修改代码,去掉原有组件的请求后端的方式。改用更简单的EventSource的方式。确保结果渲染正确。
This commit is contained in:
@@ -5,7 +5,7 @@ import type {
|
|||||||
ConversationsProps,
|
ConversationsProps,
|
||||||
PromptsProps,
|
PromptsProps,
|
||||||
} from 'ant-design-x-vue'
|
} from 'ant-design-x-vue'
|
||||||
import type { VNode } from 'vue'
|
import type { Component, VNode } from 'vue'
|
||||||
import {
|
import {
|
||||||
CloudUploadOutlined,
|
CloudUploadOutlined,
|
||||||
CommentOutlined,
|
CommentOutlined,
|
||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
ShareAltOutlined,
|
ShareAltOutlined,
|
||||||
SmileOutlined,
|
SmileOutlined,
|
||||||
} from '@ant-design/icons-vue'
|
} from '@ant-design/icons-vue'
|
||||||
import { Badge, Button, Flex, Space, Typography, theme } from 'ant-design-vue'
|
import { Badge, Button, Flex, Space, theme } from 'ant-design-vue'
|
||||||
import {
|
import {
|
||||||
Attachments,
|
Attachments,
|
||||||
Bubble,
|
Bubble,
|
||||||
@@ -213,7 +213,7 @@ let messageIdCounter = 0
|
|||||||
|
|
||||||
// ==================== Runtime ====================
|
// ==================== Runtime ====================
|
||||||
async function sendMessage(userMessage: string) {
|
async function sendMessage(userMessage: string) {
|
||||||
console.log('📝 [Submit] 用户提交消息:', userMessage)
|
console.log('[Submit] 用户提交消息:', userMessage)
|
||||||
if (!userMessage) return
|
if (!userMessage) return
|
||||||
|
|
||||||
// 添加用户消息
|
// 添加用户消息
|
||||||
@@ -243,10 +243,10 @@ async function sendMessage(userMessage: string) {
|
|||||||
message: userMessage,
|
message: userMessage,
|
||||||
conversionId: convId,
|
conversionId: convId,
|
||||||
}
|
}
|
||||||
console.log('📤 [Request] 请求体:', JSON.stringify(requestBody, null, 2))
|
console.log('[Request] 请求体:', JSON.stringify(requestBody, null, 2))
|
||||||
|
|
||||||
// 调用后端接口
|
// 调用后端接口 - POST 请求 SSE 流式响应
|
||||||
const response = await fetch('http://localhost:8080/dashscope/chat', {
|
const response = await fetch('http://localhost:8080/dashscope/generateStream', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
@@ -254,7 +254,7 @@ async function sendMessage(userMessage: string) {
|
|||||||
body: JSON.stringify(requestBody),
|
body: JSON.stringify(requestBody),
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log('📥 [Response] 响应状态:', response.status, response.statusText)
|
console.log('[Response] 响应状态:', response.status, response.statusText)
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`请求失败: ${response.status} ${response.statusText}`)
|
throw new Error(`请求失败: ${response.status} ${response.statusText}`)
|
||||||
@@ -266,25 +266,22 @@ async function sendMessage(userMessage: string) {
|
|||||||
const decoder = new TextDecoder()
|
const decoder = new TextDecoder()
|
||||||
let buffer = ''
|
let buffer = ''
|
||||||
|
|
||||||
console.log('🌊 [Stream] 开始读取流数据...')
|
console.log('[Stream] 开始读取流数据...')
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
let isFirstChunk = true
|
||||||
while (true) {
|
while (true) {
|
||||||
const { done, value } = await reader.read()
|
const { done, value } = await reader.read()
|
||||||
|
|
||||||
if (done) {
|
if (done) {
|
||||||
console.log('✅ [Stream] 流读取完成')
|
console.log('[Stream] 流读取完成')
|
||||||
const msg = messages.value[aiMsgIndex]
|
|
||||||
if (msg) {
|
|
||||||
msg.status = 'success'
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解码数据
|
// 解码数据
|
||||||
const text = decoder.decode(value, { stream: true })
|
const text = decoder.decode(value, { stream: true })
|
||||||
buffer += text
|
buffer += text
|
||||||
console.log('📦 [Stream] 收到原始数据:', text)
|
console.log('[Stream] 收到原始数据:', text)
|
||||||
|
|
||||||
// 解析 SSE 格式: data: content\n\n
|
// 解析 SSE 格式: data: content\n\n
|
||||||
const lines = buffer.split('\n\n')
|
const lines = buffer.split('\n\n')
|
||||||
@@ -299,14 +296,28 @@ async function sendMessage(userMessage: string) {
|
|||||||
for (const block of lines) {
|
for (const block of lines) {
|
||||||
if (block.startsWith('data:')) {
|
if (block.startsWith('data:')) {
|
||||||
// 提取 data: 后面的内容
|
// 提取 data: 后面的内容
|
||||||
const content = block.substring(5)
|
const data = block.substring(5).trim()
|
||||||
console.log('✨ [Parse] 解析后的内容:', JSON.stringify(content))
|
console.log('[Parse] 接收到数据:', data)
|
||||||
|
|
||||||
// 直接累积到消息内容
|
if (data) { // 若响应数据不为空
|
||||||
|
// 解析 JSON
|
||||||
|
const response = JSON.parse(data)
|
||||||
|
console.log('[Parse] 解析后的内容:', JSON.stringify(response))
|
||||||
|
|
||||||
|
// 更新消息内容并强制触发响应式更新
|
||||||
const msg = messages.value[aiMsgIndex]
|
const msg = messages.value[aiMsgIndex]
|
||||||
if (msg) {
|
if (msg) {
|
||||||
msg.content += content
|
// 第一次接收到数据时,将状态改为 success,这样内容才会显示
|
||||||
console.log('🔄 [Update] 更新消息, 当前长度:', msg.content.length)
|
if (isFirstChunk) {
|
||||||
|
isFirstChunk = false
|
||||||
|
console.log('[Stream] 首次接收数据,设置状态为 success')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 持续追加流式回答
|
||||||
|
msg.content += response.v
|
||||||
|
msg.status = 'success'
|
||||||
|
console.log('[Update] 更新消息, 当前长度:', msg.content.length)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -316,7 +327,7 @@ async function sendMessage(userMessage: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ [Error] 请求错误:', error)
|
console.error('[Error] 请求错误:', error)
|
||||||
const msg = messages.value[aiMsgIndex]
|
const msg = messages.value[aiMsgIndex]
|
||||||
if (msg) {
|
if (msg) {
|
||||||
msg.status = 'error'
|
msg.status = 'error'
|
||||||
@@ -331,7 +342,7 @@ watch(
|
|||||||
activeKey,
|
activeKey,
|
||||||
() => {
|
() => {
|
||||||
if (activeKey.value !== undefined) {
|
if (activeKey.value !== undefined) {
|
||||||
console.log('🔄 [Conversation] 切换会话:', activeKey.value)
|
console.log('[Conversation] 切换会话:', activeKey.value)
|
||||||
messages.value = []
|
messages.value = []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -370,18 +381,16 @@ const handleFileChange: AttachmentsProps['onChange'] = (info) =>
|
|||||||
// ==================== Nodes ====================
|
// ==================== Nodes ====================
|
||||||
const placeholderNode = computed(() =>
|
const placeholderNode = computed(() =>
|
||||||
h(Space, { direction: 'vertical', size: 16, style: styles.value.placeholder }, () => [
|
h(Space, { direction: 'vertical', size: 16, style: styles.value.placeholder }, () => [
|
||||||
h(Welcome, {
|
h(Welcome as Component, {
|
||||||
variant: 'borderless',
|
variant: 'borderless',
|
||||||
icon: 'https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*s5sNRo5LjfQAAAAAAAAAAAAADgCCAQ/fmt.webp',
|
icon: 'https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*s5sNRo5LjfQAAAAAAAAAAAAADgCCAQ/fmt.webp',
|
||||||
title: "Hello, I'm Ant Design X",
|
|
||||||
description: '基于Ant Design,AGI产品界面解决方案,创造更美好的智能愿景~',
|
description: '基于Ant Design,AGI产品界面解决方案,创造更美好的智能愿景~',
|
||||||
extra: h(Space, {}, () => [
|
extra: h(Space, {}, () => [
|
||||||
h(Button, { icon: h(ShareAltOutlined) }),
|
h(Button, { icon: h(ShareAltOutlined) }),
|
||||||
h(Button, { icon: h(EllipsisOutlined) }),
|
h(Button, { icon: h(EllipsisOutlined) }),
|
||||||
]),
|
]),
|
||||||
}),
|
}, () => "Hello, I'm Ant Design X"),
|
||||||
h(Prompts, {
|
h(Prompts as Component, {
|
||||||
title: '想要了是吧?',
|
|
||||||
items: placeholderPromptsItems,
|
items: placeholderPromptsItems,
|
||||||
styles: {
|
styles: {
|
||||||
list: {
|
list: {
|
||||||
@@ -392,20 +401,20 @@ const placeholderNode = computed(() =>
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
onItemClick: onPromptsItemClick,
|
onItemClick: onPromptsItemClick,
|
||||||
}),
|
}, () => '想要了是吧?'),
|
||||||
]),
|
]),
|
||||||
)
|
)
|
||||||
|
|
||||||
const items = computed<BubbleListProps['items']>(() => {
|
const items = computed<BubbleListProps['items']>(() => {
|
||||||
console.log('🎨 [Items] 计算 items, messages数量:', messages.value.length)
|
console.log('[Items] 计算 items, messages数量:', messages.value.length)
|
||||||
|
|
||||||
if (messages.value.length === 0) {
|
if (messages.value.length === 0) {
|
||||||
console.log('🎨 [Items] 显示占位符')
|
console.log('[Items] 显示占位符')
|
||||||
return [{ content: placeholderNode, variant: 'borderless' }]
|
return [{ content: placeholderNode, variant: 'borderless' }]
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = messages.value.map(({ id, role, content, status }) => {
|
const result = messages.value.map(({ id, role, content, status }) => {
|
||||||
console.log('🎨 [Items] 处理消息:', { id, role, status, contentLength: content?.length })
|
console.log('[Items] 处理消息:', { id, role, status, contentLength: content?.length })
|
||||||
return {
|
return {
|
||||||
key: id,
|
key: id,
|
||||||
loading: status === 'loading',
|
loading: status === 'loading',
|
||||||
@@ -414,7 +423,7 @@ const items = computed<BubbleListProps['items']>(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log('🎨 [Items] 最终 items:', result)
|
console.log('[Items] 最终 items:', result)
|
||||||
return result
|
return result
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
@@ -493,19 +502,19 @@ const items = computed<BubbleListProps['items']>(() => {
|
|||||||
vertical
|
vertical
|
||||||
gap="2"
|
gap="2"
|
||||||
>
|
>
|
||||||
<Typography.Text style="font-size: 30px; line-height: 1">
|
<div style="font-size: 30px; line-height: 1">
|
||||||
<CloudUploadOutlined />
|
<CloudUploadOutlined />
|
||||||
</Typography.Text>
|
</div>
|
||||||
<Typography.Title :level="5" style="margin: 0; font-size: 14px; line-height: 1.5">
|
<div style="margin: 0; font-size: 14px; line-height: 1.5; font-weight: 600">
|
||||||
Upload files
|
Upload files
|
||||||
</Typography.Title>
|
</div>
|
||||||
<Typography.Text type="secondary">
|
<div style="color: rgba(0, 0, 0, 0.45)">
|
||||||
Click or drag files to this area to upload
|
Click or drag files to this area to upload
|
||||||
</Typography.Text>
|
</div>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Typography.Text v-if="type && type.type === 'drop'">
|
<div v-if="type && type.type === 'drop'">
|
||||||
Drop file here
|
Drop file here
|
||||||
</Typography.Text>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Attachments>
|
</Attachments>
|
||||||
</Sender.Header>
|
</Sender.Header>
|
||||||
|
|||||||
Reference in New Issue
Block a user