uniapp+node+mysql接入deepseek实现流式输出
node
import express from 'express';
import mysql from 'mysql2';
import cors from 'cors';
import bodyParser from 'body-parser';
import axios from 'axios';
import { WebSocketServer } from 'ws'; // 正确导入 WebSocketServerconst app = express();// Middlewares
app.use(cors());
app.use(bodyParser.json()); // 解析JSON请求体
app.use(express.json());// MySQL数据库配置
const db = mysql.createConnection({host: '127.0.0.1',user: 'root',password: '123456',database: 'love_strategist',port: 3307,
});db.connect((err) => {if (err) throw err;console.log('✅ MySQL 连接成功');
});// 创建 WebSocket 服务器
const wss = new WebSocketServer({ port: 8080 }); // 使用 WebSocketServerwss.on('connection', (ws) => {console.log('客户端已连接');ws.on('message', async (message) => {const { message: userMessage } = JSON.parse(message);try {const response = await axios.post('https://api.deepseek.com/v1/chat/completions',{model: "deepseek-chat",messages: [{ role: "user", content: userMessage }],stream: true},{headers: {'Authorization': `Bearer 你的deepseekKey`,'Content-Type': 'application/json'},responseType: 'stream'});let buffer = ''; // 用于存储未完整的数据块response.data.on('data', (chunk) => {buffer += chunk.toString(); // 将数据块拼接到缓冲区// 按行分割数据const lines = buffer.split('\n');for (let i = 0; i < lines.length - 1; i++) {const line = lines[i].trim();if (line.startsWith('data: ')) {const jsonStr = line.replace('data: ', '');try {const data = JSON.parse(jsonStr);if (data.choices?.[0]?.delta?.content) {// 逐字发送内容const content = data.choices[0].delta.content;ws.send(JSON.stringify({ content }));}} catch (error) {console.error('解析JSON失败:', error);}}}// 保留未完整的数据行buffer = lines[lines.length - 1];});response.data.on('end', () => {ws.send(JSON.stringify({ content: '[DONE]' }));});} catch (error) {console.error('Error:', error);ws.send(JSON.stringify({ content: '系统错误,请稍后再试。' }));}});ws.on('close', () => {console.log('客户端已断开连接');});
});// 启动 HTTP 服务器
app.listen(3000, () => {console.log('✅ HTTP 服务器运行在 http://localhost:3000');
});console.log('WebSocket 服务器运行在 ws://localhost:8080');
uniapp
<template><view class="container"><!-- 顶部导航栏 --><view class="navbar">恋爱指导</view><!-- 聊天对话区域 --><scroll-view class="chat-box" scroll-y :style="{ height: (chatHeight - 70) + 'px' }" scroll-top="999999"><view v-for="(message, index) in messages" :key="index" class="chat-item"><view :class="message.from === 'user' ? 'user-message' : 'bot-message'"><text>{{ message.content }}</text></view></view></scroll-view><!-- 输入框区域 --><view class="input-area"><input v-model="userInput" class="input-box" placeholder="请输入你的问题..." /><button class="send-btn" @click="sendMessage">发送</button></view></view>
</template><script>export default {data() {return {userInput: '', // 用户输入的消息messages: [], // 存储消息记录chatHeight: 0, // 聊天框高度adviceList: [], // 存储恋爱建议socket: null // WebSocket 实例};},mounted() {this.adjustChatHeight(); // 调整聊天框高度},onShow() {setTimeout(() => {this.initWebSocket(); // 初始化 WebSocket}, 300)},// 页面隐藏时关闭 WebSocketonHide() {if (this.socket) {this.socket.close(); // 关闭 WebSocketconsole.log('WebSocket 连接已关闭');}},methods: {// 选中标签填充输入框并发送selectAdvice(content) {this.userInput = content;this.sendMessage();},// 动态计算聊天框高度adjustChatHeight() {const windowHeight = uni.getSystemInfoSync().windowHeight;this.chatHeight = windowHeight - 120; // 留出顶部和输入框的高度},// 初始化 WebSocket 连接initWebSocket() {this.socket = uni.connectSocket({url: 'ws://localhost:8080',success: () => {console.log('WebSocket 连接成功4');},fail: (err) => {console.error('WebSocket 连接失败:', err);}});// 监听 WebSocket 消息this.socket.onMessage((res) => {const data = JSON.parse(res.data);if (data.content === '[DONE]') {this.isStreaming = false; // 结束流式传输} else {// 逐字追加内容this.messages[this.messages.length - 1].content += data.content;this.$nextTick(() => {this.scrollToBottom();});}});// 监听 WebSocket 关闭this.socket.onClose(() => {console.log('WebSocket 连接已关闭');});},// 发送消息sendMessage() {if (this.userInput.trim() && !this.isStreaming) {this.addUserMessage(this.userInput); // 显示用户输入的消息this.isStreaming = true;// 通过 WebSocket 发送消息this.socket.send({data: JSON.stringify({message: this.userInput}),success: () => {console.log('消息发送成功');this.addBotMessage(''); // 初始化一个空消息用于逐步填充},fail: (err) => {console.error('消息发送失败:', err);}});this.userInput = ''; // 清空输入框}},// 添加用户消息addUserMessage(content) {this.messages.push({from: 'user',content: content});},// 添加机器人回复addBotMessage(content) {this.messages.push({from: 'bot',content: content});},// 滚动到底部scrollToBottom() {const query = uni.createSelectorQuery().in(this);query.select('.chat-box').boundingClientRect(res => {if (res) {uni.pageScrollTo({scrollTop: res.height,duration: 0});}}).exec();}}};
</script><style scoped>/* 页面容器 */.container {background-color: #fff;height: 100%;/* padding: 0 15px; *//* 加入左右边距 */}/* 顶部导航栏 */.navbar {background-color: #ff65a3;color: #fff;text-align: center;padding: 12px 0;font-size: 18px;font-weight: bold;}/* 聊天框 */.chat-box {padding: 10px;margin-bottom: 70px;/* 留出输入框的空间 */padding-left: 0;margin: 0 15px;width: auto;/* 去掉左边距,给消息更多空间 */padding-right: 0;/* 去掉右边距 */}/* 聊天消息 */.chat-item {margin: 10px 0;display: flex;}.user-message {text-align: right;background-color: #ff65a3;color: #fff;padding: 10px;border-radius: 10px;max-width: 80%;margin-left: auto;}.bot-message {text-align: left;background-color: #f2f2f2;color: #000;padding: 10px;border-radius: 10px;max-width: 80%;margin-right: auto;}/* 输入框 */.input-area {display: flex;position: fixed;bottom: 0;left: 0;width: 93%;padding: 10px;background-color: #fff;border-top: 1px solid #ddd;padding-left: 15px;/* 左边距 */padding-right: 15px;/* 右边距 */}.input-box {flex: 1;height: 40px;border-radius: 20px;border: 1px solid #ddd;padding: 0 15px;font-size: 16px;}.send-btn {background-color: #ff65a3;color: #fff;font-size: 16px;border: none;padding: 0 20px;border-radius: 20px;margin-left: 10px;}/* 恋爱指导标签 */.guidance-tags {display: flex;overflow-x: scroll;white-space: nowrap;padding: 10px;background-color: #ffe5f1;}.tag-item {display: inline-block;background-color: #ff65a3;color: white;padding: 8px 15px;margin-right: 10px;border-radius: 20px;font-size: 14px;cursor: pointer;}
</style>
相关文章:
uniapp+node+mysql接入deepseek实现流式输出
node import express from express; import mysql from mysql2; import cors from cors; import bodyParser from body-parser; import axios from axios; import { WebSocketServer } from ws; // 正确导入 WebSocketServerconst app express();// Middlewares app.use(cors…...
PHP MySQL 创建数据库
PHP MySQL 创建数据库 引言 在网站开发中,数据库是存储和管理数据的核心部分。PHP 和 MySQL 是最常用的网页开发语言和数据库管理系统之一。本文将详细介绍如何在 PHP 中使用 MySQL 创建数据库,并对其操作进行详细讲解。 前提条件 在开始创建数据库之…...
UE4 World, Level, LevelStreaming从入门到深入
前言 在《塞尔达传说:旷野之息》中,玩家攀上初始高塔的瞬间,目光所及的山川湖泊皆可抵达;在《艾尔登法环》中,黄金树的辉光始终悬于地平线之上,指引玩家穿越无缝衔接的史诗战场。这些现代游戏杰作背后的核…...
3月8日实验
拓扑: 需求: 1.学校内部的HTTP客户端可以正常通过域名www.baidu.com访问到白度网络中的HTTP服务器 2.学校网络内部网段基于192.168.1.0/24划分,PC1可以正常访问3.3.3.0/24网段,但是PC2不允许 3.学校内部路由使用静态路由&#…...
IO多路复用实现并发服务器
一.select函数 select 的调用注意事项 在使用 select 函数时,需要注意以下几个关键点: 1. 参数的修改与拷贝 readfds 等参数是结果参数 : select 函数会直接修改传入的 fd_set(如 readfds、writefds 和 exceptfds…...
【漫话机器学习系列】122.相关系数(Correlation Coefficient)
深入理解相关系数(Correlation Coefficient) 1. 引言 在数据分析、统计学和机器学习领域,研究变量之间的关系是至关重要的任务。我们常常想知道:当一个变量变化时,另一个变量是否也会随之变化?如果会&…...
控制系统分类
文章目录 定义与特点1. 自治系统(Autonomous System)与非自治系统(Non-Autonomous System)自治系统非自治系统 2. 线性系统(Linear System)与非线性系统(Nonlinear System)线性系统非…...
文档操作方法得合理使用
博主介绍:✌全网粉丝5W,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战,博主也曾写过优秀论文,查重率极低,在这方面有丰富的经验…...
Python asyncIO 面试题及参考答案 草
目录 如何正确定义一个协程函数?直接调用协程会引发什么问题? 使用 async def 定义的协程与普通函数执行流程有何本质区别? 解释 asyncio.run () 的作用及与手动管理事件循环的差异 为什么协程中必须使用 await 而非 yield 挂起操作? 写出通过 async for 实现异步迭代器…...
计算机网络——交换机
一、什么是交换机? 交换机(Switch)是局域网(LAN)中的核心设备,负责在 数据链路层(OSI第二层)高效转发数据帧。它像一位“智能交通警察”,根据设备的 MAC地址 精准引导数…...
matlab和FPGA联合仿真时读写.txt文件数据的方法
在FPGA开发过程中,往往需要将MATLAB生成的数据作为原始激励灌入FPGA进行仿真。为了验证FPGA计算是否正确,又需要将FPGA计算结果导入MATLAB绘图与MATLAB计算结果对比。 下面是MATLAB“写.txt”、“读.txt”,Verilog“读.txt”、“写.txt”的代…...
解锁DeepSpeek-R1大模型微调:从训练到部署,打造定制化AI会话系统
目录 1. 前言 2.大模型微调概念简述 2.1. 按学习范式分类 2.2. 按参数更新范围分类 2.3. 大模型微调框架简介 3. DeepSpeek R1大模型微调实战 3.1.LLaMA-Factory基础环境安装 3.1大模型下载 3.2. 大模型训练 3.3. 大模型部署 3.4. 微调大模型融合基于SpirngBootVue2…...
【分布式】聊聊分布式id实现方案和生产经验
对于分布式Id来说,在面试过程中也是高频面试题,所以主要针对分布式id实现方案进行详细分析下。 应用场景 对于无论是单机还是分布式系统来说,对于很多场景需要全局唯一ID, 数据库id唯一性日志traceId 可以方便找到日志链&#…...
uniapp或者vue 使用serialport
参考https://blog.csdn.net/ykee126/article/details/90440499 版本是第一位:否则容易编译失败 node 版本 18.14.0 npm 版本 9.3.1 electron 版本 30.0.8 electron-rebuild 版本 3.2.9 serialport 版本 10.0.0 需要python环境 main.js // Modules to control app…...
机器学习12-视觉识别任务
机器学习12-视觉识别任务 分类语义分割滑动窗口滑动窗口的实现思路优点缺点现代替代方法 全卷积(Fully Convolutional Networks, FCN)FCN 的工作原理FCN 的性能优势FCN 的应用案例FCN 的局限性改进方向下采样可学习的上采样:转置卷积 目标检测区域建议Se…...
使用paramiko爆破ssh登录
一.确认是否存在目标主机是否存在root用户 重跑 CVE-2018-15473用户名枚举漏洞 检测: import paramiko from paramiko.ssh_exception import AuthenticationExceptiondef check_user(username, hostname, port):ssh paramiko.SSHClient()ssh.set_missing_host_key…...
游戏引擎学习第146天
音高变化使得对齐读取变得不可能,我们可以支持循环声音了。 我们今天的目标是完成之前一段时间所做的音频代码。这个项目并不依赖任何引擎或库,而是一个教育项目,目的是展示从头到尾运行一个游戏所需要的全部代码。无论你对什么方面感兴趣&a…...
装饰器模式--RequestWrapper、请求流request无法被重复读取
目录 前言一、场景二、原因分析三、解决四、更多 前言 曾经遇见这么一段代码,能看出来是把request又重新包装了一下,核心信息都不会改变 后面了解到这叫 装饰器模式(Decorator Pattern) :也称为包装模式(Wrapper Pat…...
【算法题】小鱼的航程
问题: 分析 分析题目,可以看出,给你一个开始的星期,再给一个总共天数,在这些天内,只有周六周日休息,其他全要游泳250公里。 那分支处理好啦 当星期为6时,需要消耗2天,…...
视频录像机视频通道是指什么
视频录像机的视频通道是指摄像机在监控矩阵或硬盘录像机设备上的视频输入的物理位置。 与摄像头数量关系:在视频监控系统中,有多少个摄像头就需要多少路视频通道,通道数量决定了视频录像机可接入摄像头的数量,一般硬盘录像机有4路…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
