重构并拆分项目
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "ai"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
common = {path = "../common"}
|
||||
# ── 异步运行时 ──
|
||||
tokio = { version = "1.0", features = ["rt-multi-thread", "macros", "sync", "time", "process", "signal", "io-util"] } # 异步运行时核心
|
||||
# ── HTTP 客户端 ──
|
||||
reqwest = { version = "0.12", default-features = false, features = ["json", "stream", "rustls-tls"] } # HTTP 请求(微信 API + DeepSeek API + 工具调用)
|
||||
# ── 序列化 ──
|
||||
serde = { version = "1.0", features = ["derive"] } # 序列化/反序列化
|
||||
serde_json = "1.0" # JSON 处理
|
||||
serde_yaml = "0.9" # YAML 解析(工具规范文件)
|
||||
# ── 时间 ──
|
||||
chrono = "0.4"
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
use crate::toolkit::{call_tools, get_tool};
|
||||
use common::ai::{
|
||||
ChatCompletionRequestBody, ChatCompletionRequestExtra, ChatCompletionRequestMessage,
|
||||
ChatCompletionRequestThinking, ChatCompletionResponseBody,
|
||||
};
|
||||
use common::queue::QueueMessage;
|
||||
|
||||
|
||||
|
||||
pub async fn send_message(
|
||||
sender: tokio::sync::mpsc::Sender<QueueMessage>,
|
||||
messages: Vec<ChatCompletionRequestMessage>,
|
||||
) -> Result<(), reqwest::Error> {
|
||||
let result = request_llm(messages).await;
|
||||
match result {
|
||||
Ok(result) => {
|
||||
// println!("result:");
|
||||
for choice in result.unwrap().choices {
|
||||
let messsage_content = choice.message.content;
|
||||
let messsage_reasoning = choice.message.reasoning_content.unwrap_or_default();
|
||||
if !messsage_content.trim().is_empty() || !messsage_content.trim().is_empty() {
|
||||
sender
|
||||
.send(QueueMessage::Aissitant(
|
||||
messsage_reasoning,
|
||||
messsage_content,
|
||||
))
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
match choice.message.tool_calls {
|
||||
Some(tool_calls) => {
|
||||
// eprintln!("调用了{}个工具", tool_calls.len());
|
||||
let queue_message = call_tools(tool_calls).await.unwrap();
|
||||
if let Some(queue_message) = queue_message {
|
||||
sender.send(queue_message).await.unwrap();
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// eprintln!("没有调用工具");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("发送错误:{}", err);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn request_llm(
|
||||
messages: Vec<ChatCompletionRequestMessage>,
|
||||
) -> Result<Option<ChatCompletionResponseBody>, reqwest::Error> {
|
||||
let client = reqwest::Client::new();
|
||||
let body = ChatCompletionRequestBody {
|
||||
model: "deepseek-v4-flash".to_string(),
|
||||
messages: messages,
|
||||
stream: false,
|
||||
tools: get_tool(),
|
||||
extra_body: Some(ChatCompletionRequestExtra {
|
||||
thinking: ChatCompletionRequestThinking {
|
||||
thinking_type: "enabled".to_string(),
|
||||
},
|
||||
}),
|
||||
};
|
||||
let resp = client
|
||||
.post("http://100.64.52.162:9807/v1/chat/completions")
|
||||
.bearer_auth(std::env::var("ROUTER_API_KEY").unwrap())
|
||||
.json(&body)
|
||||
.send()
|
||||
.await;
|
||||
|
||||
match resp {
|
||||
Ok(resp) => {
|
||||
let status = resp.status();
|
||||
let text = resp.text().await.unwrap_or_default();
|
||||
// println!("response:\n{}", text);
|
||||
if status.is_success() {
|
||||
let result = serde_json::from_str::<ChatCompletionResponseBody>(&text).unwrap();
|
||||
return Ok(Some(result));
|
||||
} else {
|
||||
eprintln!("HTTP 请求失败");
|
||||
eprintln!("status: {}", status);
|
||||
eprintln!("body: {}", text);
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("请求发送失败: {}", err);
|
||||
|
||||
if err.is_timeout() {
|
||||
eprintln!("原因: 请求超时");
|
||||
}
|
||||
|
||||
if err.is_connect() {
|
||||
eprintln!("原因: 连接失败");
|
||||
}
|
||||
|
||||
if let Some(url) = err.url() {
|
||||
eprintln!("url: {}", url);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
pub mod core;
|
||||
pub mod toolkit;
|
||||
@@ -0,0 +1,62 @@
|
||||
use chrono::Local;
|
||||
use serde_json::error;
|
||||
|
||||
use common::{ai::ChatCompletionResponseToolCall, queue::QueueMessage};
|
||||
|
||||
pub async fn call_tools(
|
||||
tools: Vec<ChatCompletionResponseToolCall>,
|
||||
) -> Result<Option<QueueMessage>, error::Error> {
|
||||
if let Some(tool) = tools.first() {
|
||||
if let Some(funcation) = tool.function.as_ref() {
|
||||
if funcation.name == "query_date_time" {
|
||||
let date_time = Local::now();
|
||||
let formatted = date_time.format("%Y-%m-%d %H:%M:%S").to_string();
|
||||
return Ok(Some(QueueMessage::Tool(
|
||||
tool.id.clone(),
|
||||
funcation.name.clone(),
|
||||
format!("现在时间:{}", formatted),
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn get_tool() -> Vec<serde_json::Value> {
|
||||
return vec![
|
||||
serde_json::json!({
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "query_date_time",
|
||||
"description": "查看当前时间",
|
||||
"parameters": {"type": "object", "properties": {}, "required": []}
|
||||
}
|
||||
}),
|
||||
// serde_json::json!({
|
||||
// "type": "function",
|
||||
// "function": {
|
||||
// "name": "query_capabilities",
|
||||
// "description": "查询所有可用工具的列表、参数格式和用法说明",
|
||||
// "parameters": {"type": "object", "properties": {}, "required": []}
|
||||
// }
|
||||
// }),
|
||||
// serde_json::json!({
|
||||
// "type": "function",
|
||||
// "function": {
|
||||
// "name": "call_capability",
|
||||
// "description": "调用指定的工具。先通过 query_capabilities 获取工具名和参数格式",
|
||||
// "parameters": {
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "name": {"type": "string", "description": "工具名称"},
|
||||
// "prompt": {
|
||||
// "type": "object",
|
||||
// "description": "工具参数对象,如 {\"location\":\"北京\"}"
|
||||
// }
|
||||
// },
|
||||
// "required": ["name", "prompt"]
|
||||
// }
|
||||
// }
|
||||
// }),
|
||||
];
|
||||
}
|
||||
Reference in New Issue
Block a user