feat: 模块统一 ias- 前缀、独立版本与内网地址支持 (0.1.7)
- 所有 Rust crate 统一加 ias- 前缀:ai → ias-ai、common → ias-common、context → ias-context、mail → ias-mail、service → ias-service、wechat → ias-wechat - 新增 ias-main 模块承载 CLI 入口和二进制打包 - 各模块开始独立维护版本号,ias-main 0.1.7 代表整体版本 - 新增 IA_WEB_INTERNAL_URL 环境变量,版本通知同时发送公网和内网链接 - 将已有升级日志翻译为中文 - ias_upgrade_logs 新增 modules JSONB 字段 - 新增 VERSION 文件和 CHANGELOG.md - 新增 AGENTS.md 项目规则文件
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "ias-common"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
# ── 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"
|
||||
# ── 错误处理 ──
|
||||
anyhow = "1"
|
||||
thiserror = "2"
|
||||
@@ -0,0 +1 @@
|
||||
pub mod queue;
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
pub mod error;
|
||||
pub mod model;
|
||||
pub mod queue;
|
||||
@@ -0,0 +1,167 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct ChatCompletionRequestBody {
|
||||
pub model: String,
|
||||
pub messages: Vec<ChatCompletionRequestMessage>,
|
||||
pub stream: bool,
|
||||
pub tools: Vec<serde_json::Value>,
|
||||
pub extra_body: Option<ChatCompletionRequestExtra>,
|
||||
}
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct ChatCompletionRequestExtra {
|
||||
pub thinking: ChatCompletionRequestThinking,
|
||||
}
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct ChatCompletionRequestThinking {
|
||||
#[serde(rename = "type")]
|
||||
pub thinking_type: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct ChatCompletionRequestMessage {
|
||||
pub role: String,
|
||||
pub content: String,
|
||||
pub tool_call_id: Option<String>,
|
||||
pub tool_calls: Option<Vec<ChatCompletionToolCall>>,
|
||||
}
|
||||
impl ChatCompletionRequestMessage {
|
||||
pub fn new(role: String, content: String) -> Self {
|
||||
Self {
|
||||
role,
|
||||
content,
|
||||
tool_call_id: None,
|
||||
tool_calls: None,
|
||||
}
|
||||
}
|
||||
pub fn assistant(
|
||||
role: String,
|
||||
content: String,
|
||||
tool_calls: Option<Vec<ChatCompletionToolCall>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
role,
|
||||
content,
|
||||
tool_call_id: None,
|
||||
tool_calls,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tool(role: String, content: String, tool_call_id: String) -> Self {
|
||||
Self {
|
||||
role,
|
||||
content,
|
||||
tool_call_id: Some(tool_call_id),
|
||||
tool_calls: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// {"choices":[{"finish_reason":"stop","index":0,"logprobs":null,"message":{"content":"你好!😊 有什么我可以帮你的吗?","role":"assistant"}}],"created":1782208455,"id":"02178220845277286f296e4c58ddf650991f54d763d292af8529b","model":"deepseek-v4-flash-260425","service_tier":"default","object":"chat.completion","usage":{"prompt_tokens":2005,"completion_tokens":125,"total_tokens":2130,"prompt_tokens_details":{"cached_tokens":0},"completion_tokens_details":{"reasoning_tokens":114}}}
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ChatCompletionResponseBody {
|
||||
id: Option<String>,
|
||||
object: Option<String>,
|
||||
created: Option<i64>,
|
||||
model: Option<String>,
|
||||
service_tier: Option<String>,
|
||||
system_fingerprint: Option<String>,
|
||||
pub choices: Vec<ChatCompletionResponseChoice>,
|
||||
pub usage: Option<ChatCompletionUsage>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ChatCompletionResponseChoice {
|
||||
index: u32,
|
||||
pub message: ChatCompletionResponseMessage,
|
||||
logprobs: Option<serde_json::Value>,
|
||||
finish_reason: String,
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ChatCompletionResponseMessage {
|
||||
pub role: String,
|
||||
pub content: String,
|
||||
pub reasoning_content: Option<String>,
|
||||
pub tool_calls: Option<Vec<ChatCompletionToolCall>>,
|
||||
}
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct ChatCompletionToolCall {
|
||||
pub function: Option<ChatCompletionFunction>,
|
||||
pub id: String,
|
||||
#[serde(rename = "type")]
|
||||
pub call_type: String,
|
||||
}
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct ChatCompletionFunction {
|
||||
pub arguments: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ChatCompletionUsage {
|
||||
pub prompt_tokens: u32,
|
||||
pub completion_tokens: u32,
|
||||
pub total_tokens: u32,
|
||||
pub prompt_tokens_details: Option<ChatCompletionUsagePrompt>,
|
||||
pub completion_tokens_details: Option<ChatCompletionUsageCompletion>,
|
||||
pub prompt_cache_hit_tokens: Option<u32>,
|
||||
pub prompt_cache_miss_tokens: Option<u32>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ChatCompletionUsagePrompt {
|
||||
pub cached_tokens: Option<u32>,
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ChatCompletionUsageCompletion {
|
||||
pub reasoning_tokens: Option<u32>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::ChatCompletionResponseBody;
|
||||
|
||||
#[test]
|
||||
fn parses_router_response_without_service_tier() {
|
||||
let body = r#"{
|
||||
"id":"39f8dc37-a436-4781-a456-5adabc197858",
|
||||
"object":"chat.completion",
|
||||
"created":1783321827,
|
||||
"model":"deepseek-v4-flash",
|
||||
"choices":[{
|
||||
"index":0,
|
||||
"message":{
|
||||
"role":"assistant",
|
||||
"content":"我是你的日常助手,你可以叫我**知微**!",
|
||||
"reasoning_content":"长期记忆中显示助手名称是知微。"
|
||||
},
|
||||
"logprobs":null,
|
||||
"finish_reason":"stop"
|
||||
}],
|
||||
"usage":{
|
||||
"prompt_tokens":1518,
|
||||
"completion_tokens":50,
|
||||
"total_tokens":1568,
|
||||
"prompt_tokens_details":{"cached_tokens":0},
|
||||
"completion_tokens_details":{"reasoning_tokens":26},
|
||||
"prompt_cache_hit_tokens":0,
|
||||
"prompt_cache_miss_tokens":1518
|
||||
},
|
||||
"system_fingerprint":"fp_8b330d02d0_prod0820_fp8_kvcache_20260402"
|
||||
}"#;
|
||||
|
||||
let response: ChatCompletionResponseBody = serde_json::from_str(body).unwrap();
|
||||
|
||||
assert_eq!(response.service_tier, None);
|
||||
assert_eq!(
|
||||
response.choices[0].message.content,
|
||||
"我是你的日常助手,你可以叫我**知微**!"
|
||||
);
|
||||
assert_eq!(response.usage.unwrap().prompt_cache_miss_tokens, Some(1518));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod ai;
|
||||
@@ -0,0 +1,34 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::model::ai::ChatCompletionToolCall;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum QueueMessage {
|
||||
Channel(ChannelMessage),
|
||||
Notice(ChannelMessage, String),
|
||||
Aissitant(ChannelMessage, AssistantMessage),
|
||||
Tool(ChannelMessage, String, String, String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ChannelMessage {
|
||||
pub channel: String,
|
||||
pub account_id: String,
|
||||
pub from_user_id: String,
|
||||
pub content: String,
|
||||
pub context: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct AssistantMessage {
|
||||
pub reasoning: Option<String>,
|
||||
pub content: String,
|
||||
pub tool_calls: Option<Vec<ChatCompletionToolCall>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ToolMessage {
|
||||
pub tool_call_id: String,
|
||||
pub name: String,
|
||||
pub result: String,
|
||||
}
|
||||
Reference in New Issue
Block a user