1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
use fmt::Display;
use std::fmt;
use serde::{Deserialize, Serialize};
use crate::client::ChatSession;
use crate::error::ApiError;
/// Represents a message in the conversation.
///
/// A `Message` struct contains the role of the sender (either "user" or "assistant")
/// and the content of the message.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Message {
/// The role of the sender, either "user" or "assistant".
pub role: String,
/// The content of the message.
pub content: String,
}
/// Represents the request body sent to the Anthropic API.
///
/// The `RequestBody` struct contains the model name, the list of messages,
/// the maximum number of tokens to generate, and the temperature value.
#[derive(Serialize, Deserialize, Debug)]
pub struct RequestBody {
/// The name of the model to use for generating the response.
pub model: String,
/// The list of messages in the conversation.
pub messages: Vec<Message>,
/// The maximum number of tokens to generate in the response.
pub max_tokens: u32,
/// The temperature value to control the randomness of the generated response.
pub temperature: f32,
/// A system prompt is a way of providing context and instructions to Claude, such as
/// specifying a particular goal or role.
/// https://docs.anthropic.com/claude/docs/system-prompts
pub system: String,
}
/// Represents a block of content in the API response.
///
/// A `ContentBlock` struct contains the text content and the type of the block.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ContentBlock {
/// The text content of the block.
pub text: String,
/// The type of the content block.
///
/// The `#[serde(rename = "type")]` attribute is used to map the `type` field
/// in the JSON response to the `block_type` field in the struct.
#[serde(rename = "type")]
pub block_type: String,
}
/// Represents the response message received from the Anthropic API.
///
/// The `ResponseMessage` struct contains the ID of the response, the role of the sender,
/// and the list of content blocks in the response.
#[derive(Serialize, Deserialize, Debug)]
pub struct ResponseMessage {
/// The ID of the response message.
pub id: String,
/// The role of the sender, either "user" or "assistant".
pub role: String,
/// The list of content blocks in the response.
pub content: Vec<ContentBlock>,
}
impl ResponseMessage {
/// Returns the text content of the first content block in the response message.
///
/// This method retrieves the first content block from the `content` vector of the `ResponseMessage`
/// and returns its text content as a `String`. If the `content` vector is empty, an empty string
/// is returned.
///
/// # Examples
///
/// ```
/// use llm_api_adapter::models::ResponseMessage;
///
/// let response_message = ResponseMessage {
/// id: "123".to_string(),
/// role: "assistant".to_string(),
/// content: vec![
/// ContentBlock {
/// text: "Hello, how can I assist you today?".to_string(),
/// block_type: "text".to_string(),
/// },
/// ContentBlock {
/// text: "Let me know if you have any questions!".to_string(),
/// block_type: "text".to_string(),
/// },
/// ],
/// };
///
/// let first_message = response_message.first_message();
/// assert_eq!(first_message, "Hello, how can I assist you today?");
/// ```
///
/// # Returns
///
/// A `String` containing the text content of the first content block in the response message.
/// If the `content` vector is empty, an empty string is returned.
pub fn first_message(&self) -> String {
let content = self.content.first();
match content {
None => {
"".to_string()
}
Some(content) => {
content.text.to_string()
}
}
}
}
/// Implement Display trait for ResponseMessage
impl Display for ResponseMessage {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ResponseMessage {{ id: {}, role: {}, content: {:?} }}", self.id, self.role, self.content)
}
}
/// Represents the response from a chat session.
///
/// The lifetime parameter `'a` indicates that the `ChatResponse` borrows data from a `ChatSession`
/// instance and can only live as long as the `ChatSession` instance.
pub struct ChatResponse<'a> {
pub(crate) session: ChatSession<'a>,
pub(crate) last_response: String,
}
impl<'a> ChatResponse<'a> {
/// Returns the last response from the chat session.
pub fn last_response(&self) -> &str {
&self.last_response
}
/// Returns the entire conversation history of the chat session.
pub fn dialog(&self) -> &[Message] {
&self.session.messages
}
/// Sends a new user message to continue the conversation and returns the updated `ChatResponse`.
///
/// # Arguments
///
/// * `message` - The user message to send.
///
/// # Returns
///
/// An updated `ChatResponse` instance containing the last response and the updated chat session.
pub async fn add(self, message: &str) -> Result<ChatResponse<'a>, ApiError> {
self.session.send(message).await
}
}