用 Vue + DeepSeek 打造一个智能聊天网站(完整前后端项目开源)

🌟 一、项目简介

最近我利用业余时间开发了一个 AI 聊天网站

前端使用 Vue 3 + Vite ,后端使用 Express 构建 API 代理,

通过 DeepSeek 提供的接口实现了一个可以像 ChatGPT 一样流畅交流的网页端聊天系统。

项目目标很简单:

  • 提供一个 前端可视化聊天界面

  • 实现 安全调用 DeepSeek API(后端隐藏密钥)

  • 支持 连续对话、上下文记忆、流式输出

  • 让任何人都能在本地快速搭建自己的智能聊天网站!

🧩 二、项目结构

项目包含前后端两个部分:

javascript 复制代码
ai-chat-vue/ # 前端 (Vite + Vue 3)
├─ index.html
├─ package.json
├─ vite.config.js
├─ src/
│ ├─ main.js
│ ├─ App.vue
│ ├─ api/
│ │ └─ ai.js
│ ├─ components/
│ │ └─ ChatBox.vue
│ └─ styles.css
└─ .gitignore


ai-server/ # 后端 (Node + Express)
├─ server.js
├─ package.json
└─ .env

🖥️ 三、前端部分(Vue 3 + Vite)

前端采用 Vue 3 + Composition API 构建,

界面简洁、响应式良好,并支持滚动对话、输入区和加载动画。

