use crate::providers::{ChatCompletionRequest, LLMProvider, Message}; pub async fn generate_topic_description( provider: &dyn LLMProvider, first_user_message: &str, ) -> Result> { let system_prompt = "你是一个话题摘要助手。请根据用户的第一句话,用简短的词语(不超过15字)描述这个对话的主题或意图。只输出描述内容,不要任何解释、标点或前缀。"; let user_prompt = format!("用户消息:{}", first_user_message); let request = ChatCompletionRequest { messages: vec![ Message::system(system_prompt), Message::user(user_prompt), ], temperature: Some(0.0), max_tokens: Some(1024), // 给 reasoning 模型留足思考空间 tools: None, }; let response = provider.chat(request).await?; let description = response.content.trim().to_string(); if description.is_empty() { // 回退:reasoning 模型有时把所有 token 都消耗在推理上,content 为空 // 此时尝试从 reasoning_content 中提取最后一行有意义的内容作为描述 if let Some(ref reasoning) = response.reasoning_content { let fallback: String = reasoning .lines() .rev() .find(|line| { let trimmed = line.trim(); !trimmed.is_empty() && trimmed.len() <= 50 }) .unwrap_or("") .trim() .to_string(); if !fallback.is_empty() { let truncated: String = fallback.chars().take(50).collect(); return Ok(truncated); } } return Err("LLM returned empty description".into()); } if description.len() > 50 { Ok(description.chars().take(50).collect()) } else { Ok(description) } }