基于 Vue3 + TypeScript + Element Plus 实现 DeepSeek AI 对话界面(流式输出)

内容分享2周前发布
0 0 0

📖 前言

最近在开发一个后台管理系统时,需要集成 AI 对话功能。经过调研,选择了 DeepSeek API 作为后端服务,使用 Vue3 + TypeScript + Element Plus 实现了一个功能完善的对话界面。本文将详细介绍实现过程,包括流式输出、思考模式、对话历史管理等核心功能。

🎯 项目概述

本项目实现了一个完整的 DeepSeek AI 对话界面,支持:

✅ 流式回答(逐字显示)✅ 思考模式切换✅ 对话历史管理✅ 用户信息展示✅ 账户余额查询✅ 模型切换✅ 美观的 UI 界面

🛠️ 技术栈

前端框架: Vue 3.5.13 (Composition API)类型系统: TypeScript 5.8.3UI 组件库: Element Plus 2.11.9HTTP 客户端: Axios 1.13.2AI SDK: OpenAI SDK 6.10.0 (兼容 DeepSeek API)构建工具: Vite 6.3.5样式预处理: Less 4.3.0

📦 项目结构


src/views/index/
├── index.vue      # 主组件(UI 界面)
├── index.ts       # 业务逻辑(API 调用、对话管理)
└── index.scss     # 样式文件

🚀 核心功能实现

1. 流式回答实现

流式回答是核心功能之一,让 AI 的回答能够逐字显示,提升用户体验。

1.1 API 调用层(index.ts)

// 聊天 - 支持流式和思考模式
export async function main(
  userMessage?: string, 
  model: string = "deepseek-chat", 
  options?: {
    stream?: boolean;           // 是否流式输出
    thinkingMode?: boolean;     // 是否思考模式
    onStreamChunk?: (chunk: string) => void;  // 流式数据回调
  }
) {
  try {
    // 如果提供了用户消息,添加到历史
    if (userMessage) {
      addMessageToHistory({ role: "user", content: userMessage });
    }

    // 构建消息数组,包含系统提示和对话历史
    const conversation = conversations.find((c) => c.id === currentConversationId);
    const historyMessages = conversation?.messages || [];
    const messages: Message[] = [
      { role: "system", content: "You are a helpful assistant." },
      ...historyMessages,
    ];

    // 流式模式
    if (options?.stream) {
      const stream = await openai.chat.completions.create({
        messages: messages as any,
        model: model,
        stream: true,
      });

      let fullContent = "";

      for await (const chunk of stream) {
        const content = chunk.choices[0]?.delta?.content || "";
        if (content) {
          fullContent += content;
          // 调用回调函数,实时更新UI
          options?.onStreamChunk?.(fullContent);
        }
      }

      // 将完整回复添加到历史
      addMessageToHistory({ role: "assistant", content: fullContent });
      return fullContent;
    }
    // 非流式模式...
  } catch (error: any) {
    // 错误处理...
  }
}

关键点

使用
stream: true
启用流式输出通过
for await...of
遍历流数据使用回调函数
onStreamChunk
实时更新 UI
chunk.choices[0]?.delta?.content
获取增量内容

1.2 UI 层实现(index.vue)

<script setup lang="ts">
// 发送消息 - 流式处理
const handleSend = async () => {
  if (!inputMessage.value.trim() || isLoading.value) return;

  const userMsg = inputMessage.value.trim();
  inputMessage.value = "";

  // 添加用户消息到界面
  messages.value.push({ role: "user", content: userMsg });

  // 添加一个空的助手消息,用于流式更新
  const assistantMessageIndex = messages.value.length;
  messages.value.push({
    role: "assistant",
    content: "",
  });
  scrollToBottom();

  isLoading.value = true;
  streamingMessage.value = "";
  
  try {
    await main(userMsg, selectedModel.value, {
      stream: true,
      thinkingMode: thinkingMode.value,
      onStreamChunk: (chunk) => {
        // chunk 已经是完整的累积内容,直接赋值
        streamingMessage.value = chunk;
        messages.value[assistantMessageIndex].content = chunk;
        scrollToBottom();
      },
    });
  } catch (error) {
    console.error("发送消息失败:", error);
    messages.value.pop();
  } finally {
    isLoading.value = false;
    streamingMessage.value = "";
    scrollToBottom();
  }
};
</script>

关键点

先创建空的助手消息,用于流式更新
chunk
参数是完整的累积内容,直接赋值(不要累加)实时更新消息内容并自动滚动

2. 思考模式实现

思考模式允许用户切换 AI 的思考方式,通过开关控制。


<template>
  <div class="header-right">
    <!-- 思考模式开关 -->
    <el-switch
      v-model="thinkingMode"
      active-text="思考模式"
      inactive-text="普通模式"
      class="thinking-switch"
    />
  </div>
</template>

<script setup lang="ts">
const thinkingMode = ref(false); // 思考模式状态
</script>

3. 对话历史管理

