|
|
|
@ -491,6 +491,19 @@ async function send(): Promise<void> { |
|
|
|
isSending.value = true |
|
|
|
currentSuggestions.value = [] // 清空建议 |
|
|
|
|
|
|
|
const cid = chatId.value || ('web_' + Date.now()) |
|
|
|
chatId.value = cid |
|
|
|
const requestMode = mode.value |
|
|
|
// 固定本轮参数,后台引用请求不读取后续切换的角色或 RAG 配置。 |
|
|
|
const imageUrls = attachments.filter(a => a.type === 'image').map(a => a.url) |
|
|
|
const chatOptions: ChatOptions = { |
|
|
|
roleId: currentRoleId(), |
|
|
|
enableRag: isRagMode.value, |
|
|
|
rewriteStrategy: isRagMode.value ? ragStrategy.value : undefined, |
|
|
|
categoryIds: [...selectedCategoryIds.value], |
|
|
|
imageUrls: imageUrls.length ? imageUrls : undefined, |
|
|
|
} |
|
|
|
|
|
|
|
// 追加用户消息(含附件) |
|
|
|
messages.value.push({ |
|
|
|
id: generateMsgId(), role: 'user', content: text, |
|
|
|
@ -505,32 +518,19 @@ async function send(): Promise<void> { |
|
|
|
messages.value.push(assistantMsg) |
|
|
|
await scrollToBottom() |
|
|
|
|
|
|
|
const cid = chatId.value || ('web_' + Date.now()) |
|
|
|
chatId.value = cid |
|
|
|
|
|
|
|
try { |
|
|
|
// 取消上一个 SSE 请求并创建新的 AbortController |
|
|
|
if (sseAbortController) { sseAbortController.abort() } |
|
|
|
sseAbortController = new AbortController() |
|
|
|
const signal = sseAbortController.signal |
|
|
|
|
|
|
|
// 统一对话请求参数(RAG 与普通对话共用同一接口,由 enableRag 参数区分) |
|
|
|
const imageUrls = attachments.filter(a => a.type === 'image').map(a => a.url) |
|
|
|
const chatOptions: ChatOptions = { |
|
|
|
roleId: currentRoleId(), |
|
|
|
enableRag: isRagMode.value, |
|
|
|
rewriteStrategy: isRagMode.value ? ragStrategy.value : undefined, |
|
|
|
categoryIds: selectedCategoryIds.value, |
|
|
|
imageUrls: imageUrls.length ? imageUrls : undefined, |
|
|
|
} |
|
|
|
|
|
|
|
if (mode.value === 'sync') { |
|
|
|
if (requestMode === 'sync') { |
|
|
|
// 同步调用 |
|
|
|
assistantMsg.content = await chatSync(text, cid, chatOptions) |
|
|
|
} else { |
|
|
|
// SSE 流式 |
|
|
|
const url = chatSSEUrl(text, cid, chatOptions) |
|
|
|
if (isRagMode.value) { |
|
|
|
if (chatOptions.enableRag) { |
|
|
|
await readSSEStreamWithEvents(url, { |
|
|
|
onMessage: async (chunk: string) => { |
|
|
|
assistantMsg.content += chunk |
|
|
|
@ -562,12 +562,16 @@ async function send(): Promise<void> { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// RAG 模式下,拉取引用来源 |
|
|
|
if (isRagMode.value) { |
|
|
|
try { |
|
|
|
const sj = await ragSources(text, cid, chatOptions) |
|
|
|
if (sj && sj.success) assistantMsg.sources = sj.data || [] |
|
|
|
} catch (_) { /* 来源获取失败不影响主回答 */ } |
|
|
|
// 引用来源后台补齐,正文完成后立即结束发送状态。 |
|
|
|
if (chatOptions.enableRag) { |
|
|
|
void ragSources(text, cid, chatOptions).then(sj => { |
|
|
|
if (!sj?.success) throw new Error(sj?.message || '引用来源获取失败') |
|
|
|
if (chatId.value !== cid || !messages.value.some(msg => msg.id === assistantMsg.id)) return |
|
|
|
assistantMsg.sources = sj.data || [] |
|
|
|
messages.value = [...messages.value] |
|
|
|
}).catch((e: any) => { |
|
|
|
toast('引用来源获取失败: ' + (e.message || e), 'warning') |
|
|
|
}) |
|
|
|
} |
|
|
|
} catch (e: any) { |
|
|
|
// AbortError 不是真正的错误,不显示错误信息 |
|
|
|
|