【AI大模型】DeepSeek + Nodejs 实现AI对话,打造强大聊天工具

最终效果

AI聊天展示效果

项目目录结构

chatgpt-web-service/
├── client/                # 前端页面
│   └── index.html
├── server/                # Node.js 后端
│   ├── app.js
│   ├── routes/chat.js
│   ├── controllers/chatController.js
│   ├── services/openaiService.js
│   ├── db/
│   │   ├── chat.db
│   │   └── init.js
├── .env
├── package.json
└── README.md

开发环境

系统: Window10
nvm: 1.1.2 (切换node 版本)
node: v18.20.4
yarn: 1.22.22
vsCode 插件:SQLite Viewer (查看sqlite数据)

依赖版本

better-sqlite3: ^11.9.1 (嵌入式存储,保存对话历史)
cors: ^2.8.5
dotenv: ^16.5.0
express: ^5.1.0
node-fetch: ^3.3.2
openai: ^4.95.1
uuid: ^11.1.0

一、初始化项目和安装依赖

mkdir chatgpt-web-service && cd chatgpt-web-service
npm init -y
npm install express openai dotenv sqlite3 cors uuid

二、本地配置文件 .env

openai-key 去官网申请,openai 有代理限制。建议申请 deepseek api ,最下方有api-key申请地址

OPENAI_API_KEY=sk-xxx-your-openai-key
PORT=3000

三、SQLite 初始化脚本 server/db/init.js

const sqlite3 = require('sqlite3').verbose();
const db = new sqlite3.Database('./server/db/chat.db');

db.serialize(() => {
  db.run(`CREATE TABLE IF NOT EXISTS messages (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    session_id TEXT,
    role TEXT,
    content TEXT,
    timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
  )`);
});

db.close();

运行一次:

node server/db/init.js

四、OpenAI 封装 server/services/openaiService.js

const { Configuration, OpenAIApi } = require('openai');

const configuration = new Configuration({
  apiKey: process.env.OPENAI_API_KEY,
});

const openai = new OpenAIApi(configuration);

async function getChatResponse(messages) {
  const res = await openai.createChatCompletion({
    model: 'gpt-3.5-turbo',
    messages,
  });
  return res.data.choices[0].message.content;
}

module.exports = { getChatResponse };

五、Controller 逻辑 server/controllers/chatController.js

const sqlite3 = require('sqlite3').verbose();
const db = new sqlite3.Database('./server/db/chat.db');
const { getChatResponse } = require('../services/openaiService');

const chatWithGPT = async (req, res) => {
  const { message, session_id } = req.body;

  if (!message || !session_id) {
    return res.status(400).json({ error: 'message and session_id are required' });
  }

  // 获取最近的上下文记录
  db.all(
    `SELECT role, content FROM messages WHERE session_id = ? ORDER BY timestamp DESC LIMIT 6`,
    [session_id],
    async (err, rows) => {
      if (err) return res.status(500).json({ error: err.message });

      const context = rows.reverse(); // 旧的在前
      context.push({ role: 'user', content: message });

      try {
        const reply = await getChatResponse(context);

        // 存入数据库
        const stmt = db.prepare(`INSERT INTO messages (session_id, role, content) VALUES (?, ?, ?)`);
        stmt.run(session_id, 'user', message);
        stmt.run(session_id, 'assistant', reply);
        stmt.finalize();

        res.json({ reply });
      } catch (error) {
        res.status(500).json({ error: error.message });
      }
    }
  );
};

module.exports = { chatWithGPT };

七、路由文件 server/routes/chat.js

const express = require('express');
const router = express.Router();
const { chatWithGPT } = require('../controllers/chatController');

router.post('/', chatWithGPT);

module.exports = router;

八、启动服务器 server/app.js

const express = require('express');
const dotenv = require('dotenv');
const cors = require('cors');
const path = require('path');

dotenv.config();
const app = express();
const port = process.env.PORT || 3000;

app.use(cors());
app.use(express.json());
app.use(express.static(path.join(__dirname, '../client'))); // 静态前端页面

const chatRoutes = require('./routes/chat');
app.use('/api/chat', chatRoutes);

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});

九、前端页面 client/index.html