实现了多对话管理,支持创建、切换、删除对话。


// 对话历史管理
interface Conversation {
  id: string;
  title: string;
  messages: Message[];
  createdAt: number;
  updatedAt: number;
}

let conversations: Conversation[] = [];
let currentConversationId: string | null = null;

// 创建新对话
export function createNewConversation(): string {
  const id = `conv_${Date.now()}`;
  const newConversation: Conversation = {
    id,
    title: "新对话",
    messages: [],
    createdAt: Date.now(),
    updatedAt: Date.now(),
  };
  conversations.unshift(newConversation);
  currentConversationId = id;
  return id;
}

// 切换到指定对话
export function switchConversation(conversationId: string) {
  currentConversationId = conversationId;
  const conversation = conversations.find((c) => c.id === conversationId);
  return conversation?.messages || [];
}

4. 用户信息展示

在侧边栏展示用户头像、姓名和账户余额。


<template>
  <div class="user-info-card">
    <el-avatar :size="50" :src="userInfo.accountBalance.avatar">{ userInfo.accountBalance.name || "用户" }}</div>
      <div class="user-total-balance" v-if="userInfo.accountBalance.total_balance !== undefined">
        <span>总额: ¥{{ formatBalance(userInfo.accountBalance.total_balance) }}</span>
      </div>
    </div>
  </div>
</template>

5. 键盘快捷键

实现了便捷的键盘操作:

Enter: 发送消息Shift + Enter: 换行Ctrl + Enter / Cmd + Enter: 发送消息


// 处理回车键
const handleEnterKey = (event: Event) => {
  const keyboardEvent = event as KeyboardEvent;
  // 如果按了 Shift+Enter,允许换行(默认行为)
  if (keyboardEvent.shiftKey) {
    return;
  }
  // 如果按了 Ctrl+Enter 或 Cmd+Enter,发送消息
  if (keyboardEvent.ctrlKey || keyboardEvent.metaKey) {
    handleSend();
    return;
  }
  // 单独按 Enter,发送消息并阻止默认换行
  keyboardEvent.preventDefault();
  handleSend();
};

🎨 UI 设计亮点

1. 左侧可折叠侧边栏

支持折叠/展开,节省空间显示用户信息和对话历史流畅的动画过渡

2. 消息气泡设计

用户消息:右侧显示,渐变紫色背景AI 消息:左侧显示,白色背景加载状态:在消息气泡内显示”正在思考…”

3. 响应式布局

适配不同屏幕尺寸优雅的滚动条样式流畅的交互体验

📸 效果展示

图片位置 1:整体界面效果

基于 Vue3 + TypeScript + Element Plus 实现 DeepSeek AI 对话界面(流式输出)

图片位置 2:流式回答效果

基于 Vue3 + TypeScript + Element Plus 实现 DeepSeek AI 对话界面(流式输出)

图片位置 3:思考模式切换

基于 Vue3 + TypeScript + Element Plus 实现 DeepSeek AI 对话界面(流式输出)

图片位置 4:对话历史管理

基于 Vue3 + TypeScript + Element Plus 实现 DeepSeek AI 对话界面(流式输出)

图片位置 5:用户信息卡片

基于 Vue3 + TypeScript + Element Plus 实现 DeepSeek AI 对话界面(流式输出)

📦 环境要求与安装

环境要求

Node.js: >= 16.0.0npm: >= 7.0.0 或 pnpm: >= 7.0.0TypeScript: >= 5.0.0

完整依赖包列表

核心依赖包


@element-plus/icons-vue
: ^2.3.2 – Element Plus 图标库
axios
: ^1.13.2 – HTTP 请求库
element-plus
: ^2.11.9 – UI 组件库
openai
: ^6.10.0 – OpenAI SDK(兼容 DeepSeek API)
vue
: ^3.5.13 – Vue 3 框架
less
: ^4.3.0 – Less 预处理器
less-loader
: ^12.3.0 – Less 加载器

开发依赖包


@vitejs/plugin-vue
: ^5.2.3 – Vite Vue 插件
@vue/tsconfig
: ^0.7.0 – Vue TypeScript 配置
typescript
: ~5.8.3 – TypeScript 编译器
vite
: ^6.3.5 – 构建工具
vue-tsc
: ^2.2.8 – Vue TypeScript 类型检查

安装步骤

方式一:使用 npm

# 1. 创建项目(如果还没有)
npm create vite@latest my-deepseek-chat -- --template vue-ts

# 2. 进入项目目录
cd my-deepseek-chat

# 3. 安装所有依赖
npm install

# 4. 安装核心依赖包
npm install openai axios element-plus @element-plus/icons-vue less less-loader

# 5. 安装开发依赖(如果还没有)
npm install -D @vitejs/plugin-vue typescript vue-tsc vite
方式二:使用 pnpm(推荐)

# 1. 创建项目
pnpm create vite my-deepseek-chat --template vue-ts

# 2. 进入项目目录
cd my-deepseek-chat

