Skip to main content

j_cli/command/chat/
mod.rs

1pub mod api;
2pub mod app;
3pub mod handler;
4pub mod markdown;
5pub mod model;
6pub mod render;
7pub mod theme;
8pub mod ui;
9
10use crate::command::chat::theme::ThemeName;
11use crate::config::YamlConfig;
12use crate::{error, info};
13use api::call_openai_stream;
14use handler::run_chat_tui;
15use model::{
16    AgentConfig, ChatMessage, ModelProvider, agent_config_path, load_agent_config,
17    save_agent_config,
18};
19use std::io::{self, Write};
20
21pub fn handle_chat(content: &[String], _config: &YamlConfig) {
22    let agent_config = load_agent_config();
23
24    if agent_config.providers.is_empty() {
25        info!("⚠️  尚未配置 LLM 模型提供方。");
26        info!("📁 请编辑配置文件: {}", agent_config_path().display());
27        info!("📝 配置示例:");
28        let example = AgentConfig {
29            providers: vec![ModelProvider {
30                name: "GPT-4o".to_string(),
31                api_base: "https://api.openai.com/v1".to_string(),
32                api_key: "sk-your-api-key".to_string(),
33                model: "gpt-4o".to_string(),
34            }],
35            active_index: 0,
36            system_prompt: Some("你是一个有用的助手。".to_string()),
37            stream_mode: true,
38            max_history_messages: 20,
39            theme: ThemeName::default(),
40        };
41        if let Ok(json) = serde_json::to_string_pretty(&example) {
42            println!("{}", json);
43        }
44        // 自动创建示例配置文件
45        if !agent_config_path().exists() {
46            let _ = save_agent_config(&example);
47            info!(
48                "✅ 已自动创建示例配置文件: {}",
49                agent_config_path().display()
50            );
51            info!("📌 请修改其中的 api_key 和其他配置后重新运行 chat 命令");
52        }
53        return;
54    }
55
56    if content.is_empty() {
57        // 无参数:进入 TUI 对话界面
58        run_chat_tui();
59        return;
60    }
61
62    // 有参数:快速发送消息并打印回复
63    let message = content.join(" ");
64    let message = message.trim().to_string();
65    if message.is_empty() {
66        error!("⚠️ 消息内容为空");
67        return;
68    }
69
70    let idx = agent_config
71        .active_index
72        .min(agent_config.providers.len() - 1);
73    let provider = &agent_config.providers[idx];
74
75    info!("🤖 [{}] 思考中...", provider.name);
76
77    let mut messages = Vec::new();
78    if let Some(sys) = &agent_config.system_prompt {
79        messages.push(ChatMessage {
80            role: "system".to_string(),
81            content: sys.clone(),
82        });
83    }
84    messages.push(ChatMessage {
85        role: "user".to_string(),
86        content: message,
87    });
88
89    match call_openai_stream(provider, &messages, &mut |chunk| {
90        print!("{}", chunk);
91        let _ = io::stdout().flush();
92    }) {
93        Ok(_) => {
94            println!(); // 换行
95        }
96        Err(e) => {
97            error!("\n❌ {}", e);
98        }
99    }
100}