update
This commit is contained in:
parent
75286acc9a
commit
318f7eb08f
@ -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'
|
||||
|
||||
@ -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 `<div class="markdown-body">${marked.parse(content)}</div>`
|
||||
}
|
||||
|
||||
// 定义Agent类型
|
||||
@ -111,6 +113,7 @@ const userInput = ref('')
|
||||
const chatHistory = ref<ChatMessage[]>([])
|
||||
const isLoading = ref(false)
|
||||
const messagesContainer = ref<HTMLElement | null>(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) => {
|
||||
<div class="chat-window">
|
||||
<div class="messages-container" ref="messagesContainer">
|
||||
<div v-for="(message, index) in chatHistory" :key="index" class="message-wrapper">
|
||||
<div :class="['message', message.role === 'user' ? 'user-message' : 'ai-message']">
|
||||
<div
|
||||
:class="[
|
||||
'message',
|
||||
message.role === 'user'
|
||||
? 'user-message'
|
||||
: message.role === 'thought'
|
||||
? 'thought-message'
|
||||
: 'ai-message',
|
||||
]"
|
||||
>
|
||||
<div class="message-content">
|
||||
<div class="message-text" v-html="renderMarkdown(message.content)"></div>
|
||||
<div v-html="renderMarkdown(message.content)"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -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;
|
||||
.thought-message .message-content {
|
||||
max-width: 85%;
|
||||
font-size: 0.9rem;
|
||||
padding: 0.6rem 0.8rem;
|
||||
}
|
||||
|
||||
.message-text :deep(li) {
|
||||
margin: 0;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.message-text :deep(li > p) {
|
||||
display: inline;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
</style>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user