diff --git a/Cargo.lock b/Cargo.lock index 8f860a5..b836125 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5544,6 +5544,7 @@ dependencies = [ "dirs 5.0.1", "futures", "reqwest 0.12.28", + "rusqlite", "serde", "serde_json", "tauri", diff --git a/apps/desktop/Cargo.toml b/apps/desktop/Cargo.toml index 1c5f3ad..1d79a2b 100644 --- a/apps/desktop/Cargo.toml +++ b/apps/desktop/Cargo.toml @@ -29,6 +29,7 @@ reqwest.workspace = true futures.workspace = true uuid.workspace = true dirs.workspace = true +rusqlite.workspace = true xianren-core = { path = "../../crates/core" } xianren-engine = { path = "../../crates/engine" } xianren-download = { path = "../../crates/download" } diff --git a/apps/desktop/src/commands.rs b/apps/desktop/src/commands.rs index 3859ac0..b866842 100644 --- a/apps/desktop/src/commands.rs +++ b/apps/desktop/src/commands.rs @@ -217,10 +217,12 @@ pub fn list_conversations(state: State<'_, App>) -> Result, title: String, + model_id: Option, ) -> Result { let id = uuid::Uuid::new_v4().to_string(); let db = state.core.db.lock().unwrap(); - sessions_db::create_conversation(&db, &id, &title, None, None).map_err(|e| e.to_string())?; + sessions_db::create_conversation(&db, &id, &title, model_id.as_deref(), None) + .map_err(|e| e.to_string())?; sessions_db::get_conversation(&db, &id) .map_err(|e| e.to_string())? .ok_or_else(|| "conversation not found".to_string()) @@ -481,6 +483,9 @@ pub async fn chat_send( ) .map_err(|e| e.to_string())?; } + // 始终把当前使用的模型写回会话,编辑/重新生成依赖它 + sessions_db::update_conversation_model(&db, &payload.conversation_id, &payload.model_id) + .map_err(|e| e.to_string())?; let user_message_id = sessions_db::add_message( &db, &payload.conversation_id, @@ -724,6 +729,21 @@ fn estimate_tokens(text: &str) -> usize { score / 4 + 1 } +/// 解析会话使用的模型:优先会话记录;未记录时若本地只有一个模型则自动使用,否则提示。 +fn resolve_conversation_model( + db: &rusqlite::Connection, + conversation: &xianren_core::Conversation, +) -> Result { + if let Some(id) = &conversation.model_id { + return Ok(id.clone()); + } + let all = models_db::list(db).map_err(|e| e.to_string())?; + if all.len() == 1 { + return Ok(all[0].id.clone()); + } + Err("会话未记录模型:请先在该会话发送一条消息,或重新选择模型后重试".into()) +} + /// 重新生成某条助手回复:旧内容存入版本历史,截断后重新生成。 #[tauri::command] pub async fn regenerate_message( @@ -768,10 +788,7 @@ pub async fn regenerate_message( images: m.images.clone(), }) .collect::>(); - let model_id = conversation - .model_id - .clone() - .ok_or_else(|| "conversation has no model".to_string())?; + let model_id = resolve_conversation_model(&db, &conversation)?; let model = models_db::get(&db, &model_id) .map_err(|e| e.to_string())? .ok_or_else(|| "model not found".to_string())?; @@ -835,10 +852,7 @@ pub async fn edit_message( images: m.images, }) .collect::>(); - let model_id = conversation - .model_id - .clone() - .ok_or_else(|| "conversation has no model".to_string())?; + let model_id = resolve_conversation_model(&db, &conversation)?; let model = models_db::get(&db, &model_id) .map_err(|e| e.to_string())? .ok_or_else(|| "model not found".to_string())?; diff --git a/crates/core/src/sessions.rs b/crates/core/src/sessions.rs index f8b92a5..6b09ea5 100644 --- a/crates/core/src/sessions.rs +++ b/crates/core/src/sessions.rs @@ -85,6 +85,14 @@ pub fn touch_conversation(db: &Connection, id: &str) -> Result<()> { Ok(()) } +pub fn update_conversation_model(db: &Connection, id: &str, model_id: &str) -> Result<()> { + db.execute( + "UPDATE conversations SET model_id = ?1 WHERE id = ?2", + params![model_id, id], + )?; + Ok(()) +} + pub fn delete_conversation(db: &Connection, id: &str) -> Result<()> { db.execute("DELETE FROM conversations WHERE id = ?1", params![id])?; Ok(()) diff --git a/ui/src/api.ts b/ui/src/api.ts index 79ceabe..92ab8e8 100644 --- a/ui/src/api.ts +++ b/ui/src/api.ts @@ -194,8 +194,8 @@ export const api = { settingsSet: (key: string, value: string) => invoke("settings_set", { key, value }), listConversations: () => invoke("list_conversations"), - createConversation: (title: string) => - invoke("create_conversation", { title }), + createConversation: (title: string, modelId?: string) => + invoke("create_conversation", { title, modelId: modelId ?? null }), deleteConversation: (id: string) => invoke("delete_conversation", { id }), getMessages: (conversationId: string) => diff --git a/ui/src/pages/ChatPage.tsx b/ui/src/pages/ChatPage.tsx index a6c39d3..db7aed2 100644 --- a/ui/src/pages/ChatPage.tsx +++ b/ui/src/pages/ChatPage.tsx @@ -331,7 +331,7 @@ export default function ChatPage() { } async function handleNewConversation() { - const conv = await api.createConversation("新会话"); + const conv = await api.createConversation("新会话", selectedModelId || undefined); setActiveConvId(conv.id); setMessages([]); setError(null);