Skip to main content

j_cli/command/chat/
model.rs

1use crate::config::YamlConfig;
2use crate::error;
3use serde::{Deserialize, Serialize};
4use std::fs;
5use std::path::PathBuf;
6
7// ========== 数据结构 ==========
8
9/// 单个模型提供方配置
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct ModelProvider {
12    /// 显示名称(如 "GPT-4o", "DeepSeek-V3")
13    pub name: String,
14    /// API Base URL(如 "https://api.openai.com/v1")
15    pub api_base: String,
16    /// API Key
17    pub api_key: String,
18    /// 模型名称(如 "gpt-4o", "deepseek-chat")
19    pub model: String,
20}
21
22/// Agent 配置
23#[derive(Debug, Clone, Serialize, Deserialize, Default)]
24pub struct AgentConfig {
25    /// 模型提供方列表
26    #[serde(default)]
27    pub providers: Vec<ModelProvider>,
28    /// 当前选中的 provider 索引
29    #[serde(default)]
30    pub active_index: usize,
31    /// 系统提示词(可选)
32    #[serde(default)]
33    pub system_prompt: Option<String>,
34    /// 是否使用流式输出(默认 true,设为 false 则等回复完整后再显示)
35    #[serde(default = "default_stream_mode")]
36    pub stream_mode: bool,
37    /// 发送给 API 的历史消息数量限制(默认 20 条,避免 token 消耗过大)
38    #[serde(default = "default_max_history_messages")]
39    pub max_history_messages: usize,
40}
41
42fn default_max_history_messages() -> usize {
43    20
44}
45
46/// 默认流式输出
47fn default_stream_mode() -> bool {
48    true
49}
50
51/// 对话消息
52#[derive(Debug, Clone, Serialize, Deserialize)]
53pub struct ChatMessage {
54    pub role: String, // "user" | "assistant" | "system"
55    pub content: String,
56}
57
58/// 对话会话
59#[derive(Debug, Clone, Serialize, Deserialize, Default)]
60pub struct ChatSession {
61    pub messages: Vec<ChatMessage>,
62}
63
64// ========== 文件路径 ==========
65
66/// 获取 agent 数据目录: ~/.jdata/agent/data/
67pub fn agent_data_dir() -> PathBuf {
68    let dir = YamlConfig::data_dir().join("agent").join("data");
69    let _ = fs::create_dir_all(&dir);
70    dir
71}
72
73/// 获取 agent 配置文件路径
74pub fn agent_config_path() -> PathBuf {
75    agent_data_dir().join("agent_config.json")
76}
77
78/// 获取对话历史文件路径
79pub fn chat_history_path() -> PathBuf {
80    agent_data_dir().join("chat_history.json")
81}
82
83// ========== 配置读写 ==========
84
85/// 加载 Agent 配置
86pub fn load_agent_config() -> AgentConfig {
87    let path = agent_config_path();
88    if !path.exists() {
89        return AgentConfig::default();
90    }
91    match fs::read_to_string(&path) {
92        Ok(content) => serde_json::from_str(&content).unwrap_or_else(|e| {
93            error!("❌ 解析 agent_config.json 失败: {}", e);
94            AgentConfig::default()
95        }),
96        Err(e) => {
97            error!("❌ 读取 agent_config.json 失败: {}", e);
98            AgentConfig::default()
99        }
100    }
101}
102
103/// 保存 Agent 配置
104pub fn save_agent_config(config: &AgentConfig) -> bool {
105    let path = agent_config_path();
106    if let Some(parent) = path.parent() {
107        let _ = fs::create_dir_all(parent);
108    }
109    match serde_json::to_string_pretty(config) {
110        Ok(json) => match fs::write(&path, json) {
111            Ok(_) => true,
112            Err(e) => {
113                error!("❌ 保存 agent_config.json 失败: {}", e);
114                false
115            }
116        },
117        Err(e) => {
118            error!("❌ 序列化 agent 配置失败: {}", e);
119            false
120        }
121    }
122}
123
124/// 加载对话历史
125pub fn load_chat_session() -> ChatSession {
126    let path = chat_history_path();
127    if !path.exists() {
128        return ChatSession::default();
129    }
130    match fs::read_to_string(&path) {
131        Ok(content) => serde_json::from_str(&content).unwrap_or_else(|_| ChatSession::default()),
132        Err(_) => ChatSession::default(),
133    }
134}
135
136/// 保存对话历史
137pub fn save_chat_session(session: &ChatSession) -> bool {
138    let path = chat_history_path();
139    if let Some(parent) = path.parent() {
140        let _ = fs::create_dir_all(parent);
141    }
142    match serde_json::to_string_pretty(session) {
143        Ok(json) => fs::write(&path, json).is_ok(),
144        Err(_) => false,
145    }
146}