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路…...
AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...
(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...
selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...
人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
