S2-Pro前端集成示例在Vue项目中构建实时AI聊天界面1. 引言为什么选择Vue集成AI聊天功能最近在开发一个知识管理工具时需要为产品添加智能问答功能。经过技术选型我们最终决定使用Vue 3配合S2-Pro的API来实现这个需求。Vue的响应式特性和Composition API让这类实时交互功能的开发变得异常简单。S2-Pro提供的流式对话接口特别适合构建聊天类应用。相比传统的一次性返回完整响应流式传输能让用户看到消息逐步生成的过程体验更接近真人对话。本文将手把手带你实现一个完整的AI聊天界面包含打字机效果、Markdown渲染等实用功能。2. 项目准备与环境配置2.1 创建Vue 3项目如果你还没有现成的Vue项目可以使用Vite快速初始化一个npm create vitelatest vue-ai-chat --template vue-ts cd vue-ai-chat npm install2.2 安装必要依赖我们需要安装axios用于API调用以及markdown-it来处理返回的Markdown格式内容npm install axios markdown-it2.3 获取S2-Pro API凭证确保你已经拥有可用的S2-Pro API密钥。如果还没有可以参考官方文档申请。我们将把API密钥存储在环境变量中# .env VITE_API_KEYyour_api_key_here VITE_API_BASE_URLhttps://api.s2-pro.example.com3. 核心功能实现3.1 初始化聊天服务模块首先创建一个src/services/chat.ts文件封装与S2-Pro API的交互逻辑import axios from axios import md from markdown-it() const api axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL, headers: { Authorization: Bearer ${import.meta.env.VITE_API_KEY}, Content-Type: application/json } }) export interface Message { role: user | assistant content: string } export const chatStream async (messages: Message[], onData: (chunk: string) void) { try { const response await api.post(/chat/completions, { messages, stream: true }, { responseType: stream }) const reader response.data.getReader() const decoder new TextDecoder() let result while (true) { const { done, value } await reader.read() if (done) break const chunk decoder.decode(value) result chunk onData(chunk) } return result } catch (error) { console.error(Chat error:, error) throw error } } export const renderMarkdown (content: string) { return md.render(content) }3.2 构建聊天组件接下来创建src/components/ChatWindow.vue组件script setup langts import { ref, reactive } from vue import { chatStream, renderMarkdown, type Message } from ../services/chat const messages reactiveMessage[]([ { role: assistant, content: 你好我是AI助手有什么可以帮你的吗 } ]) const userInput ref() const isLoading ref(false) const error refstring | null(null) const sendMessage async () { if (!userInput.value.trim() || isLoading.value) return const userMessage: Message { role: user, content: userInput.value } messages.push(userMessage) userInput.value isLoading.value true error.value null let assistantMessage try { await chatStream( [...messages], (chunk) { assistantMessage chunk // 更新最后一条消息内容 if (messages[messages.length - 1].role assistant) { messages[messages.length - 1].content assistantMessage } else { messages.push({ role: assistant, content: assistantMessage }) } } ) // 最终渲染Markdown messages[messages.length - 1].content renderMarkdown(assistantMessage) } catch (err) { error.value 对话过程中出现错误请稍后再试 console.error(err) } finally { isLoading.value false } } /script template div classchat-container div classmessages div v-for(message, index) in messages :keyindex :class[message, message.role] div classmessage-content v-htmlmessage.content/div /div div v-ifisLoading classmessage assistant div classtyping-indicator.../div /div /div div classinput-area input v-modeluserInput keyup.entersendMessage placeholder输入你的问题... :disabledisLoading / button clicksendMessage :disabledisLoading {{ isLoading ? 发送中... : 发送 }} /button /div div v-iferror classerror-message {{ error }} /div /div /template style scoped .chat-container { max-width: 800px; margin: 0 auto; border: 1px solid #ddd; border-radius: 8px; overflow: hidden; } .messages { height: 500px; overflow-y: auto; padding: 16px; background: #f9f9f9; } .message { margin-bottom: 12px; max-width: 80%; } .message.user { margin-left: auto; background: #007bff; color: white; padding: 8px 12px; border-radius: 12px 12px 0 12px; } .message.assistant { margin-right: auto; background: white; padding: 8px 12px; border-radius: 12px 12px 12px 0; box-shadow: 0 1px 2px rgba(0,0,0,0.1); } .input-area { display: flex; padding: 12px; background: white; border-top: 1px solid #eee; } .input-area input { flex: 1; padding: 8px 12px; border: 1px solid #ddd; border-radius: 4px; margin-right: 8px; } .error-message { color: #dc3545; padding: 8px; text-align: center; } .typing-indicator { display: inline-block; animation: typing 1.5s infinite; } keyframes typing { 0% { opacity: 0.3; } 50% { opacity: 1; } 100% { opacity: 0.3; } } /style4. 功能优化与扩展4.1 添加打字机动画效果为了让消息显示更加自然我们可以改进消息渲染方式实现逐字显示效果。修改ChatWindow.vue中的相关部分// 在setup()中添加 const displayedMessages reactive{role: user | assistant; content: string}[]([]) watch(messages, (newMessages) { if (newMessages.length displayedMessages.length) { const lastMessage newMessages[newMessages.length - 1] if (lastMessage.role assistant) { typeMessage(lastMessage.content) } else { displayedMessages.push({...lastMessage}) } } }, { deep: true }) const typeMessage (content: string) { const index displayedMessages.length displayedMessages.push({ role: assistant, content: }) let i 0 const typingInterval setInterval(() { if (i content.length) { displayedMessages[index].content content.substring(0, i 1) i } else { clearInterval(typingInterval) } }, 20) }4.2 添加对话历史管理我们可以使用Pinia来管理全局的对话状态。首先安装Pinianpm install pinia然后创建src/stores/chat.tsimport { defineStore } from pinia import { type Message } from ../services/chat export const useChatStore defineStore(chat, { state: () ({ conversations: [] as { id: string title: string messages: Message[] }[], currentConversationId: null as string | null }), getters: { currentConversation(state) { return state.conversations.find(c c.id state.currentConversationId) } }, actions: { newConversation() { const id Date.now().toString() this.conversations.push({ id, title: 新对话, messages: [] }) this.currentConversationId id return id }, setConversationTitle(id: string, title: string) { const conv this.conversations.find(c c.id id) if (conv) conv.title title }, addMessage(message: Message) { const conv this.conversations.find(c c.id this.currentConversationId) if (conv) conv.messages.push(message) } } })5. 总结与后续优化建议实现下来Vue 3的Composition API配合S2-Pro的流式API确实能构建出非常流畅的聊天体验。整个开发过程中最让人惊喜的是Vue的响应式系统它能自动处理UI更新让我们可以专注于业务逻辑。这套方案已经能满足基本需求但还有几个可以优化的方向首先是性能方面当对话历史很长时可以考虑实现分页加载其次是用户体验可以添加对话暂停/继续功能最后是功能扩展比如支持文件上传和解析等高级特性。实际部署时建议添加API调用频率限制和错误重试机制确保在网络不稳定时仍能提供良好的用户体验。如果你需要更复杂的功能比如多轮对话管理或知识库检索S2-Pro的API也提供了相应的接口支持。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。