diff --git a/docker-compose.yml b/docker-compose.yml index 1ae1a21..f7a4814 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,7 +5,7 @@ services: build: context: . dockerfile: Dockerfile - image: tradus-web:1.0.27 + image: tradus-web:1.1 container_name: tradus-web ports: - '6000:80' diff --git a/src/views/AIAgentView.vue b/src/views/AIAgentView.vue index f5c8481..5c04c14 100644 --- a/src/views/AIAgentView.vue +++ b/src/views/AIAgentView.vue @@ -6,11 +6,13 @@ import { marked } from 'marked' // 配置 marked marked.setOptions({ async: false, + gfm: true, + breaks: true, }) // 渲染 Markdown const renderMarkdown = (content: string) => { - return marked.parse(content) + return `
${marked.parse(content)}
` } // 定义Agent类型 @@ -111,6 +113,7 @@ const userInput = ref('') const chatHistory = ref([]) const isLoading = ref(false) const messagesContainer = ref(null) +const currentResponseText = ref('') // 当用户不是VIP时,显示提示 onMounted(() => { @@ -154,6 +157,9 @@ const sendMessage = async () => { if (!userInput.value.trim() || isLoading.value || !isAuthenticated.value || !selectedAgent.value) return + // 重置当前响应文本 + currentResponseText.value = '' + // 添加用户消息到历史记录 chatHistory.value.push({ role: 'user', @@ -210,7 +216,6 @@ const sendMessage = async () => { } const decoder = new TextDecoder() - let responseText = '' // 处理流式响应 while (true) { @@ -227,43 +232,20 @@ const sendMessage = async () => { const data = JSON.parse(line.slice(6)) switch (data.event) { - case 'agent_thought': - // 记录使用的工具 - if (data.tool) { - if (!chatHistory.value[tempMessageIndex].tools) { - chatHistory.value[tempMessageIndex].tools = [] - } - chatHistory.value[tempMessageIndex].tools?.push(data.tool) - - // 更新显示的工具列表 - let toolsText = '' - chatHistory.value[tempMessageIndex].tools?.forEach((tool, index) => { - toolsText += `${index + 1}.调用 ${tool} 工具\n` - }) - - if (responseText) { - chatHistory.value[tempMessageIndex].content = toolsText + '\n' + responseText - } else { - chatHistory.value[tempMessageIndex].content = toolsText - } + case 'agent_message': + if (data.answer) { + currentResponseText.value += data.answer + chatHistory.value[tempMessageIndex].content = currentResponseText.value await scrollToBottom() } break - case 'agent_message': - if (data.answer) { - responseText += data.answer - - // 更新临时助手消息的内容,保留工具列表 - let toolsText = '' - if (chatHistory.value[tempMessageIndex].tools?.length) { - chatHistory.value[tempMessageIndex].tools?.forEach((tool, index) => { - toolsText += `${index + 1}.调用 ${tool} 工具\n` - }) - chatHistory.value[tempMessageIndex].content = toolsText + '\n' + responseText - } else { - chatHistory.value[tempMessageIndex].content = responseText - } + case 'agent_thought': + if (data.tool) { + const thoughtText = `AI正在调用 ${data.tool} 工具来回答问题` + chatHistory.value[tempMessageIndex].content = currentResponseText.value + ? `${thoughtText}\n\n${currentResponseText.value}` + : thoughtText await scrollToBottom() } break @@ -357,9 +339,18 @@ const getIconPath = (agent: Agent) => {
-
+
-
+
@@ -586,7 +577,7 @@ const getIconPath = (agent: Agent) => { } .message-wrapper { - margin: 0.5rem 0; + margin: 0.75rem 0; display: flex; width: 100%; } @@ -597,7 +588,8 @@ const getIconPath = (agent: Agent) => { display: flex; } -.ai-message { +.ai-message, +.thought-message { justify-content: flex-start; width: 100%; display: flex; @@ -612,8 +604,6 @@ const getIconPath = (agent: Agent) => { display: inline-block; max-width: 800px; min-width: 4em; - padding: 1.5rem; - border-radius: 0.75rem; word-break: break-word; overflow-wrap: break-word; white-space: pre-wrap; @@ -627,49 +617,50 @@ const getIconPath = (agent: Agent) => { background-color: var(--color-accent); color: white; border-radius: 1rem 1rem 0 1rem; + padding: 1.25rem; } .ai-message .message-content { background-color: var(--color-bg-secondary); color: var(--color-text-primary); border-radius: 1rem 1rem 1rem 0; + border: 1px solid var(--color-border); + padding: 1.25rem; + margin-top: 0.5rem; } -.message-text { - font-size: 1rem; - line-height: 1.4; - white-space: pre-wrap; - word-break: break-word; +.thought-message .message-content { + background-color: rgba(var(--color-accent-rgb), 0.08); + color: var(--color-text-secondary); + border-radius: 0.75rem; + font-style: italic; + padding: 0.75rem 1rem; + border: 1px solid rgba(var(--color-accent-rgb), 0.15); + font-size: 0.95rem; + max-width: 600px; } -.message-text :deep(p) { - margin: 0.2em 0; - line-height: 1.4; - display: inline-block; +/* 调整思考消息的间距 */ +.thought-message + .ai-message { + margin-top: 0.25rem; } -.message-text :deep(p:last-child) { - margin-bottom: 0; +/* 确保思考消息和AI回复之间的视觉关联 */ +.thought-message { + margin-bottom: 0.25rem; } -.message-text :deep(p:first-child) { - margin-top: 0; -} +/* 移动端适配 */ +@media (max-width: 768px) { + .message-content { + max-width: 90%; + } -.message-text :deep(ul), -.message-text :deep(ol) { - margin: 0.2em 0; - padding-left: 1.2em; -} - -.message-text :deep(li) { - margin: 0; - line-height: 1.4; -} - -.message-text :deep(li > p) { - display: inline; - margin: 0; + .thought-message .message-content { + max-width: 85%; + font-size: 0.9rem; + padding: 0.6rem 0.8rem; + } } .input-container { @@ -761,7 +752,7 @@ const getIconPath = (agent: Agent) => { } :deep(.markdown-body p) { - margin: 0.2em 0; + margin: 0; line-height: 1.4; display: inline-block; } @@ -799,36 +790,20 @@ const getIconPath = (agent: Agent) => { border-left: 4px solid var(--color-accent); } -:deep(.markdown-body table) { - border-collapse: collapse; - width: 100%; - margin: 0.5rem 0; +:deep(.markdown-body ul), +:deep(.markdown-body ol) { + margin: 0.2em 0; + padding-left: 1.2em; } -:deep(.markdown-body th), -:deep(.markdown-body td) { - border: 1px solid var(--color-border); - padding: 0.5rem; - text-align: left; +:deep(.markdown-body li) { + margin: 0; + line-height: 1.4; } -:deep(.markdown-body th) { - background-color: var(--color-bg-secondary); -} - -:deep(.markdown-body img) { - max-width: 100%; - height: auto; - border-radius: 0.5rem; -} - -:deep(.markdown-body a) { - color: var(--color-accent); - text-decoration: none; -} - -:deep(.markdown-body a:hover) { - text-decoration: underline; +:deep(.markdown-body li > p) { + display: inline; + margin: 0; } /* 修改 Agent 选择器样式 */ @@ -1020,4 +995,32 @@ const getIconPath = (agent: Agent) => { word-break: break-word; overflow-wrap: break-word; } + +.user-message .markdown-body { + color: white; +} + +.user-message :deep(.markdown-body) { + color: white; +} + +.user-message :deep(.markdown-body pre) { + background-color: rgba(255, 255, 255, 0.1); + border-color: rgba(255, 255, 255, 0.2); +} + +.user-message :deep(.markdown-body blockquote) { + background-color: rgba(255, 255, 255, 0.1); + border-left-color: rgba(255, 255, 255, 0.3); +} + +.user-message :deep(.markdown-body a) { + color: white; + text-decoration: underline; +} + +.user-message :deep(.markdown-body code) { + color: white; + background-color: rgba(255, 255, 255, 0.1); +}