ds_api/normal_chatter.rs
1//! 支持自定义历史记录管理的聊天客户端模块
2//!
3//! 提供灵活的聊天客户端实现,允许用户自定义对话历史记录的存储和管理方式。
4//!
5//! # 主要特性
6//!
7//! - **自定义历史记录**: 通过实现 [`History`] trait 来自定义历史记录存储
8//! - **聊天功能**: 支持基本的聊天交互
9//! - **JSON 响应**: 支持 JSON 格式的响应
10//! - **异步处理**: 基于 `tokio` 的异步实现
11//!
12//! # 示例
13//!
14//! ## 基本使用
15//!
16//! ```rust,no_run
17//! use ds_api::{NormalChatter, History, Message, Role};
18//!
19//! #[tokio::main]
20//! async fn main() -> ds_api::error::Result<()> {
21//! let token = "your_deepseek_api_token".to_string();
22//! let mut chatter = NormalChatter::new(token);
23//! let mut history: Vec<Message> = vec![];
24//!
25//! let response = chatter.chat("Hello, how are you?", &mut history).await?;
26//! println!("Assistant: {}", response);
27//!
28//! Ok(())
29//! }
30//! ```
31//!
32//! ## 自定义历史记录实现
33//!
34//! ```rust,no_run
35//! use ds_api::{NormalChatter, History, Message, Role};
36//!
37//! struct LimitedHistory {
38//! messages: Vec<Message>,
39//! max_messages: usize,
40//! }
41//!
42//! impl History for LimitedHistory {
43//! fn add_message(&mut self, message: Message) {
44//! self.messages.push(message);
45//! if self.messages.len() > self.max_messages {
46//! self.messages.remove(0); // 移除最旧的消息
47//! }
48//! }
49//!
50//! fn get_history(&self) -> Vec<Message> {
51//! self.messages.clone()
52//! }
53//! }
54//!
55//! #[tokio::main]
56//! async fn main() -> ds_api::error::Result<()> {
57//! let token = "your_deepseek_api_token".to_string();
58//! let mut chatter = NormalChatter::new(token);
59//! let mut history = LimitedHistory {
60//! messages: vec![],
61//! max_messages: 10,
62//! };
63//!
64//! let response = chatter.chat("What is Rust?", &mut history).await?;
65//! println!("Assistant: {}", response);
66//!
67//! Ok(())
68//! }
69//! ```
70//!
71//! ## 使用 JSON 响应
72//!
73//! ```rust,no_run
74//! use ds_api::{NormalChatter, History, Message, Role};
75//! use serde_json::Value;
76//!
77//! #[tokio::main]
78//! async fn main() -> ds_api::error::Result<()> {
79//! let token = "your_deepseek_api_token".to_string();
80//! let mut chatter = NormalChatter::new(token);
81//! let mut history: Vec<Message> = vec![
82//! Message::new(Role::System, "You are a helpful assistant that responds in JSON format.")
83//! ];
84//!
85//! let json_response = chatter.chat_json("Give me information about Paris in JSON format", &mut history).await?;
86//! println!("JSON response: {}", serde_json::to_string_pretty(&json_response)?);
87//!
88//! Ok(())
89//! }
90//! ```
91//!
92//! # 注意事项
93//!
94//! - 当前实现不支持流式响应
95//! - 需要手动管理上下文长度,避免超过模型限制
96//! - 历史记录中的第一条消息通常是系统提示词
97//!
98
99/// 历史记录管理 trait
100///
101/// 定义对话历史记录的存储和管理接口,允许用户自定义历史记录的存储方式。
102///
103/// # 实现要求
104///
105/// 实现者需要提供:
106/// - 消息添加功能
107/// - 历史记录获取功能
108///
109/// # 示例
110///
111/// 使用 `Vec<Message>` 作为历史记录存储:
112///
113/// ```rust
114/// use ds_api::{History, Message, Role};
115///
116/// let mut history: Vec<Message> = vec![];
117/// history.add_message(Message::new(Role::User, "Hello"));
118///
119/// let messages = history.get_history();
120/// assert_eq!(messages.len(), 1);
121/// ```
122pub trait History {
123 /// 添加一条消息到历史记录中
124 ///
125 /// # 参数
126 ///
127 /// * `message` - 要添加的消息
128 fn add_message(&mut self, message: Message);
129
130 /// 获取完整的历史记录
131 ///
132 /// 返回历史记录中所有消息的副本。由于需要发送给 API,
133 /// 这里直接返回 `Vec<Message>` 而不是迭代器,这样不会带来性能损失。
134 ///
135 /// # 返回
136 ///
137 /// 历史记录中所有消息的向量
138 fn get_history(&self) -> Vec<Message>;
139}
140
141impl History for Vec<Message> {
142 fn add_message(&mut self, message: Message) {
143 self.push(message);
144 }
145
146 fn get_history(&self) -> Vec<Message> {
147 self.clone()
148 }
149}
150
151use crate::error::Result;
152
153use crate::request::*;
154use crate::response::Response;
155use reqwest::Client;
156use serde_json::Value;
157
158/// 支持自定义历史记录管理的聊天客户端
159///
160/// 这个结构体提供了与 DeepSeek API 交互的基本功能,同时允许用户
161/// 通过实现 [`History`] trait 来自定义历史记录的存储和管理方式。
162///
163/// # 字段
164///
165/// - `token`: DeepSeek API 访问令牌
166/// - `client`: HTTP 客户端,用于发送请求
167///
168/// # 注意事项
169///
170/// - 历史记录中的第一条消息通常是系统提示词(System Prompt)
171/// - 后续消息是用户(User)或助手(Assistant)的对话内容
172/// - 需要手动管理上下文长度,避免超过模型限制
173pub struct NormalChatter {
174 /// DeepSeek API 访问令牌
175 pub token: String,
176 /// HTTP 客户端实例
177 pub client: Client,
178}
179
180impl NormalChatter {
181 /// 创建一个新的 `NormalChatter` 实例
182 ///
183 /// # 参数
184 ///
185 /// * `token` - DeepSeek API 访问令牌
186 ///
187 /// # 示例
188 ///
189 /// ```rust
190 /// use ds_api::NormalChatter;
191 ///
192 /// let token = "your_deepseek_api_token".to_string();
193 /// let chatter = NormalChatter::new(token);
194 /// ```
195 pub fn new(token: String) -> Self {
196 Self {
197 token,
198 client: Client::new(),
199 }
200 }
201
202 /// 发送聊天消息并获取文本响应
203 ///
204 /// 这个方法会将用户消息添加到历史记录中,发送请求到 DeepSeek API,
205 /// 然后将助手的响应也添加到历史记录中,最后返回响应文本。
206 ///
207 /// # 参数
208 ///
209 /// * `user_message` - 用户消息内容
210 /// * `history` - 实现了 [`History`] trait 的历史记录管理器
211 ///
212 /// # 返回
213 ///
214 /// 返回助手的响应文本,如果发生错误则返回错误信息。
215 ///
216 /// # 示例
217 ///
218 /// ```rust,no_run
219 /// use ds_api::{NormalChatter, History, Message, Role};
220 ///
221 /// #[tokio::main]
222 /// async fn main() -> ds_api::error::Result<()> {
223 /// let token = "your_token".to_string();
224 /// let mut chatter = NormalChatter::new(token);
225 /// let mut history: Vec<Message> = vec![];
226 ///
227 /// let response = chatter.chat("Hello, world!", &mut history).await?;
228 /// println!("Assistant: {}", response);
229 ///
230 /// Ok(())
231 /// }
232 /// ```
233 pub async fn chat<T: AsRef<str>>(
234 &mut self,
235 user_message: T,
236 history: &mut impl History,
237 ) -> Result<String> {
238 let user_message = Message::new(Role::User, user_message.as_ref());
239 history.add_message(user_message);
240
241 let response = Request::basic_query(history.get_history())
242 .execute_nostreaming(&self.token)
243 .await?;
244
245 let assistant_message = response
246 .choices
247 .get(0)
248 .map(|c| c.message.clone())
249 .ok_or_else(|| {
250 crate::error::ApiError::Other("missing choice or content in response".to_string())
251 })?;
252 history.add_message(assistant_message);
253
254 Ok(response.content()?.to_string())
255 }
256
257 /// 发送聊天消息并获取 JSON 格式的响应
258 ///
259 /// 这个方法与 [`NormalChatter::chat`] 类似,但会启用 JSON 响应模式,并返回解析后的 JSON 值。
260 ///
261 /// # 参数
262 ///
263 /// * `user_message` - 用户消息内容
264 /// * `history` - 实现了 [`History`] trait 的历史记录管理器
265 ///
266 /// # 返回
267 ///
268 /// 返回解析后的 JSON 值,如果发生错误则返回错误信息。
269 ///
270 /// # 注意事项
271 ///
272 /// 使用此方法前,确保在系统提示词中指示模型返回 JSON 格式的响应。
273 ///
274 /// # 示例
275 ///
276 /// ```rust,no_run
277 /// use ds_api::{NormalChatter, History, Message, Role};
278 /// use serde_json::Value;
279 ///
280 /// #[tokio::main]
281 /// async fn main() -> ds_api::error::Result<()> {
282 /// let token = "your_token".to_string();
283 /// let mut chatter = NormalChatter::new(token);
284 /// let mut history: Vec<Message> = vec![
285 /// Message::new(Role::System, "You are a helpful assistant that responds in JSON format.")
286 /// ];
287 ///
288 /// let json_response = chatter.chat_json("Give me information about Paris", &mut history).await?;
289 /// println!("JSON response: {}", serde_json::to_string_pretty(&json_response)?);
290 ///
291 /// Ok(())
292 /// }
293 /// ```
294 pub async fn chat_json<T: AsRef<str>>(
295 &mut self,
296 user_message: T,
297 history: &mut impl History,
298 ) -> Result<Value> {
299 let user_message = Message::new(Role::User, user_message.as_ref());
300 history.add_message(user_message);
301
302 let response = Request::basic_query(history.get_history())
303 .json()
304 .execute_nostreaming(&self.token)
305 .await?;
306
307 let assistant_message = response
308 .choices
309 .get(0)
310 .map(|c| c.message.clone())
311 .ok_or_else(|| {
312 crate::error::ApiError::Other("missing choice or content in response".to_string())
313 })?;
314 history.add_message(assistant_message);
315
316 let value = serde_json::from_str(response.content()?)?;
317
318 Ok(value)
319 }
320}