|
|
@@ -489,7 +489,7 @@ import { createSSEConnection, closeSSEConnection } from '@/utils/sse'
|
|
|
import { getApiPrefix, BACKEND_API_PREFIX } from '@/utils/apiConfig'
|
|
|
import { renderMarkdown } from '@/utils/markdown'
|
|
|
import { stopSSEStream, updateAIMessageContent } from '@/utils/api.js'
|
|
|
-import { buildPreviewUrl } from '@/utils/filePreviewUrl'
|
|
|
+import { buildPreviewUrl, buildPreviewUrlSync } from '@/utils/filePreviewUrl'
|
|
|
import {
|
|
|
applyReportChunkToMessage,
|
|
|
buildDisplayThinkingSummary,
|
|
|
@@ -710,8 +710,8 @@ const reportTypewriters = new Map() // 存储每个报告字段的打字机定
|
|
|
const typewriterIntervals = new Map() // 存储打字机定时器
|
|
|
const streamingAnswerTypewriters = new Map() // 存储流式回答的平滑渲染定时器
|
|
|
const databaseFileRevealTimers = new Map() // 存储召回文件逐条显现定时器
|
|
|
-const STREAMING_ANSWER_CHARS_PER_FRAME = 2
|
|
|
-const STREAMING_ANSWER_FRAME_MS = 1000 / 36
|
|
|
+const STREAMING_ANSWER_CHARS_PER_SECOND = 78
|
|
|
+const STREAMING_ANSWER_FRAME_MS = 1000 / 30
|
|
|
const FINAL_ANSWER_TYPEWRITER_SPEED = 80
|
|
|
const DATABASE_FILE_REVEAL_INTERVAL_MS = 320
|
|
|
|
|
|
@@ -2295,12 +2295,14 @@ const handleFilePreview = async (data) => {
|
|
|
fileError.value = ''
|
|
|
fileLoading.value = false
|
|
|
|
|
|
+ const rawPath = typeof data === 'string' ? data : data?.filePath
|
|
|
+
|
|
|
// 处理不同类型的输入参数
|
|
|
if (typeof data === 'string') {
|
|
|
- previewFilePath.value = await buildPreviewUrl(data)
|
|
|
+ previewFilePath.value = buildPreviewUrlSync(data)
|
|
|
previewFileName.value = data
|
|
|
} else if (data && data.filePath) {
|
|
|
- previewFilePath.value = await buildPreviewUrl(data.filePath)
|
|
|
+ previewFilePath.value = buildPreviewUrlSync(data.filePath)
|
|
|
previewFileName.value = data.fileName || data.filePath
|
|
|
} else {
|
|
|
fileError.value = '文件路径为空'
|
|
|
@@ -2317,6 +2319,15 @@ const handleFilePreview = async (data) => {
|
|
|
}
|
|
|
|
|
|
showFilePreview.value = true
|
|
|
+
|
|
|
+ try {
|
|
|
+ const convertedPath = await buildPreviewUrl(rawPath)
|
|
|
+ if (convertedPath && convertedPath !== previewFilePath.value) {
|
|
|
+ previewFilePath.value = convertedPath
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.warn('文件预览链接转换失败,使用原始链接:', error)
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
const toggleNetworkSearch = () => {
|
|
|
@@ -2701,14 +2712,22 @@ const ensureStreamingAnswerTypewriter = (message) => {
|
|
|
}
|
|
|
|
|
|
message._visibleAnswerLength = Number(message._visibleAnswerLength || 0)
|
|
|
+ message._answerTypewriterCarry = Number(message._answerTypewriterCarry || 0)
|
|
|
+ message._answerTypewriterLastTick = Date.now()
|
|
|
const interval = setInterval(() => {
|
|
|
const rawContent = String(message.content || '')
|
|
|
const targetLength = rawContent.length
|
|
|
|
|
|
if (message._visibleAnswerLength < targetLength) {
|
|
|
+ const now = Date.now()
|
|
|
+ const elapsed = Math.max(0, now - (message._answerTypewriterLastTick || now))
|
|
|
+ message._answerTypewriterLastTick = now
|
|
|
+ const exactChars = (elapsed / 1000) * STREAMING_ANSWER_CHARS_PER_SECOND + Number(message._answerTypewriterCarry || 0)
|
|
|
+ const charsToReveal = Math.max(1, Math.floor(exactChars))
|
|
|
+ message._answerTypewriterCarry = Math.max(0, exactChars - charsToReveal)
|
|
|
message._visibleAnswerLength = Math.min(
|
|
|
targetLength,
|
|
|
- message._visibleAnswerLength + STREAMING_ANSWER_CHARS_PER_FRAME
|
|
|
+ message._visibleAnswerLength + charsToReveal
|
|
|
)
|
|
|
renderAnswerPrefix(message, message._visibleAnswerLength)
|
|
|
return
|
|
|
@@ -2926,6 +2945,11 @@ const finalizeThinkingContent = (aiMessage) => {
|
|
|
aiMessage.showThinking = Boolean(aiMessage.thinkingContent)
|
|
|
}
|
|
|
|
|
|
+const buildInitialThinkingContent = (question) => buildDisplayThinkingSummary({
|
|
|
+ userQuestion: question || currentQuestion.value || '',
|
|
|
+ rawThinking: question || currentQuestion.value || ''
|
|
|
+})
|
|
|
+
|
|
|
const toggleThinkingPanel = (message) => {
|
|
|
message.showThinking = message.showThinking === false
|
|
|
}
|
|
|
@@ -3029,6 +3053,15 @@ const handleSSEMessage = (data, aiMessageIndex) => {
|
|
|
|
|
|
if (data.thinking_content) {
|
|
|
aiMessage.rawIntentThinkingContent = data.thinking_content
|
|
|
+ if (!aiMessage.rawThinkingContent) {
|
|
|
+ aiMessage.thinkingContent = buildDisplayThinkingSummary({
|
|
|
+ rawThinking: data.thinking_content,
|
|
|
+ existingThinking: '',
|
|
|
+ userQuestion: aiMessage.userQuestion || currentQuestion.value || '',
|
|
|
+ summary: data.summary || aiMessage._fullSummary || aiMessage.summary || ''
|
|
|
+ })
|
|
|
+ aiMessage.showThinking = true
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// 如果启用联网搜索,稍后会更新为web_searching状态
|
|
|
@@ -3831,6 +3864,7 @@ const handleReportGeneratorSubmit = async (data) => {
|
|
|
|
|
|
// 添加AI消息占位符
|
|
|
const aiMessageIndex = chatMessages.value.length
|
|
|
+ const initialThinkingContent = buildInitialThinkingContent(data.question)
|
|
|
chatMessages.value.push({
|
|
|
id: Date.now() + 1,
|
|
|
type: 'ai',
|
|
|
@@ -3845,9 +3879,9 @@ const handleReportGeneratorSubmit = async (data) => {
|
|
|
isTyping: true,
|
|
|
content: '',
|
|
|
displayContent: '',
|
|
|
- thinkingContent: '',
|
|
|
+ thinkingContent: initialThinkingContent,
|
|
|
showThinking: true,
|
|
|
- thinkingStreaming: false,
|
|
|
+ thinkingStreaming: true,
|
|
|
answerStreaming: false,
|
|
|
timestamp: new Date().toISOString(),
|
|
|
// 新增:状态管理
|