用于验证是否有效

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>ChatGPT 多轮对话</title>
  <style>
    body { font-family: sans-serif; padding: 20px; }
    #chat { border: 1px solid #ccc; padding: 10px; max-width: 600px; height: 400px; overflow-y: auto; }
    .msg { margin: 8px 0; }
    .user { color: blue; }
    .ai { color: green; }
  </style>
</head>
<body>
  <h2>ChatGPT 多轮对话演示</h2>
  <div id="chat"></div>
  <input id="input" type="text" placeholder="输入问题..." style="width: 400px;" />
  <button onclick="send()">发送</button>

  <script>
    const session_id = localStorage.getItem('session_id') || (crypto.randomUUID());
    localStorage.setItem('session_id', session_id);

    async function send() {
      const input = document.getElementById('input');
      const message = input.value.trim();
      if (!message) return;

      appendMessage('user', message);
      input.value = '';

      const res = await fetch('/api/chat', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ message, session_id })
      });

      const data = await res.json();
      appendMessage('ai', data.reply);
    }

    function appendMessage(role, content) {
      const chat = document.getElementById('chat');
      const div = document.createElement('div');
      div.className = 'msg ' + role;
      div.textContent = `${role === 'user' ? '你' : 'AI'}${content}`;
      chat.appendChild(div);
      chat.scrollTop = chat.scrollHeight;
    }
  </script>
</body>
</html>

十、启动项目

  1. 运行 SQLite 初始化(只需一次):

    node server/db/init.js
    
  2. 启动服务:

    node server/app.js
    
  3. 打开浏览器访问:

    http://localhost:3000
    

十一、资源分享

  1. DeepSeek API 文档
  2. DeepSeep API Key 申请
  3. 模拟微信聊天的多轮对话
