寫在前面
今天寫一下使用nodejs作為服務端,vue作為客戶端,mysql的數據庫,對接deepseek的全過程,要實現一個很簡單的效果就是,可以自由的詢問,然后可以將詢問的過程存儲到mysql的數據庫中。
文檔對接
deepseek對接文檔
效果圖
服務端代碼
- 這里避免你們看的時候費勁,所以這里不做任何封裝,正常你們如果用代碼,可以將連接數據、輸出答案的過程封裝起來。下面的代碼為不封裝的,僅供參考!別說我寫代碼不封裝,最討厭這種人。以下為nodejs代碼
插件安裝
npm i cors
npm i mysql2
npm i openai
var createError = require("http-errors");
var express = require("express");
var path = require("path");
var OpenAI = require("openai");
var cors = require("cors");const mysql = require("mysql2/promise");// 創建數據庫連接池
const pool = mysql.createPool({host: "127.0.0.1", port: 3306, user: "root",password: "實際情況來!",database: "deepseek",waitForConnections: true,connectionLimit: 10,queueLimit: 0,
});
// 測試鏈接情況
pool.getConnection().then((connection) => {console.log("數據庫連接成功");connection.release();}).catch((err) => {console.error("數據庫連接失敗:", err);});var app = express();
// 啟用 CORS 避免本地調用出現的跨域問題
app.use(cors());
// 格式化返回數據為JSON格式
app.use(express.json());// 初始化OpenAI客戶端
const openai = new OpenAI({baseURL: "https://api.deepseek.com", // 官方固定的地址apiKey: "自己的key",
});// 添加POST路由處理聊天請求
app.post("/chat", async (req, res) => {// console.log("收到請求:", req.body);// 添加這行來收集完整回答let fullAnswer = ""; try {// 引入官方文檔語法const completion = await openai.chat.completions.create({messages: req.body.messages || [{ role: "system", content: "You are a helpful assistant." },],model: "deepseek-chat",stream: true,},{ responseType: "stream" });// 設置響應頭res.setHeader("Content-Type", "text/event-stream");res.setHeader("Cache-Control", "no-cache");res.setHeader("Connection", "keep-alive");// 處理流式響應for await (const chunk of completion) {const content = chunk.choices[0]?.delta?.content || "";if (content) {fullAnswer += content; // 累積完整回答res.write(`data: ${JSON.stringify(chunk)}\n\n`);}}const connection = await pool.getConnection();try {console.log("準備存儲到數據庫:", {question: req.body.messages[0].content,answer: fullAnswer,});const [result] = await connection.execute("INSERT INTO chat_history (question, answer) VALUES (?, ?)",[req.body.messages[0].content, fullAnswer]);console.log("數據庫存儲結果:", result);} catch (dbError) {console.error("數據庫存儲錯誤:", dbError);} finally {connection.release();}// 添加結束標記res.write("data: [DONE]\n\n"); res.end();} catch (error) {console.error("Error:", error);if (!res.headersSent) {// 檢查是否已經發送響應頭res.status(500).json({ error: error.message });} else {res.write(`data: ${JSON.stringify({ error: error.message })}\n\n`);res.end();}}
});// 添加服務啟動監聽
const port = process.env.PORT || 3000;
app.listen(port, () => {console.log(`DeepSeek 服務已啟動,監聽端口: ${port}`);
});module.exports = app;
客戶端代碼
這里為了簡單,就沒有對css進行scss處理,喜歡折騰的自己改一下樣式也可以
插件安裝
npm i axios
<template><div class="chat-container"><div class="input-wrapper"><inputclass="ai-input"type="text"v-model="questionMsg"placeholder="請輸入您的問題..."@keyup.enter="main"/><button class="ai-btn" @click="main"><span>詢問</span></button></div><textareaclass="ai-area"v-model="answer"placeholder="AI 回答將顯示在這里..."readonly></textarea></div>
</template><script setup>
import axios from 'axios';
import { ref } from "vue";const questionMsg = ref("");
const answer = ref("");
const loading = ref(false);async function main() {if (!questionMsg.value.trim()) return;loading.value = true;answer.value = "";try {const response = await axios({method: 'post',url: 'http://localhost:3000/chat',data: {messages: [{role: "system",content: questionMsg.value,},],model: "deepseek-chat",stream: true},headers: {'Authorization': 'Bearer 自己的key','Content-Type': 'application/json',},responseType: 'text', // 改為 text 類型});// 處理返回的文本數據const lines = response.data.split('\n').filter(line => line.trim() !== '');for (const line of lines) {if (line.startsWith('data: ')) {try {const data = JSON.parse(line.slice(6));const content = data.choices[0]?.delta?.content || '';answer.value += content;} catch (e) {console.error('Parse error:', e);}}}} catch (error) {console.error("Error:", error);answer.value = "抱歉,發生了錯誤,請稍后重試。";} finally {loading.value = false;}
}
</script><style>
.chat-container {max-width: 800px;margin: 40px auto;padding: 20px;border-radius: 12px;box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);background-color: #ffffff;
}.input-wrapper {display: flex;gap: 15px;margin-bottom: 20px;
}.ai-input {flex: 1;height: 45px;padding: 0 15px;border: 2px solid #e8e8e8;border-radius: 8px;font-size: 16px;transition: all 0.3s ease;
}.ai-input:focus {outline: none;border-color: #409eff;box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
}.ai-btn {min-width: 100px;height: 45px;border: none;border-radius: 8px;background-color: #409eff;color: #fff;font-size: 16px;font-weight: 500;cursor: pointer;transition: all 0.3s ease;
}.ai-btn:hover {background-color: #66b1ff;transform: translateY(-1px);
}.ai-btn:active {transform: translateY(1px);
}.ai-area {width: 100%;min-height: 200px;padding: 15px;border: 2px solid #e8e8e8;border-radius: 8px;font-size: 15px;line-height: 1.6;resize: vertical;transition: all 0.3s ease;
}.ai-area:focus {outline: none;border-color: #409eff;box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
}
</style>
數據庫設計
因為我主要是搞前端的,所以對數據庫設計這塊無法整的很好,后端的大佬看到就不要笑我了,這里我只是簡單的演示一下整個處理的過程,所以表設計也是非常簡單的。我用的數據庫客戶端也是DBeaver,非常簡單的一個客戶端。
CREATE DATABASE IF NOT EXISTS deepseek;
USE deepseek;CREATE TABLE IF NOT EXISTS chat_history (id INT AUTO_INCREMENT PRIMARY KEY,question TEXT NOT NULL,answer TEXT NOT NULL,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
存儲之后的效果
服務端攔截到的日志
總結
整體對接下來,因為我對接的是最基礎的,你們可以看到這里我甚至沒有做連續對話和長鏈接的形式對接,雖然用了stream的形式處理的,但是其實并沒有達到這種效果,你們對接的時候可以看文檔自己多做幾步處理,今天的文章就先這樣吧,感覺不錯的可以關注一下哦!