51 lines
1.9 KiB
Rust
51 lines
1.9 KiB
Rust
use crate::providers::{ChatCompletionRequest, LLMProvider, Message};
|
||
|
||
pub async fn generate_topic_description(
|
||
provider: &dyn LLMProvider,
|
||
first_user_message: &str,
|
||
) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
|
||
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)
|
||
}
|
||
} |