# 3. 安装所有依赖
pnpm install

# 4. 安装核心依赖包
pnpm add openai axios element-plus @element-plus/icons-vue less less-loader

# 5. 安装开发依赖
pnpm add -D @vitejs/plugin-vue typescript vue-tsc vite
方式三:使用 yarn

# 1. 创建项目
yarn create vite my-deepseek-chat --template vue-ts

# 2. 进入项目目录
cd my-deepseek-chat

# 3. 安装所有依赖
yarn install

# 4. 安装核心依赖包
yarn add openai axios element-plus @element-plus/icons-vue less less-loader

# 5. 安装开发依赖
yarn add -D @vitejs/plugin-vue typescript vue-tsc vite

完整 package.json 配置示例


{
  "name": "deepseek-chat",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite --open",
    "build": "vue-tsc -b && vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "@element-plus/icons-vue": "^2.3.2",
    "axios": "^1.13.2",
    "element-plus": "^2.11.9",
    "openai": "^6.10.0",
    "vue": "^3.5.13",
    "less": "^4.3.0",
    "less-loader": "^12.3.0"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^5.2.3",
    "@vue/tsconfig": "^0.7.0",
    "typescript": "~5.8.3",
    "vite": "^6.3.5",
    "vue-tsc": "^2.2.8"
  }
}

提示:可以直接复制上面的配置到你的
package.json
文件中,然后运行
npm install

pnpm install
安装所有依赖。

启动项目

安装完成后,运行以下命令启动开发服务器:


# npm
npm run dev

# pnpm
pnpm dev

# yarn
yarn dev

项目将在
http://localhost:5173
启动(端口可能不同,请查看终端输出)。

🔧 配置说明

DeepSeek API 配置


src/views/index/index.ts
文件中配置你的 DeepSeek API Key:


const openaiProps: openaiProps = {
  baseURL: "https://api.deepseek.com",
  apiKey: "***",  // 替换为你的 API Key
  dangerouslyAllowBrowser: true,  // 允许在浏览器中使用
  stream: true,
};

⚠️ 安全提示:在生产环境中,建议将 API Key 放在后端,通过代理调用 API,避免在前端暴露密钥。

Element Plus 全局配置


src/main.ts
中引入 Element Plus:


import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import App from './App.vue'

const app = createApp(App)

// 注册 Element Plus
app.use(ElementPlus)

// 注册所有图标
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
  app.component(key, component)
}

app.mount('#app')

Vite 配置(vite.config.ts)

确保配置了 Vue 插件和 Less 支持:


import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  css: {
    preprocessorOptions: {
      less: {
        javascriptEnabled: true,
      },
    },
  },
})

🐛 常见问题

1. 流式回答重复显示

问题:流式回答时内容重复显示

解决:确保在回调函数中直接赋值,不要累加:


onStreamChunk: (chunk) => {
  // ✅ 正确:直接赋值
  messages.value[index].content = chunk;
  
  // ❌ 错误:不要累加
  // messages.value[index].content += chunk;
}

2. 余额不足错误

问题:API 返回 402 错误

解决:检查账户余额,前往 DeepSeek 官网充值。

3. API 密钥无效

问题:API 返回 401 错误

解决:检查 API Key 是否正确,确保有访问权限。

📝 核心代码文件

index.ts – API 调用和对话管理

主要功能:

DeepSeek API 配置流式对话实现对话历史管理错误处理账户余额查询模型列表获取

index.vue – UI 组件

主要功能:

界面布局消息展示用户交互状态管理

index.scss – 样式文件

主要功能:

响应式布局动画效果主题样式

🎯 功能特性总结

功能 状态 说明
流式回答 逐字显示 AI 回答
思考模式 可切换思考模式
对话历史 多对话管理
用户信息 头像、姓名、余额
模型切换 支持切换不同模型
键盘快捷键 Enter 发送,Shift+Enter 换行
错误处理 完善的错误提示
响应式设计 适配不同屏幕

🚀 未来优化方向

后端代理:将 API 调用移到后端,提高安全性消息持久化:使用 IndexedDB 或后端存储对话历史Markdown 渲染:支持 Markdown 格式的消息显示代码高亮:代码块语法高亮文件上传:支持图片、文件上传语音输入:集成语音识别功能

📚 参考资源

DeepSeek API 文档OpenAI SDK 文档Vue 3 官方文档Element Plus 文档

💡 总结

本文详细介绍了一个基于 Vue3 + TypeScript + Element Plus 的 DeepSeek AI 对话界面实现。核心功能包括流式回答、思考模式、对话历史管理等。通过合理的架构设计和代码组织,实现了一个功能完善、用户体验良好的对话界面。

关键实现点

使用 OpenAI SDK 的流式 API 实现逐字显示通过回调函数实时更新 UI完善的错误处理和用户提示优雅的 UI 设计和交互体验

希望本文对正在开发类似功能的开发者有所帮助!如有问题,欢迎在评论区交流讨论。

© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
none
暂无评论...