主要功能组件

  • ChatBox.vue:显示消息记录、输入框和发送按钮

  • api.js :封装与后端交互的接口(调用 /api/chat

  • 流式输出 :利用 ReadableStream 实现逐字输出效果

✨ 样例界面

  • 左侧是聊天窗口

  • 右下角输入框输入内容按回车即可发送

  • AI 响应实时滚动输出

src/api/ai.js

javascript 复制代码
import axios from 'axios'
const API_BASE = import.meta.env.VITE_API_BASE || 'http://localhost:7666'
export async function getAIReply(question) {
const res = await axios.post(`${API_BASE}/api/chat`, { question })
if (res.data && res.data.reply) return res.data.reply
throw new Error('无效的后端响应')
}

src/components/ChatBox.vue

javascript 复制代码
<template>
<div>
<div class="messages" ref="msgBox">
<div v-for="(m, i) in messages" :key="i" class="message" :class="m.role === 'user' ? 'msg-user' : 'msg-ai'">
<div><strong>{{ m.role === 'user' ? '你' : 'AI' }}:</strong></div>
<div>{{ m.content }}</div>
</div>
</div>


<textarea v-model="input" @keydown.enter.prevent="sendIfEnter($event)" placeholder="输入你想问的问题,按 Enter 发送(Shift+Enter 换行)"></textarea>
<div style="display:flex;gap:8px;justify-content:flex-end;">
<button @click="send">发送</button>
</div>
</div>
</template>


<script setup>
import { ref, nextTick } from 'vue'
import { getAIReply } from '../api/ai'


const input = ref('')
const messages = ref([])
const msgBox = ref(null)


function scrollToBottom() {
nextTick(() => {
if (msgBox.value) {
msgBox.value.scrollTop = msgBox.value.scrollHeight
}
})
}


function sendIfEnter(e) {
if (!e.shiftKey) send()
}


async function send() {
const text = input.value.trim()
if (!text) return
messages.value.push({ role: 'user', content: text })
input.value = ''
scrollToBottom()


// 显示一个占位的 AI 消息(可替换为流式)
messages.value.push({ role: 'ai', content: '正在生成回复...' })
scrollToBottom()


try {
const reply = await getAIReply(text)
// 把最后一条 ai 占位替换
const lastIdx = messages.value.map(m => m.role).lastIndexOf('ai')
if (lastIdx >= 0) messages.value[lastIdx].content = reply
} catch (err) {
const lastIdx = messages.value.map(m => m.role).lastIndexOf('ai')
if (lastIdx >= 0) messages.value[lastIdx].content = '请求失败:' + (err.message || '未知错误')
}
scrollToBottom()
}
</script>


<style scoped>
.messages { margin-bottom: 8px }
.msg-user { color: #0b72ff }
.msg-ai { color: #111 }
textarea { font-family: inherit }
button { background: #0b72ff; color: white }
</style>

src/App.vue

javascript 复制代码
<template>
<div>
<h1>AI 聊天</h1>
<div class="chat-wrap">
<ChatBox />
</div>
</div>
</template>


<script setup>
import ChatBox from './components/ChatBox.vue'
</script>


<style scoped>
h1 { margin-bottom: 12px }
</style>

src/main.js

javascript 复制代码
import { createApp } from 'vue'
import App from './App.vue'
import './styles.css'


createApp(App).mount('#app')

src/styles.css

javascript 复制代码
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial; margin: 0; padding: 20px; background: #f7f9fc; }
#app { max-width: 800px; margin: 0 auto; }
h1 { text-align: center; }
.chat-wrap { background: white; border-radius: 8px; padding: 16px; box-shadow: 0 4px 14px rgba(0,0,0,0.08); }
.messages { height: 420px; overflow-y: auto; padding: 8px; border: 1px solid #eee; border-radius: 6px; }
.message { margin: 8px 0; }
.msg-user { text-align: right; }
.msg-ai { text-align: left; }
textarea { width: 100%; min-height: 80px; margin-top: 8px; padding: 8px; }
button { margin-top: 8px; padding: 8px 14px; border: none; border-radius: 6px; cursor: pointer; }

index.html

javascript 复制代码
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>AI 聊天 (Vue + OpenAI)</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

package.json

javascript 复制代码
{"type": "module","name":"ai-chat-vue","version":"1.0.0","scripts":{"dev":"vite","build":"vite build","preview":"vite preview"},"dependencies":{"axios":"^1.5.0","vue":"^3.3.0"},"devDependencies":{"@vitejs/plugin-vue":"^6.0.1","vite":"^5.0.0"}}
  

vite.config.mjs

javascript 复制代码
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  server: {
    host: '0.0.0.0',
    port: 5173
  }
})

⚙️ 四、后端部分(Express + DeepSeek Proxy)

为了安全起见,我们不在前端直接暴露 DeepSeek 的 API Key,

而是通过 Node.js 后端中转请求。

.env

javascript 复制代码
PORT=7666
DEEPSEEK_API_KEY=这里改为你的deepseek api

server.js

javascript 复制代码
import express from 'express'
import cors from 'cors'
import axios from 'axios'
import dotenv from 'dotenv'


dotenv.config()
const app = express()
app.use(cors())
app.use(express.json())

const PORT = process.env.PORT || 7666
const DEEPSEEK_KEY = process.env.DEEPSEEK_API_KEY
if (!DEEPSEEK_KEY) console.warn('⚠️ DEEPSEEK_API_KEY 未设置,将无法调用 DeepSeek API')


app.post('/api/chat', async (req, res) => {
const { question } = req.body
if (!question) return res.status(400).json({ error: 'missing question' })


try {
const resp = await axios.post(
      'https://api.deepseek.com/v1/chat/completions',
      {
        model: 'deepseek-chat', // 也可以换成 deepseek-reasoner
messages: [
{ role: 'system', content: '你是一个友好的助理。用中文回复。' },
{ role: 'user', content: question }
],
max_tokens: 800
},
{
headers: {
'Authorization': `Bearer ${DEEPSEEK_KEY}`,
'Content-Type': 'application/json'
}
}
)


const reply = resp.data.choices?.[0]?.message?.content || ''
res.json({ reply })
} catch (err) {
console.error(err?.response?.data || err.message)
res.status(500).json({ reply: '调用出错,请检查后端日志。' })
}
})


app.listen(PORT, () => console.log(`✅ Server listening on http://localhost:${PORT}`))

package.json

javascript 复制代码
{
  "name": "ai-server",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "axios": "^1.5.0",
    "cors": "^2.8.5",
    "dotenv": "^16.0.0",
    "express": "^4.18.2"
  }
}

🔐 五、安全设计

  1. 后端代理调用 DeepSeek,防止 API Key 暴露。

  2. CORS 控制:仅允许特定前端域名访问。

  3. 环境变量配置 :所有密钥都放在 .env 文件中,项目安全性更高。


🌈 六、项目运行效果

当用户输入问题时,例如:

"请帮我写一段介绍 Vue 的开场白"

系统会流式输出 DeepSeek 的回答,

在几秒钟内完成自然语言回复。

🧠 七、技术要点与难点

功能 技术实现
前端聊天界面 Vue 3 + Tailwind CSS
实时响应 ReadableStream 流式读取
API 代理 Node.js + Express
安全性 .env 隐藏密钥,CORS 限制
模型调用 DeepSeek Chat Completion API

🚀 八、部署方式

1️⃣ 本地运行

复制代码
# 前端

cd ai-chat-vue

npm install

npm run dev



# 后端 (另开终端)

cd ai-server

npm install

# 填写 .env 中的 DEEPSEEK_API_KEY

node server.js

访问前端页面(默认 http://localhost:5173)开始聊天。

2️⃣ 部署到线上

  • 后端:Render / Vercel / Railway / 自建服务器

  • 前端:Netlify / Vercel / GitHub Pages

💬 九、项目亮点总结

前后端完全开源

DeepSeek API 集成示例

流式聊天效果

安全 API Key 管理机制

适合二次开发、博客展示或课程作业

🔗 十、项目仓库地址

GitHub 地址:

👉 13536309143/Build-an-intelligent-chat-website-with-Vue-DeepSeek


❤️ 十一、结语

这是一个轻量、易扩展的 AI 聊天网站项目,

既能展示前后端交互能力,也能体验 DeepSeek 的强大对话性能。

如果你正在学习:

  • Vue 3 前端开发

  • Node.js 后端接口代理

  • AI 聊天网站架构

那么这个项目非常适合作为你的入门实战!

相关推荐
zhangyao9403303 小时前
关于js导入Excel时,Excel的(年/月/日)日期是五位数字的问题。以及对Excel日期存在的错误的分析和处理。
开发语言·javascript·excel
骑驴看星星a3 小时前
【Three.js--manual script】4.光照
android·开发语言·javascript
devincob9 小时前
js原生、vue导出、react导出、axios ( post请求方式)跨平台导出下载四种方式的demo
javascript·vue.js·react.js
编程社区管理员9 小时前
React 发送短信验证码和验证码校验功能组件
前端·javascript·react.js
葡萄城技术团队9 小时前
迎接下一代 React 框架:Next.js 16 核心能力解读
javascript·spring·react.js
全马必破三9 小时前
React“组件即函数”
前端·javascript·react.js
三思而后行,慎承诺9 小时前
React 底层原理
前端·react.js·前端框架
座山雕~9 小时前
html 和css基础常用的标签和样式
前端·css·html
課代表9 小时前
JavaScript 中获取二维数组最大值
javascript·max·数组·递归·array·最大值·二维