前端使用 fetch API 处理 SSE 流式响应

<template>
  <div class="chat-container">
    <div class="messages" ref="messagesRef">
      <div v-for="msg in messages" :key="msg.id" :class="['message', msg.role]">
        {{ msg.content }}
      </div>
    </div>
    <div class="input-area">
      <input v-model="input" @keyup.enter="sendMessage" placeholder="输入消息..." />
      <button @click="sendMessage" :disabled="loading">发送</button>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const messages = ref([])
const input = ref('')
const loading = ref(false)

async function sendMessage() {
    if (!input.value.trim() || loading.value) return
    
    const userMessage = input.value
    messages.value.push({ id: Date.now(), role: 'user', content: userMessage })
    input.value = ''
    loading.value = true
    
    // 添加 AI 消息占位
    const aiMessage = { id: Date.now() + 1, role: 'assistant', content: '' }
    messages.value.push(aiMessage)
    
    try {
        const response = await fetch('/api/ai/chat/stream', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ message: userMessage })
        })
        
        const reader = response.body.getReader()
        const decoder = new TextDecoder()
        
        while (true) {
            const { done, value } = await reader.read()
            if (done) break
            
            const text = decoder.decode(value)
            if (text === '[DONE]') break
            
            aiMessage.content += text
        }
    } finally {
        loading.value = false
    }
}
</script>

 

posted @ 2025-12-30 15:36  热心市民~菜先生  阅读(3)  评论(0)    收藏  举报