关于我对接了deepseek之后部署到本地将数据存储到mysql的过程
写在前面
今天写一下使用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">
<input
class="ai-input"
type="text"
v-model="questionMsg"
placeholder="请输入您的问题..."
@keyup.enter="main"
/>
<button class="ai-btn" @click="main">
<span>询问</span>
</button>
</div>
<textarea
class="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的形式处理的,但是其实并没有达到这种效果,你们对接的时候可以看文档自己多做几步处理,今天的文章就先这样吧,感觉不错的可以关注一下哦!