Skip to main content

linger_openai_sdk/
chat.rs

1use crate::error::LingerError;
2use crate::RequestId;
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5use std::collections::BTreeMap;
6
7/// EN: Request body for `POST /v1/chat/completions`.
8/// 中文:`POST /v1/chat/completions` 的请求体。
9#[derive(Clone, Debug, Serialize, PartialEq)]
10#[non_exhaustive]
11pub struct CreateChatCompletionRequest {
12    /// EN: Model id used to create the chat completion.
13    /// 中文:用于创建 chat completion 的模型 ID。
14    pub model: String,
15    /// EN: Chat messages for the completion.
16    /// 中文:用于 completion 的聊天消息。
17    pub messages: Vec<ChatMessage>,
18    /// EN: Optional upper bound for generated completion tokens.
19    /// 中文:可选的生成 completion token 上限。
20    #[serde(skip_serializing_if = "Option::is_none")]
21    pub max_completion_tokens: Option<u32>,
22    /// EN: Optional sampling temperature.
23    /// 中文:可选的采样温度。
24    #[serde(skip_serializing_if = "Option::is_none")]
25    pub temperature: Option<f32>,
26    /// EN: Forward-compatible optional fields not yet covered by handwritten types.
27    /// 中文:手写类型尚未覆盖的前向兼容可选字段。
28    #[serde(flatten)]
29    pub extra: BTreeMap<String, Value>,
30}
31
32impl CreateChatCompletionRequest {
33    /// EN: Starts building a chat-completion request.
34    /// 中文:开始构建 chat completion 请求。
35    pub fn builder() -> CreateChatCompletionRequestBuilder {
36        CreateChatCompletionRequestBuilder::default()
37    }
38}
39
40/// EN: Builder for chat-completion requests.
41/// 中文:Chat completion 请求构建器。
42#[derive(Clone, Debug, Default)]
43#[non_exhaustive]
44pub struct CreateChatCompletionRequestBuilder {
45    model: Option<String>,
46    messages: Vec<ChatMessage>,
47    max_completion_tokens: Option<u32>,
48    temperature: Option<f32>,
49    extra: BTreeMap<String, Value>,
50}
51
52impl CreateChatCompletionRequestBuilder {
53    /// EN: Sets the model id.
54    /// 中文:设置模型 ID。
55    pub fn model(mut self, model: impl Into<String>) -> Self {
56        self.model = Some(model.into());
57        self
58    }
59
60    /// EN: Appends a chat message.
61    /// 中文:追加一条聊天消息。
62    pub fn message(mut self, message: ChatMessage) -> Self {
63        self.messages.push(message);
64        self
65    }
66
67    /// EN: Sets the generated completion token limit.
68    /// 中文:设置生成 completion token 上限。
69    pub fn max_completion_tokens(mut self, max_completion_tokens: u32) -> Self {
70        self.max_completion_tokens = Some(max_completion_tokens);
71        self
72    }
73
74    /// EN: Sets the sampling temperature.
75    /// 中文:设置采样温度。
76    pub fn temperature(mut self, temperature: f32) -> Self {
77        self.temperature = Some(temperature);
78        self
79    }
80
81    /// EN: Adds a forward-compatible JSON field.
82    /// 中文:添加前向兼容的 JSON 字段。
83    pub fn extra(mut self, name: impl Into<String>, value: Value) -> Self {
84        self.extra.insert(name.into(), value);
85        self
86    }
87
88    /// EN: Builds and validates the request.
89    /// 中文:构建并校验请求。
90    pub fn build(self) -> Result<CreateChatCompletionRequest, LingerError> {
91        let model = self
92            .model
93            .filter(|value| !value.trim().is_empty())
94            .ok_or_else(|| LingerError::invalid_config("model is required"))?;
95        if self.messages.is_empty() {
96            return Err(LingerError::invalid_config("messages is required"));
97        }
98        if self
99            .messages
100            .iter()
101            .any(|message| message.role.trim().is_empty() || message.content.is_empty())
102        {
103            return Err(LingerError::invalid_config(
104                "message role and content must not be empty",
105            ));
106        }
107        Ok(CreateChatCompletionRequest {
108            model,
109            messages: self.messages,
110            max_completion_tokens: self.max_completion_tokens,
111            temperature: self.temperature,
112            extra: self.extra,
113        })
114    }
115}
116
117/// EN: Request body for modifying a stored chat completion.
118/// 中文:修改已存储 chat completion 的请求体。
119#[derive(Clone, Debug, Default, Serialize, PartialEq)]
120#[non_exhaustive]
121pub struct ModifyChatCompletionRequest {
122    /// EN: Metadata to attach to the stored chat completion.
123    /// 中文:要附加到已存储 chat completion 的元数据。
124    pub metadata: BTreeMap<String, String>,
125}
126
127impl ModifyChatCompletionRequest {
128    /// EN: Starts building a stored chat-completion modification request.
129    /// 中文:开始构建已存储 chat completion 修改请求。
130    pub fn builder() -> ModifyChatCompletionRequestBuilder {
131        ModifyChatCompletionRequestBuilder::default()
132    }
133}
134
135/// EN: Builder for stored chat-completion modification requests.
136/// 中文:已存储 chat completion 修改请求的构建器。
137#[derive(Clone, Debug, Default)]
138#[non_exhaustive]
139pub struct ModifyChatCompletionRequestBuilder {
140    metadata: BTreeMap<String, String>,
141}
142
143impl ModifyChatCompletionRequestBuilder {
144    /// EN: Adds a metadata key/value pair.
145    /// 中文:添加一个元数据键值对。
146    pub fn metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
147        self.metadata.insert(key.into(), value.into());
148        self
149    }
150
151    /// EN: Builds and validates the request.
152    /// 中文:构建并校验请求。
153    pub fn build(self) -> Result<ModifyChatCompletionRequest, LingerError> {
154        validate_metadata(&self.metadata)?;
155        Ok(ModifyChatCompletionRequest {
156            metadata: self.metadata,
157        })
158    }
159}
160
161/// EN: Chat message request item.
162/// 中文:聊天消息请求项。
163#[derive(Clone, Debug, Serialize, PartialEq, Eq)]
164#[non_exhaustive]
165pub struct ChatMessage {
166    /// EN: Message role such as `developer`, `system`, `user`, or `assistant`.
167    /// 中文:消息角色,例如 `developer`、`system`、`user` 或 `assistant`。
168    pub role: String,
169    /// EN: Text content for this message.
170    /// 中文:该消息的文本内容。
171    pub content: String,
172}
173
174impl ChatMessage {
175    /// EN: Creates a developer message.
176    /// 中文:创建 developer 消息。
177    pub fn developer(content: impl Into<String>) -> Self {
178        Self::new("developer", content)
179    }
180
181    /// EN: Creates a system message.
182    /// 中文:创建 system 消息。
183    pub fn system(content: impl Into<String>) -> Self {
184        Self::new("system", content)
185    }
186
187    /// EN: Creates a user message.
188    /// 中文:创建 user 消息。
189    pub fn user(content: impl Into<String>) -> Self {
190        Self::new("user", content)
191    }
192
193    /// EN: Creates an assistant message.
194    /// 中文:创建 assistant 消息。
195    pub fn assistant(content: impl Into<String>) -> Self {
196        Self::new("assistant", content)
197    }
198
199    /// EN: Creates a message with a custom role.
200    /// 中文:创建自定义角色消息。
201    pub fn new(role: impl Into<String>, content: impl Into<String>) -> Self {
202        Self {
203            role: role.into(),
204            content: content.into(),
205        }
206    }
207}
208
209/// EN: Chat completion response object.
210/// 中文:Chat completion 响应对象。
211#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
212#[non_exhaustive]
213pub struct ChatCompletion {
214    /// EN: Chat completion id.
215    /// 中文:Chat completion ID。
216    pub id: String,
217    /// EN: API object type.
218    /// 中文:API 对象类型。
219    pub object: String,
220    /// EN: Unix timestamp for creation.
221    /// 中文:创建时间的 Unix 时间戳。
222    pub created: u64,
223    /// EN: Model that produced the completion.
224    /// 中文:生成 completion 的模型。
225    pub model: String,
226    /// EN: Completion choices.
227    /// 中文:Completion 候选项。
228    #[serde(default)]
229    pub choices: Vec<ChatCompletionChoice>,
230    /// EN: Token usage, when returned.
231    /// 中文:Token 用量,如响应中存在。
232    #[serde(default)]
233    pub usage: Option<ChatCompletionUsage>,
234    /// EN: Additional fields preserved for forward compatibility.
235    /// 中文:为前向兼容保留的额外字段。
236    #[serde(flatten)]
237    pub extra: BTreeMap<String, Value>,
238    /// EN: OpenAI request id from response headers.
239    /// 中文:响应头中的 OpenAI 请求 ID。
240    #[serde(skip)]
241    request_id: Option<RequestId>,
242}
243
244impl ChatCompletion {
245    pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
246        self.request_id = request_id;
247        self
248    }
249
250    /// EN: Returns the OpenAI request id, when present.
251    /// 中文:返回 OpenAI 请求 ID,如存在。
252    pub fn request_id(&self) -> Option<&RequestId> {
253        self.request_id.as_ref()
254    }
255}
256
257/// EN: Paginated stored chat completion list.
258/// 中文:已存储 chat completion 的分页列表。
259#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
260#[non_exhaustive]
261pub struct ChatCompletionPage {
262    /// EN: API list object type.
263    /// 中文:API 列表对象类型。
264    pub object: String,
265    /// EN: Chat completions on this page.
266    /// 中文:本页中的 chat completion。
267    #[serde(default)]
268    pub data: Vec<ChatCompletion>,
269    /// EN: First item id on this page.
270    /// 中文:本页第一个项目 ID。
271    #[serde(default)]
272    pub first_id: Option<String>,
273    /// EN: Last item id on this page.
274    /// 中文:本页最后一个项目 ID。
275    #[serde(default)]
276    pub last_id: Option<String>,
277    /// EN: Whether more items are available.
278    /// 中文:是否还有更多项目。
279    pub has_more: bool,
280    /// EN: OpenAI request id from response headers.
281    /// 中文:响应头中的 OpenAI 请求 ID。
282    #[serde(skip)]
283    request_id: Option<RequestId>,
284}
285
286impl ChatCompletionPage {
287    pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
288        self.request_id = request_id;
289        self
290    }
291
292    /// EN: Returns the OpenAI request id, when present.
293    /// 中文:返回 OpenAI 请求 ID,如存在。
294    pub fn request_id(&self) -> Option<&RequestId> {
295        self.request_id.as_ref()
296    }
297}
298
299/// EN: Deletion result returned for stored chat completions.
300/// 中文:已存储 chat completion 的删除结果。
301#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
302#[non_exhaustive]
303pub struct ChatCompletionDeletion {
304    /// EN: Deleted chat completion id.
305    /// 中文:已删除的 chat completion ID。
306    pub id: String,
307    /// EN: API object type.
308    /// 中文:API 对象类型。
309    pub object: String,
310    /// EN: Whether the chat completion was deleted.
311    /// 中文:chat completion 是否已删除。
312    pub deleted: bool,
313    /// EN: OpenAI request id from response headers.
314    /// 中文:响应头中的 OpenAI 请求 ID。
315    #[serde(skip)]
316    request_id: Option<RequestId>,
317}
318
319impl ChatCompletionDeletion {
320    pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
321        self.request_id = request_id;
322        self
323    }
324
325    /// EN: Returns the OpenAI request id, when present.
326    /// 中文:返回 OpenAI 请求 ID,如存在。
327    pub fn request_id(&self) -> Option<&RequestId> {
328        self.request_id.as_ref()
329    }
330}
331
332/// EN: Single chat completion choice.
333/// 中文:单个 chat completion 候选项。
334#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
335#[non_exhaustive]
336pub struct ChatCompletionChoice {
337    /// EN: Choice index.
338    /// 中文:候选项索引。
339    pub index: u32,
340    /// EN: Assistant message for this choice.
341    /// 中文:该候选项的助手消息。
342    pub message: ChatCompletionMessage,
343    /// EN: Finish reason, when returned.
344    /// 中文:结束原因,如响应中存在。
345    #[serde(default)]
346    pub finish_reason: Option<String>,
347    /// EN: Additional fields preserved for forward compatibility.
348    /// 中文:为前向兼容保留的额外字段。
349    #[serde(flatten)]
350    pub extra: BTreeMap<String, Value>,
351}
352
353/// EN: Chat completion message returned by the API.
354/// 中文:API 返回的 chat completion 消息。
355#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
356#[non_exhaustive]
357pub struct ChatCompletionMessage {
358    /// EN: Message role.
359    /// 中文:消息角色。
360    pub role: String,
361    /// EN: Text content, when returned.
362    /// 中文:文本内容,如响应中存在。
363    #[serde(default)]
364    pub content: Option<String>,
365    /// EN: Additional fields preserved for forward compatibility.
366    /// 中文:为前向兼容保留的额外字段。
367    #[serde(flatten)]
368    pub extra: BTreeMap<String, Value>,
369}
370
371/// EN: Stored chat completion message returned by the API.
372/// 中文:API 返回的已存储 chat completion 消息。
373#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
374#[non_exhaustive]
375pub struct ChatCompletionStoredMessage {
376    /// EN: Stored message id.
377    /// 中文:已存储消息 ID。
378    pub id: String,
379    /// EN: API object type.
380    /// 中文:API 对象类型。
381    pub object: String,
382    /// EN: Message role.
383    /// 中文:消息角色。
384    pub role: String,
385    /// EN: Text content, when returned.
386    /// 中文:文本内容,如响应中存在。
387    #[serde(default)]
388    pub content: Option<String>,
389    /// EN: Additional fields preserved for forward compatibility.
390    /// 中文:为前向兼容保留的额外字段。
391    #[serde(flatten)]
392    pub extra: BTreeMap<String, Value>,
393}
394
395/// EN: Paginated stored chat completion messages.
396/// 中文:已存储 chat completion 消息的分页列表。
397#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
398#[non_exhaustive]
399pub struct ChatCompletionMessagePage {
400    /// EN: API list object type.
401    /// 中文:API 列表对象类型。
402    pub object: String,
403    /// EN: Stored messages on this page.
404    /// 中文:本页中的已存储消息。
405    #[serde(default)]
406    pub data: Vec<ChatCompletionStoredMessage>,
407    /// EN: First item id on this page.
408    /// 中文:本页第一个项目 ID。
409    #[serde(default)]
410    pub first_id: Option<String>,
411    /// EN: Last item id on this page.
412    /// 中文:本页最后一个项目 ID。
413    #[serde(default)]
414    pub last_id: Option<String>,
415    /// EN: Whether more items are available.
416    /// 中文:是否还有更多项目。
417    pub has_more: bool,
418    /// EN: OpenAI request id from response headers.
419    /// 中文:响应头中的 OpenAI 请求 ID。
420    #[serde(skip)]
421    request_id: Option<RequestId>,
422}
423
424impl ChatCompletionMessagePage {
425    pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
426        self.request_id = request_id;
427        self
428    }
429
430    /// EN: Returns the OpenAI request id, when present.
431    /// 中文:返回 OpenAI 请求 ID,如存在。
432    pub fn request_id(&self) -> Option<&RequestId> {
433        self.request_id.as_ref()
434    }
435}
436
437/// EN: Token usage for a chat completion.
438/// 中文:Chat completion 的 token 用量。
439#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
440#[non_exhaustive]
441pub struct ChatCompletionUsage {
442    /// EN: Prompt token count.
443    /// 中文:Prompt token 数量。
444    pub prompt_tokens: u64,
445    /// EN: Completion token count.
446    /// 中文:Completion token 数量。
447    pub completion_tokens: u64,
448    /// EN: Total token count.
449    /// 中文:总 token 数量。
450    pub total_tokens: u64,
451}
452
453fn validate_metadata(metadata: &BTreeMap<String, String>) -> Result<(), LingerError> {
454    for key in metadata.keys() {
455        if key.trim().is_empty() {
456            return Err(LingerError::invalid_config(
457                "metadata keys must not be empty",
458            ));
459        }
460    }
461    Ok(())
462}