update
This commit is contained in:
parent
75286acc9a
commit
318f7eb08f
@ -5,7 +5,7 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
image: tradus-web:1.0.27
|
image: tradus-web:1.1
|
||||||
container_name: tradus-web
|
container_name: tradus-web
|
||||||
ports:
|
ports:
|
||||||
- '6000:80'
|
- '6000:80'
|
||||||
|
|||||||
@ -6,11 +6,13 @@ import { marked } from 'marked'
|
|||||||
// 配置 marked
|
// 配置 marked
|
||||||
marked.setOptions({
|
marked.setOptions({
|
||||||
async: false,
|
async: false,
|
||||||
|
gfm: true,
|
||||||
|
breaks: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
// 渲染 Markdown
|
// 渲染 Markdown
|
||||||
const renderMarkdown = (content: string) => {
|
const renderMarkdown = (content: string) => {
|
||||||
return marked.parse(content)
|
return `<div class="markdown-body">${marked.parse(content)}</div>`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 定义Agent类型
|
// 定义Agent类型
|
||||||
@ -111,6 +113,7 @@ const userInput = ref('')
|
|||||||
const chatHistory = ref<ChatMessage[]>([])
|
const chatHistory = ref<ChatMessage[]>([])
|
||||||
const isLoading = ref(false)
|
const isLoading = ref(false)
|
||||||
const messagesContainer = ref<HTMLElement | null>(null)
|
const messagesContainer = ref<HTMLElement | null>(null)
|
||||||
|
const currentResponseText = ref('')
|
||||||
|
|
||||||
// 当用户不是VIP时,显示提示
|
// 当用户不是VIP时,显示提示
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@ -154,6 +157,9 @@ const sendMessage = async () => {
|
|||||||
if (!userInput.value.trim() || isLoading.value || !isAuthenticated.value || !selectedAgent.value)
|
if (!userInput.value.trim() || isLoading.value || !isAuthenticated.value || !selectedAgent.value)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
// 重置当前响应文本
|
||||||
|
currentResponseText.value = ''
|
||||||
|
|
||||||
// 添加用户消息到历史记录
|
// 添加用户消息到历史记录
|
||||||
chatHistory.value.push({
|
chatHistory.value.push({
|
||||||
role: 'user',
|
role: 'user',
|
||||||
@ -210,7 +216,6 @@ const sendMessage = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const decoder = new TextDecoder()
|
const decoder = new TextDecoder()
|
||||||
let responseText = ''
|
|
||||||
|
|
||||||
// 处理流式响应
|
// 处理流式响应
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -227,43 +232,20 @@ const sendMessage = async () => {
|
|||||||
const data = JSON.parse(line.slice(6))
|
const data = JSON.parse(line.slice(6))
|
||||||
|
|
||||||
switch (data.event) {
|
switch (data.event) {
|
||||||
case 'agent_thought':
|
case 'agent_message':
|
||||||
// 记录使用的工具
|
if (data.answer) {
|
||||||
if (data.tool) {
|
currentResponseText.value += data.answer
|
||||||
if (!chatHistory.value[tempMessageIndex].tools) {
|
chatHistory.value[tempMessageIndex].content = currentResponseText.value
|
||||||
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
|
|
||||||
}
|
|
||||||
await scrollToBottom()
|
await scrollToBottom()
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'agent_message':
|
case 'agent_thought':
|
||||||
if (data.answer) {
|
if (data.tool) {
|
||||||
responseText += data.answer
|
const thoughtText = `AI正在调用 ${data.tool} 工具来回答问题`
|
||||||
|
chatHistory.value[tempMessageIndex].content = currentResponseText.value
|
||||||
// 更新临时助手消息的内容,保留工具列表
|
? `${thoughtText}\n\n${currentResponseText.value}`
|
||||||
let toolsText = ''
|
: thoughtText
|
||||||
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
|
|
||||||
}
|
|
||||||
await scrollToBottom()
|
await scrollToBottom()
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
@ -357,9 +339,18 @@ const getIconPath = (agent: Agent) => {
|
|||||||
<div class="chat-window">
|
<div class="chat-window">
|
||||||
<div class="messages-container" ref="messagesContainer">
|
<div class="messages-container" ref="messagesContainer">
|
||||||
<div v-for="(message, index) in chatHistory" :key="index" class="message-wrapper">
|
<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-content">
|
||||||
<div class="message-text" v-html="renderMarkdown(message.content)"></div>
|
<div v-html="renderMarkdown(message.content)"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -586,7 +577,7 @@ const getIconPath = (agent: Agent) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.message-wrapper {
|
.message-wrapper {
|
||||||
margin: 0.5rem 0;
|
margin: 0.75rem 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
@ -597,7 +588,8 @@ const getIconPath = (agent: Agent) => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-message {
|
.ai-message,
|
||||||
|
.thought-message {
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -612,8 +604,6 @@ const getIconPath = (agent: Agent) => {
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
max-width: 800px;
|
max-width: 800px;
|
||||||
min-width: 4em;
|
min-width: 4em;
|
||||||
padding: 1.5rem;
|
|
||||||
border-radius: 0.75rem;
|
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
@ -627,49 +617,50 @@ const getIconPath = (agent: Agent) => {
|
|||||||
background-color: var(--color-accent);
|
background-color: var(--color-accent);
|
||||||
color: white;
|
color: white;
|
||||||
border-radius: 1rem 1rem 0 1rem;
|
border-radius: 1rem 1rem 0 1rem;
|
||||||
|
padding: 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-message .message-content {
|
.ai-message .message-content {
|
||||||
background-color: var(--color-bg-secondary);
|
background-color: var(--color-bg-secondary);
|
||||||
color: var(--color-text-primary);
|
color: var(--color-text-primary);
|
||||||
border-radius: 1rem 1rem 1rem 0;
|
border-radius: 1rem 1rem 1rem 0;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
padding: 1.25rem;
|
||||||
|
margin-top: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-text {
|
.thought-message .message-content {
|
||||||
font-size: 1rem;
|
background-color: rgba(var(--color-accent-rgb), 0.08);
|
||||||
line-height: 1.4;
|
color: var(--color-text-secondary);
|
||||||
white-space: pre-wrap;
|
border-radius: 0.75rem;
|
||||||
word-break: break-word;
|
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;
|
.thought-message + .ai-message {
|
||||||
line-height: 1.4;
|
margin-top: 0.25rem;
|
||||||
display: inline-block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-text :deep(p:last-child) {
|
/* 确保思考消息和AI回复之间的视觉关联 */
|
||||||
margin-bottom: 0;
|
.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),
|
.thought-message .message-content {
|
||||||
.message-text :deep(ol) {
|
max-width: 85%;
|
||||||
margin: 0.2em 0;
|
font-size: 0.9rem;
|
||||||
padding-left: 1.2em;
|
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 {
|
.input-container {
|
||||||
@ -761,7 +752,7 @@ const getIconPath = (agent: Agent) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
:deep(.markdown-body p) {
|
:deep(.markdown-body p) {
|
||||||
margin: 0.2em 0;
|
margin: 0;
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
@ -799,36 +790,20 @@ const getIconPath = (agent: Agent) => {
|
|||||||
border-left: 4px solid var(--color-accent);
|
border-left: 4px solid var(--color-accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.markdown-body table) {
|
:deep(.markdown-body ul),
|
||||||
border-collapse: collapse;
|
:deep(.markdown-body ol) {
|
||||||
width: 100%;
|
margin: 0.2em 0;
|
||||||
margin: 0.5rem 0;
|
padding-left: 1.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.markdown-body th),
|
:deep(.markdown-body li) {
|
||||||
:deep(.markdown-body td) {
|
margin: 0;
|
||||||
border: 1px solid var(--color-border);
|
line-height: 1.4;
|
||||||
padding: 0.5rem;
|
|
||||||
text-align: left;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.markdown-body th) {
|
:deep(.markdown-body li > p) {
|
||||||
background-color: var(--color-bg-secondary);
|
display: inline;
|
||||||
}
|
margin: 0;
|
||||||
|
|
||||||
: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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 修改 Agent 选择器样式 */
|
/* 修改 Agent 选择器样式 */
|
||||||
@ -1020,4 +995,32 @@ const getIconPath = (agent: Agent) => {
|
|||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
overflow-wrap: 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>
|
</style>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user