feat: 优化话题描述生成逻辑,增加空描述回退机制;更新话题创建命令以自动聚焦新话题
This commit is contained in:
parent
dad0f57b9b
commit
a4cdb31ba0
@ -4,15 +4,17 @@ pub async fn generate_topic_description(
|
|||||||
provider: &dyn LLMProvider,
|
provider: &dyn LLMProvider,
|
||||||
first_user_message: &str,
|
first_user_message: &str,
|
||||||
) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let prompt = format!(
|
let system_prompt = "你是一个话题摘要助手。请根据用户的第一句话,用简短的词语(不超过15字)描述这个对话的主题或意图。只输出描述内容,不要任何解释、标点或前缀。";
|
||||||
"请根据用户的第一句话,用简短的词语(不超过15字)描述这个对话的主题或意图。只输出描述内容,不要其他解释。\n\n用户消息:{}",
|
|
||||||
first_user_message
|
let user_prompt = format!("用户消息:{}", first_user_message);
|
||||||
);
|
|
||||||
|
|
||||||
let request = ChatCompletionRequest {
|
let request = ChatCompletionRequest {
|
||||||
messages: vec![Message::user(prompt)],
|
messages: vec![
|
||||||
temperature: Some(0.3),
|
Message::system(system_prompt),
|
||||||
max_tokens: Some(50),
|
Message::user(user_prompt),
|
||||||
|
],
|
||||||
|
temperature: Some(0.0),
|
||||||
|
max_tokens: Some(1024), // 给 reasoning 模型留足思考空间
|
||||||
tools: None,
|
tools: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -20,6 +22,24 @@ pub async fn generate_topic_description(
|
|||||||
let description = response.content.trim().to_string();
|
let description = response.content.trim().to_string();
|
||||||
|
|
||||||
if description.is_empty() {
|
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());
|
return Err("LLM returned empty description".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -202,7 +202,7 @@ function App() {
|
|||||||
let cmd: Command
|
let cmd: Command
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case 'new':
|
case 'new':
|
||||||
cmd = { type: 'create_session', title: args.join(' ') || undefined }
|
cmd = createTopic(args.join(' ') || undefined)
|
||||||
break
|
break
|
||||||
case 'list':
|
case 'list':
|
||||||
cmd = { type: 'list_sessions', include_archived: args[0] === 'all' }
|
cmd = { type: 'list_sessions', include_archived: args[0] === 'all' }
|
||||||
|
|||||||
@ -158,6 +158,7 @@ export function useChat(): UseChatReturn {
|
|||||||
const schedulerViewRef = useRef<SchedulerJobView | null>(null)
|
const schedulerViewRef = useRef<SchedulerJobView | null>(null)
|
||||||
const topicsRef = useRef<Topic[]>([])
|
const topicsRef = useRef<Topic[]>([])
|
||||||
const selectedTopicRef = useRef<string | null>(null)
|
const selectedTopicRef = useRef<string | null>(null)
|
||||||
|
const pendingNewTopicRef = useRef(false)
|
||||||
|
|
||||||
const isConnected = useMemo(() => connectionId !== null, [connectionId])
|
const isConnected = useMemo(() => connectionId !== null, [connectionId])
|
||||||
const selectedSession = useMemo(
|
const selectedSession = useMemo(
|
||||||
@ -402,7 +403,15 @@ export function useChat(): UseChatReturn {
|
|||||||
}))
|
}))
|
||||||
setTopics(newTopics)
|
setTopics(newTopics)
|
||||||
|
|
||||||
// 默认选中第一个 Topic(如果没有选中)
|
// 新建话题后自动聚焦到新话题(列表按 last_active_at DESC 排序,第一个即最新)
|
||||||
|
if (pendingNewTopicRef.current) {
|
||||||
|
pendingNewTopicRef.current = false
|
||||||
|
if (newTopics.length > 0) {
|
||||||
|
setSelectedTopic(newTopics[0].id)
|
||||||
|
setMessages([])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -592,6 +601,7 @@ export function useChat(): UseChatReturn {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const createTopic = useCallback((title?: string): Command => {
|
const createTopic = useCallback((title?: string): Command => {
|
||||||
|
pendingNewTopicRef.current = true
|
||||||
return {
|
return {
|
||||||
type: 'create_session',
|
type: 'create_session',
|
||||||
title: title || `话题 ${new Date().toLocaleString('zh-CN', { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' })}`,
|
title: title || `话题 ${new Date().toLocaleString('zh-CN', { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' })}`,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user