feat: 添加生成对话标题功能,支持根据内容自动生成简短标题,使用 fast_model
This commit is contained in:
parent
74229c05a4
commit
53e0ed37f6
@ -47,11 +47,11 @@ class Config(BaseModel):
|
|||||||
# 模型配置
|
# 模型配置
|
||||||
# ============================================================
|
# ============================================================
|
||||||
default_model: str = Field(
|
default_model: str = Field(
|
||||||
default="siliconflow/Pro/deepseek-ai/DeepSeek-V3.2",
|
default="siliconflow/Pro/MiniMaxAI/MiniMax-M2.5",
|
||||||
description="默认对话模型",
|
description="默认对话模型",
|
||||||
)
|
)
|
||||||
fast_model: str = Field(
|
fast_model: str = Field(
|
||||||
default="siliconflow/Qwen/Qwen3.5-9B",
|
default="siliconflow/Pro/MiniMaxAI/MiniMax-M2.5",
|
||||||
description="快速响应模型",
|
description="快速响应模型",
|
||||||
)
|
)
|
||||||
embed_model: str = Field(
|
embed_model: str = Field(
|
||||||
@ -63,7 +63,7 @@ class Config(BaseModel):
|
|||||||
description="默认 Re-Ranker 模型",
|
description="默认 Re-Ranker 模型",
|
||||||
)
|
)
|
||||||
content_guard_llm_model: str = Field(
|
content_guard_llm_model: str = Field(
|
||||||
default="siliconflow/Qwen/Qwen3.5-9B",
|
default="siliconflow/Pro/MiniMaxAI/MiniMax-M2.5",
|
||||||
description="内容审查LLM模型",
|
description="内容审查LLM模型",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -52,6 +52,20 @@ export const agentApi = {
|
|||||||
*/
|
*/
|
||||||
simpleCall: (query) => apiPost('/api/chat/call', { query }),
|
simpleCall: (query) => apiPost('/api/chat/call', { query }),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成对话标题
|
||||||
|
* @param {string} query - 查询内容
|
||||||
|
* @param {Object} modelSpec - 模型配置
|
||||||
|
* @returns {Promise<string>} - 生成的标题
|
||||||
|
*/
|
||||||
|
generateTitle: async (query, modelSpec) => {
|
||||||
|
const response = await apiPost('/api/chat/call', {
|
||||||
|
query: `根据以下对话内容生成一个简短的标题(最多30个字符,中英文均可),不要包含 markdown 标记:\n\n${query.slice(0, 2000)}`,
|
||||||
|
meta: { model_spec: modelSpec }
|
||||||
|
})
|
||||||
|
return response.response
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取默认智能体
|
* 获取默认智能体
|
||||||
* @returns {Promise} - 默认智能体信息
|
* @returns {Promise} - 默认智能体信息
|
||||||
|
|||||||
@ -63,6 +63,12 @@
|
|||||||
<MessageCirclePlus v-else class="nav-btn-icon" size="16" />
|
<MessageCirclePlus v-else class="nav-btn-icon" size="16" />
|
||||||
<span class="text">新对话</span>
|
<span class="text">新对话</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="currentThread?.title && currentThread.title !== '新的对话'"
|
||||||
|
class="conversation-title"
|
||||||
|
>
|
||||||
|
{{ currentThread.title }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="header__right">
|
<div class="header__right">
|
||||||
<UserInfoComponent v-if="!userStore.isAdmin" />
|
<UserInfoComponent v-if="!userStore.isAdmin" />
|
||||||
@ -227,6 +233,7 @@ import { useAgentStore } from '@/stores/agent'
|
|||||||
import { useChatUIStore } from '@/stores/chatUI'
|
import { useChatUIStore } from '@/stores/chatUI'
|
||||||
import { useInfoStore } from '@/stores/info'
|
import { useInfoStore } from '@/stores/info'
|
||||||
import { useUserStore } from '@/stores/user'
|
import { useUserStore } from '@/stores/user'
|
||||||
|
import { useConfigStore } from '@/stores/config'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { MessageProcessor } from '@/utils/messageProcessor'
|
import { MessageProcessor } from '@/utils/messageProcessor'
|
||||||
import { agentApi, threadApi } from '@/apis'
|
import { agentApi, threadApi } from '@/apis'
|
||||||
@ -250,6 +257,7 @@ const agentStore = useAgentStore()
|
|||||||
const chatUIStore = useChatUIStore()
|
const chatUIStore = useChatUIStore()
|
||||||
const infoStore = useInfoStore()
|
const infoStore = useInfoStore()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
const configStore = useConfigStore()
|
||||||
const {
|
const {
|
||||||
agents,
|
agents,
|
||||||
selectedAgentId,
|
selectedAgentId,
|
||||||
@ -798,11 +806,24 @@ const sendMessage = async ({
|
|||||||
return Promise.reject(error)
|
return Promise.reject(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果是新对话,用消息内容作为标题
|
// 如果是新对话,用 fast-model 异步生成标题(不阻塞消息发送)
|
||||||
if ((threadMessages.value[threadId] || []).length === 0) {
|
if ((threadMessages.value[threadId] || []).length === 0) {
|
||||||
const autoTitle = text.replace(/\s+/g, ' ').trim().slice(0, 255)
|
const autoTitle = text.replace(/\s+/g, ' ').trim().slice(0, 2000)
|
||||||
if (autoTitle) {
|
if (autoTitle) {
|
||||||
void updateThread(threadId, autoTitle).catch(() => {})
|
void (async () => {
|
||||||
|
try {
|
||||||
|
const generatedTitle = await agentApi.generateTitle(autoTitle, configStore.config?.fast_model)
|
||||||
|
if (generatedTitle) {
|
||||||
|
const finalTitle = generatedTitle.slice(0, 30).replace(/\s+/g, ' ').trim()
|
||||||
|
if (finalTitle) {
|
||||||
|
void updateThread(threadId, finalTitle).catch(() => {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// 失败时使用原始文本作为标题
|
||||||
|
void updateThread(threadId, autoTitle.slice(0, 30)).catch(() => {})
|
||||||
|
}
|
||||||
|
})()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1017,9 +1038,22 @@ const handleSendMessage = async ({ image } = {}) => {
|
|||||||
|
|
||||||
if (useRunsApi) {
|
if (useRunsApi) {
|
||||||
if ((threadMessages.value[threadId] || []).length === 0) {
|
if ((threadMessages.value[threadId] || []).length === 0) {
|
||||||
const autoTitle = text.replace(/\s+/g, ' ').trim().slice(0, 255)
|
const autoTitle = text.replace(/\s+/g, ' ').trim().slice(0, 2000)
|
||||||
if (autoTitle) {
|
if (autoTitle) {
|
||||||
void updateThread(threadId, autoTitle).catch(() => {})
|
void (async () => {
|
||||||
|
try {
|
||||||
|
const generatedTitle = await agentApi.generateTitle(autoTitle, configStore.config?.fast_model)
|
||||||
|
if (generatedTitle) {
|
||||||
|
const finalTitle = generatedTitle.slice(0, 30).replace(/\s+/g, ' ').trim()
|
||||||
|
if (finalTitle) {
|
||||||
|
void updateThread(threadId, finalTitle).catch(() => {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// 失败时使用原始文本作为标题
|
||||||
|
void updateThread(threadId, autoTitle.slice(0, 30)).catch(() => {})
|
||||||
|
}
|
||||||
|
})()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1459,6 +1493,17 @@ watch(
|
|||||||
.sidebar-logo-toggle:hover .sidebar-expand-overlay {
|
.sidebar-logo-toggle:hover .sidebar-expand-overlay {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.conversation-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--text-primary);
|
||||||
|
max-width: 200px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user