<think>好的,我现在需要帮助用户解决如何在Node.js中通过DeepSeek大模型实现流式响应的智能聊天应用的问题。首先,我得理清楚用户的需求。用户提到了流式响应,这意味着需要处理数据的分块传输,而不是等待整个响应完成后再返回给客户端。这通常涉及使用服务器发送的事件(SSE)或者WebSocket,但根据引用内容,可能更倾向于使用API的流式响应功能。 接下来,我需要查看用户提供的引用内容,特别是引用[1]、[2]、[4]和[5],因为它们直接相关于Node.js调用DeepSeek API。引用[1]提到一个命令行聊天应用实现了流式响应和对话记录保存,引用[2]则强调Node.js的异步特性和错误处理,引用[4]提供了多语言的开发流程,而引用[5]涉及本地运行DeepSeek模型。不过用户的需求是调用DeepSeek的API,而不是本地运行,所以重点可能在前几个引用。 首先,用户需要知道如何调用DeepSeek的API,并且处理流式响应。根据引用[1]和[2],可能需要使用HTTP客户端库,如axios或node-fetch,并处理流式数据。引用[2]提到异步编程,所以可能需要使用async/await或者Promise来处理异步请求。此外,流式响应可能需要监听数据事件,逐步接收数据块。 接下来,我需要考虑代码结构。根据示例中的Python代码,可能需要在Node.js中设置一个函数,发送POST请求到DeepSeek的API端点,并处理返回的数据流。引用[1]中的示例可能用到了流式处理,例如使用fetch的响应体作为可读流,逐块读取数据。 然后,用户可能需要设置请求头,包含认证信息,比如API密钥。引用[1]和[2]都提到了API密钥的必要性,所以在代码中需要从环境变量中获取,避免硬编码。 另外,流式响应的处理可能需要将接收到的数据块拼接起来,并实时输出到控制台或其他前端界面。例如,在命令行应用中,每次收到数据块就打印出来,而不是等待整个响应完成。引用[5]提到了使用Ollama本地运行模型,但用户需要的是调用API,所以可以忽略这部分,但可能参考其流式处理的方法。 可能还需要处理对话历史,以保持上下文。引用[1]提到对话记录的自动保存,所以需要在代码中维护一个消息数组,每次请求时包含之前的对话历史。 错误处理也是关键,引用[2]提到完善的错误处理机制,所以在代码中需要捕获网络错误、API返回的错误状态码等,并进行相应处理。 最后,用户可能需要将实现封装成模块,方便维护和扩展,如引用[2]提到的代码结构清晰,易于维护。可能需要创建一个类,封装API调用、流式处理、对话历史管理等功能。 总结步骤应该是:安装依赖、配置环境变量、创建API请求函数、处理流式响应、维护对话历史、实现实时输出、错误处理。同时,根据引用内容,可能需要参考硅基流动(SiliconFlow)的API文档,确保请求参数正确,如model版本、messages结构等。 可能遇到的问题包括流式数据的正确解析,例如API返回的数据可能是JSON格式的块,或者是纯文本,需要根据实际情况处理。例如,某些API可能返回多个JSON对象,每个对象包含部分响应,需要逐个解析并提取内容部分。 测试时,可以使用示例代码发送请求,观察是否能实时接收到数据块,并确保对话历史正确更新。此外,需要处理网络中断或API限制的情况,添加重试机制或适当的用户提示。 最后,确保代码符合最佳实践,如使用环境变量管理敏感信息,模块化代码结构,添加注释以提高可读性,并处理可能的异常情况,如无效的API密钥或网络错误。</think>以下是基于Node.js实现DeepSeek流式聊天应用的完整解决方案: ### 一、环境准备 1. 安装必要依赖 ```bash npm install axios dotenv ``` 2. 创建`.env`文件存储API密钥 ```env DEEPSEEK_API_KEY=your_api_key_here DEEPSEEK_API_URL=https://api.siliconflow.cn/v1/chat/completions ``` ### 二、核心实现代码 ```javascript require('dotenv').config(); const axios = require('axios'); class DeepSeekChat { constructor() { this.history = []; this.config = { headers: { 'Authorization': `Bearer ${process.env.DEEPSEEK_API_KEY}`, 'Content-Type': 'application/json', 'Accept': 'text/event-stream' }, responseType: 'stream' }; } async streamChat(prompt) { try { this.history.push({ role: 'user', content: prompt }); const requestBody = { model: 'deepseek-chat', messages: this.history, stream: true, temperature: 0.7 }; const response = await axios.post( process.env.DEEPSEEK_API_URL, requestBody, this.config ); let fullResponse = ''; const stream = response.data; return new Promise((resolve, reject) => { stream.on('data', chunk => { const lines = chunk.toString().split('\n').filter(line => line.trim()); for (const line of lines) { if (line.startsWith('data: ')) { const data = line.replace('data: ', ''); if (data === '[DONE]') break; try { const json = JSON.parse(data); const content = json.choices[0].delta.content || ''; process.stdout.write(content); fullResponse += content; } catch (err) { console.error('解析错误:', err); } } } }); stream.on('end', () => { this.history.push({ role: 'assistant', content: fullResponse }); resolve(fullResponse); }); stream.on('error', err => reject(err)); }); } catch (error) { console.error('API请求失败:', error.response?.data || error.message); throw error; } } } ``` ### 三、使用示例 ```javascript const chat = new DeepSeekChat(); // 命令行交互示例 const readline = require('readline').createInterface({ input: process.stdin, output: process.stdout }); async function chatLoop() { while (true) { const input = await new Promise(resolve => readline.question('\n用户: ', resolve) ); if (input.toLowerCase() === 'exit') break; try { process.stdout.write('助手: '); await chat.streamChat(input); } catch (err) { console.error('对话异常:', err); } } readline.close(); } chatLoop(); ``` ### 四、关键特性解析 1. **流式响应处理** 使用`responseType: 'stream'`配置接收数据流,通过事件监听器实时处理分块数据。这种方式相比传统响应方式可降低首字节时间(TTFB)[^2]。 2. **对话历史管理** 采用`history`数组维护上下文对话,每次请求携带完整对话记录实现连续对话能力。研究显示上下文长度直接影响模型响应质量[^4]。 3. **错误处理机制** 包含三级错误处理: - API请求异常捕获 - 流数据处理异常捕获 - JSON解析异常处理 4. **配置管理** 通过`.env`文件隔离敏感信息,符合12要素应用原则[^3]。 ### 五、性能优化建议 1. 使用连接池复用HTTP连接 2. 实现断线重连机制 3. 添加速率限制防止API过载 4. 使用WebSocket替代SSE(需API支持)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值