1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
10#[serde(rename_all = "lowercase")]
11pub enum Source {
12 OpenAI,
13 Anthropic,
14 Ollama,
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
19#[serde(rename_all = "lowercase")]
20pub enum Role {
21 System,
22 User,
23 Assistant,
24 Tool,
25}
26
27impl Role {
28 pub fn as_str(&self) -> &'static str {
29 match self {
30 Role::System => "system",
31 Role::User => "user",
32 Role::Assistant => "assistant",
33 Role::Tool => "tool",
34 }
35 }
36}
37
38#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
40pub struct TextContent {
41 pub text: String,
42}
43
44impl TextContent {
45 pub fn new(text: impl Into<String>) -> Self {
46 Self { text: text.into() }
47 }
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
52#[serde(rename_all = "lowercase")]
53pub enum ImageSourceType {
54 Base64,
55 Url,
56}
57
58#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
60pub struct ImageContent {
61 pub source_type: ImageSourceType,
62 pub media_type: String,
63 pub data: String,
64}
65
66#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
68pub struct ToolCallContent {
69 pub id: String,
70 pub name: String,
71 pub arguments: String,
72}
73
74#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
76pub struct ToolResultContent {
77 pub tool_call_id: String,
78 pub content: String,
79}
80
81#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
83#[serde(tag = "type", rename_all = "snake_case")]
84pub enum Content {
85 Text(TextContent),
86 Image(ImageContent),
87 ToolCall(ToolCallContent),
88 ToolResult(ToolResultContent),
89}
90
91impl Content {
92 pub fn text(text: impl Into<String>) -> Self {
93 Content::Text(TextContent::new(text))
94 }
95}
96
97#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
99pub struct Message {
100 pub role: Role,
101 pub content: Vec<Content>,
102 #[serde(skip_serializing_if = "Option::is_none")]
103 pub source: Option<Source>,
104 #[serde(skip_serializing_if = "Option::is_none")]
105 pub raw: Option<serde_json::Value>,
106}
107
108impl Message {
109 pub fn new(role: Role, content: Vec<Content>) -> Self {
110 Self {
111 role,
112 content,
113 source: None,
114 raw: None,
115 }
116 }
117
118 pub fn text(role: Role, text: impl Into<String>) -> Self {
119 Self::new(role, vec![Content::text(text)])
120 }
121
122 pub fn with_source(mut self, source: Source) -> Self {
123 self.source = Some(source);
124 self
125 }
126
127 pub fn with_raw(mut self, raw: serde_json::Value) -> Self {
128 self.raw = Some(raw);
129 self
130 }
131}
132
133#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
135pub struct ChatRequest {
136 pub model: String,
137 pub messages: Vec<Message>,
138 #[serde(skip_serializing_if = "Option::is_none")]
139 pub max_tokens: Option<u32>,
140 #[serde(skip_serializing_if = "Option::is_none")]
141 pub temperature: Option<f32>,
142 #[serde(skip_serializing_if = "Option::is_none")]
143 pub top_p: Option<f32>,
144 #[serde(default)]
145 pub stream: bool,
146}
147
148#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
150pub struct Usage {
151 pub prompt_tokens: u32,
152 pub completion_tokens: u32,
153 pub total_tokens: u32,
154}
155
156#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
158pub struct Choice {
159 pub index: u32,
160 pub message: Message,
161 #[serde(skip_serializing_if = "Option::is_none")]
162 pub finish_reason: Option<String>,
163}
164
165#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
167pub struct ChatResponse {
168 pub id: String,
169 pub model: String,
170 pub choices: Vec<Choice>,
171 #[serde(skip_serializing_if = "Option::is_none")]
172 pub usage: Option<Usage>,
173}
174
175#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
181pub struct TextDelta {
182 pub text: String,
183}
184
185#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
187pub struct ToolCallDelta {
188 pub index: u32,
189 #[serde(skip_serializing_if = "Option::is_none")]
190 pub id: Option<String>,
191 #[serde(skip_serializing_if = "Option::is_none")]
192 pub name: Option<String>,
193 #[serde(skip_serializing_if = "Option::is_none")]
194 pub arguments: Option<String>,
195}
196
197#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
199#[serde(tag = "type", rename_all = "snake_case")]
200pub enum DeltaContent {
201 TextDelta(TextDelta),
202 ToolCallDelta(ToolCallDelta),
203}
204
205#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
207pub struct ChoiceDelta {
208 pub index: u32,
209 pub content: Vec<DeltaContent>,
210 #[serde(skip_serializing_if = "Option::is_none")]
211 pub finish_reason: Option<String>,
212}
213
214#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
216pub struct StreamChunk {
217 pub id: String,
218 pub model: String,
219 pub choices: Vec<ChoiceDelta>,
220 #[serde(skip_serializing_if = "Option::is_none")]
221 pub usage: Option<Usage>,
222 #[serde(skip_serializing_if = "Option::is_none")]
223 pub source: Option<Source>,
224 #[serde(skip_serializing_if = "Option::is_none")]
225 pub raw: Option<serde_json::Value>,
226}