SSE流式响应完成

This commit is contained in:
2025-10-22 21:47:08 +08:00
parent 10270afc87
commit 9c69404bf9

View File

@@ -2,26 +2,29 @@
<div class="h-screen max-w-3xl mx-auto relative"> <div class="h-screen max-w-3xl mx-auto relative">
<!-- 聊天记录区域 --> <!-- 聊天记录区域 -->
<div class="overflow-y-auto pb-24 pt-4 px-4"> <div class="overflow-y-auto pb-24 pt-4 px-4">
<!-- 遍历聊天记录 -->
<template v-for="(chat, index) in chatList" :key="index">
<!-- 用户提问消息靠右 --> <!-- 用户提问消息靠右 -->
<div class="flex justify-end mb-4"> <div v-if="chat.role === 'user'" class="flex justify-end mb-4">
<div class="quesiton-container"> <div class="quesiton-container">
<p>你是谁</p> <p>{{ chat.content }}</p>
</div> </div>
</div> </div>
<!-- 大模型回复消息靠左 --> <!-- 大模型回复消息靠左 -->
<div class="flex mb-4"> <div v-else class="flex mb-4">
<!-- 头像 --> <!-- 头像 -->
<div class="flex-shrink-0 mr-3"> <div class="shrink-0 mr-3">
<div class="w-8 h-8 rounded-full flex items-center justify-center border border-gray-200"> <div class="w-8 h-8 rounded-full flex items-center justify-center border border-gray-200">
<SvgIcon name="deepseek-logo" customCss="w-5 h-5"></SvgIcon> <SvgIcon name="deepseek-logo" customCss="w-5 h-5"></SvgIcon>
</div> </div>
</div> </div>
<!-- 回复的内容 --> <!-- 回复的内容 -->
<div class="p-1 max-w-[80%] mb-2 grow"> <div class="p-1 max-w-[80%] mb-2">
<p>我是DeepSeek Chat由深度求索公司开发的智能AI助手 我可以帮你解答各种问题无论是学习工作还是日常生活中的小困惑都可以找我聊聊有什么我可以帮你的吗😊</p> <p>{{ chat.content }}</p>
</div> </div>
</div> </div>
</template>
</div> </div>
<!-- 提问输入框 --> <!-- 提问输入框 -->
<div class="absolute bottom-0 left-0 w-full mb-5"> <div class="absolute bottom-0 left-0 w-full mb-5">
@@ -34,6 +37,7 @@
<!-- 发送按钮 --> <!-- 发送按钮 -->
<div class="flex justify-end"> <div class="flex justify-end">
<button <button
@click="sendMessage"
class="flex items-center justify-center bg-[#4d6bfe] rounded-full w-8 h-8 border border-[#4d6bfe] hover:bg-[#3b5bef] transition-colors"> class="flex items-center justify-center bg-[#4d6bfe] rounded-full w-8 h-8 border border-[#4d6bfe] hover:bg-[#3b5bef] transition-colors">
<SvgIcon name="up-arrow" customCss="w-5 h-5 text-white"></SvgIcon> <SvgIcon name="up-arrow" customCss="w-5 h-5 text-white"></SvgIcon>
</button> </button>
@@ -46,12 +50,110 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue' import { onBeforeUnmount, ref } from 'vue'
interface ChatMessage {
role: 'user' | 'assistant'
content: string
}
// 输入的消息 // 输入的消息
const message = ref('') const message = ref<string>('')
// textarea引用 // textarea引用
const textareaRef = ref<HTMLElement | null>(null); const textareaRef = ref<HTMLTextAreaElement | null>(null);
// 当前 SSE 连接实例
let eventSource: EventSource | null = null
// 聊天记录 (给个默认的问候语)
const chatList = ref<ChatMessage[]>([
{ role: 'assistant', content: '我是小维智能 AI 助手!✨ 我可以帮你解答各种问题,无论是学习、工作,还是日常生活中的小困惑,都可以找我聊聊。有什么我可以帮你的吗?😊' }
])
// 发送消息
const sendMessage = async (): Promise<void> => {
// 校验发送的消息不能为空
if (!message.value.trim()) return
// 将用户发送的消息添加到 chatList 聊天列表中
const userMessage = message.value.trim()
chatList.value.push({ role: 'user', content: userMessage })
// 点击发送按钮后,清空输入框
message.value = ''
// 将输入框的高度重置
if (textareaRef.value) {
textareaRef.value.style.height = 'auto'
}
// 发送新的消息前关闭旧的 SSE 连接
closeSSE()
// 添加一个占位的回复消息
chatList.value.push({ role: 'assistant', content: '' })
const updateAssistantMessage = (content: string) => {
const lastIndex = chatList.value.length - 1
if (lastIndex < 0) return
const lastMessage = chatList.value[lastIndex]
if (lastMessage?.role !== 'assistant') return
lastMessage.content = content
}
try {
// 建立 SSE 连接
eventSource = new EventSource(`http://localhost:8080/v5/ai/generateStream?message=${encodeURIComponent(userMessage)}`)
// 响应的回答
let responseText = ''
// 处理消息事件
eventSource.onmessage = (event) => {
console.log('接收到数据: ', event.data)
if (event.data) { // 若响应数据不为空
// 持续追加流式回答
responseText += event.data;
// 更新最后一条消息
updateAssistantMessage(responseText)
}
}
// 处理错误
eventSource.onerror = (error) => {
// 通常 SSE 在完成传输后会触发一次 error 事件,这是正常的
if (error.eventPhase === EventSource.CLOSED) {
console.log('SSE正常关闭')
} else {
// 提示用户 “请求出错”
updateAssistantMessage('抱歉,请求出错了,请稍后重试。')
}
// 关闭 SSE
closeSSE()
}
} catch (error) {
console.error('发送消息错误: ', error)
// 提示用户 “请求出错”
updateAssistantMessage('抱歉,请求出错了,请稍后重试。')
closeSSE()
}
}
// 关闭 SSE 连接
const closeSSE = () => {
if (eventSource) {
eventSource.close()
eventSource = null
}
}
// 组件卸载时自动关闭连接
onBeforeUnmount(() => {
closeSSE()
})
// 自动调整文本域高度 // 自动调整文本域高度
const autoResize = () => { const autoResize = () => {