AI 对话完善【人工智能】
AI 对话【人工智能】
- 前言
- 版权
- 开源
- 推荐
- AI 对话
- v0版本:基础
- v1版本:对话
- 数据表
- tag.js
- TagController
- v2版本:回复中
- textarea.js
- ChatController
- v3版本:流式输出
- chatLast.js
- ChatController
- v4版本:多轮对话
- QianfanUtil
- ChatController
- v5:其他修改
- 前端样式:跳转到最后一个消息
- 前端样式:Message保留空白符
- 前端样式:最新回复保留空白符
- 最后
前言
2024-4-7 15:04:07
以下内容源自《【人工智能】》
仅供学习交流使用
版权
禁止其他平台发布时删除以下此话
本文首次发布于CSDN平台
作者是CSDN@日星月云
博客主页是https://jsss-1.blog.csdn.net
禁止其他平台发布时删除以上此话
开源
日星月云 / AI对话完善版
jsss-1/aichat
推荐
百度智能云+SpringBoot=AI对话【人工智能】
对话Chat-千帆大模型平台
AI 对话
以下版本除了最简单的AI对话,还完善了一下功能。
以下是部分代码,完整代码请移步GIT。
v0版本:基础
聊天
v1版本:对话
新建新对话
可以置顶(取消置顶)、删除、修改对应的对话
数据表
create table tag
(id int auto_incrementprimary key,user_id int not null,tag_name varchar(16) not null,top int default 0 null
);create table conversation
(id int auto_incrementprimary key,tag_id int null,user_message text null,bot_message text null,create_time varchar(32) null,username varchar(16) null
);
tag.js
$(document).ready(function () {tagList();$("#editBlock").hide();$(".add-button").on("click", function() {addTag();});});function tagSearch(data) {var data=$("#search-input").val();if(!data){//没有数据搜索全部tagList();return false;}$.ajax({type: "GET",url: SERVER_PATH + "/tag/search",data: {data: data},xhrFields: {withCredentials: true},success: function (result) {if (result.status) {alertBox(result.data.message);return false;}set_tags(result.data);}});
}function addTag() {$.ajax({type: "POST",url: SERVER_PATH + "/tag/addTag",xhrFields: {withCredentials: true},success: function (result) {if (result.status) {alertBox(result.data.message);return false;}tagList();}});
}function tagList() {$.ajax({type: "GET",url: SERVER_PATH + "/tag/tagList",xhrFields: {withCredentials: true},success: function (result) {if (result.status) {alertBox(result.data.message);return false;}set_tags(result.data);}});
}function set_tags(tags) {if (!tags) {return false;}$(".tag-list").empty();$.each(tags, function (i, tag) {var btnClass = tag.top === 0 ? "top-btn" : "notop-btn";var topClass = tag.top === 0 ? "ptTag" : "topTag";var tagDiv = `<div class="tag"><img class="tag-btn ${topClass}"></img><span class="show-btn" data-id="${tag.id}">${tag.tagName}</span><div class="button-group"><img class="icon-btn ${btnClass}" data-id="${tag.id}"></img><img class="icon-btn modify-btn" data-id="${tag.id}" data-name="${tag.tagName}"></img><img class="icon-btn delete-btn" data-id="${tag.id}"></img></div></div>`;$(".tag-list").append(tagDiv);});$(".show-btn").on("click", function() {var tagId = $(this).data('id');window.location.href="aichat.html?tagId="+tagId;});$(".notop-btn").on("click", function() {var tagId = $(this).data('id');var newTop=0;topTag(tagId,newTop);});$(".top-btn").on("click", function() {var tagId = $(this).data('id');var newTop=top=1;topTag(tagId,newTop);});$(".modify-btn").on("click", function() {var tagId = $(this).data('id');var tagName = $(this).data('name'); // 获取标签名称// 将标签名称填充到输入框中$("#newName").val(tagName);// 显示编辑界面块$("#editBlock").show();// 保存按钮点击事件$("#saveBtn").off("click").on("click", function() {var newName = $("#newName").val();if(!newName){alertBox("请输入新名字");return false;}modify(tagId,newName);// 关闭编辑界面块$("#editBlock").hide();});$("#cancelBtn").on("click", function() {$("#editBlock").hide();});});$(".delete-btn").on("click", function() {var tagId = $(this).data('id');// 弹出确认删除的提示框var confirmDelete = confirm("确定要删除这个标签吗?");// 如果用户点击确定删除,则执行删除操作if (confirmDelete) {deleteTag(tagId);} });}function topTag(tagId,newTop){$.ajax({type: "POST",url: SERVER_PATH + "/tag/top",data: {tagId: tagId,top: newTop},xhrFields: {withCredentials: true},success: function (result) {if (result.status) {alertBox(result.data.message);return false;}tagList();}});
}function modify(tagId,newName){$.ajax({type: "POST",url: SERVER_PATH + "/tag/modify",data: {tagId: tagId,tagName: newName},xhrFields: {withCredentials: true},success: function (result) {if (result.status) {alertBox(result.data.message);return false;}tagList();}});
}function deleteTag(tagId){$.ajax({type: "GET",url: SERVER_PATH + "/tag/delete",data: {tagId: tagId},xhrFields: {withCredentials: true},success: function (result) {if (result.status) {alertBox(result.data.message);return false;}tagList();}});
}
TagController
package com.jsss.qianfan.controller;import com.jsss.common.BusinessException;
import com.jsss.common.ErrorCode;
import com.jsss.common.ResponseModel;
import com.jsss.entity.User;
import com.jsss.qianfan.entity.Tag;
import com.jsss.qianfan.service.TagService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;import java.util.List;@RestController
@RequestMapping("tag")
@CrossOrigin(origins = "${jsss.web.path}", allowedHeaders = "*", allowCredentials = "true")
public class TagController implements ErrorCode {@AutowiredRedisTemplate redisTemplate;@AutowiredTagService tagService;@GetMapping("/tagList")public ResponseModel getTags(String token) {User user = null;if (StringUtils.isNotEmpty(token)) {user = (User) redisTemplate.opsForValue().get(token);}if (user == null) {throw new BusinessException(USER_NOT_LOGIN, "用户未登录");}List<Tag> tags = tagService.searchByUserId(user.getUserId());return new ResponseModel(tags);}@PostMapping("/addTag")public ResponseModel addTag(String token) {User user = null;if (StringUtils.isNotEmpty(token)) {user = (User) redisTemplate.opsForValue().get(token);}if (user == null) {throw new BusinessException(USER_NOT_LOGIN, "用户未登录");}String tagName = "新对话";Tag tag = new Tag(null, user.getUserId(), tagName, 0);tagService.addTag(tag);return new ResponseModel("添加成功");}@PostMapping("/modify")public ResponseModel modifyTag(Integer tagId, String tagName) {if (StringUtils.isEmpty(tagName)){throw new BusinessException(PARAMETER_ERROR, "缺失新的tag名");}tagService.updateTagName(tagId, tagName);return new ResponseModel("修改成功");}@PostMapping("/top")public ResponseModel topTag(Integer tagId, Integer top) {tagService.updateTagTop(tagId, top);String res = top == 1 ? "置顶成功" : "取消置顶成功";return new ResponseModel(res);}@GetMapping("/delete")public ResponseModel deleteTag(Integer tagId) {tagService.deleteTag(tagId);return new ResponseModel("删除成功");}@GetMapping("/search")public ResponseModel searchTag(String token, String data) {User user = null;if (StringUtils.isNotEmpty(token)) {user = (User) redisTemplate.opsForValue().get(token);}if (user == null) {throw new BusinessException(USER_NOT_LOGIN, "用户未登录");}List<Tag> tags = tagService.searchTag(user.getUserId(),data);return new ResponseModel(tags);}}
v2版本:回复中
用户发送问题之后,显示回复中,得到回复后显示。
前端发送请求之后,先会得到“回复中”;
之后,去轮询获取最新回复。
后端接受请求之后,先存入到数据库中一个未回复请求。
然后异步得到回复之后,再去更新数据库。
textarea.js
var textarea = document.getElementById("messageInput");var isSendingMessage = false; // 添加一个变量用于标识是否正在发送消息textarea.addEventListener("keydown", function(event) {if (event.key === "Enter" && !event.shiftKey) {event.preventDefault();if (isSendingMessage) {// 如果正在发送消息,则在文本框中添加换行符textarea.value += "\n";} else{var message = textarea.value.trim();textarea.value = "";if(!message){alertBox("输入内容不能为空!");return false;}var tagId=$.getUrlParam("tagId");;if(!tagId){alertBox("没有对应的参数");return false;}isSendingMessage = true; // 设置为true表示正在发送消息$.ajax({type: "POST",url: SERVER_PATH+"/chat/chat",data:{"tagId": tagId,"content":message},xhrFields: {withCredentials: true},success:function(result){isSendingMessage = false; // 发送完成后设置为falseif (result.status) {alertBox(result.data.message);return false;}//请求成功之后list(tagId);getChat(result.data.id);}});}}
});textarea.addEventListener("keydown", function(event) {if (event.key === "Enter" && event.shiftKey) {// 在 Shift+Enter 情况下允许换行textarea.value += "\n";event.preventDefault();}
});function getChat(chatId){var tagId=$.getUrlParam("tagId");;$.ajax({type: "GET",url: SERVER_PATH+"/chat/getChat",data:{"id": chatId,},xhrFields: {withCredentials: true},success:function(result){isSendingMessage = false; // 发送完成后设置为falseif (result.status) {alertBox(result.data.message);return false;}if (result.data.botMessage == "回复中...") {// 继续轮询,100ms 一次setTimeout(function() {getChat(chatId);}, 100);} else {// 获取到最终回复// 处理回复逻辑list(tagId);}}});
}
ChatController
@PostMapping("/chat")public ResponseModel chat(Integer tagId,String content){if (tagId==null){throw new BusinessException(PARAMETER_ERROR,"没有指定响应的tag");}if (StringUtils.isEmpty(content)){throw new BusinessException(PARAMETER_ERROR,"输入内容不能为空");}Tag tag = tagService.searchById(tagId);if (tag==null){throw new BusinessException(NOT_FIND,"没有找到对应的对话");}String username=userService.selectUserById(tag.getUserId()).getUsername();Conversation conversation = new Conversation(null, tagId,username, content, "回复中...", format(new Date()));chatService.addChat(conversation);// 异步处理AI回复CompletableFuture.runAsync(() -> {Integer id=conversation.getId();String res = null;try {res = qianfanUtil.addMessage(content);} catch (Exception e) {res = "回复失败";}Conversation aiConversation = new Conversation();aiConversation.setId(id);aiConversation.setBotMessage(res);chatService.updateChat(aiConversation);});return new ResponseModel(conversation);}
v3版本:流式输出
流式输出,终止生成。
前端实现,让消息一个字符一个字符显示
chatLast.js
var lastId;
var interval;$(document).ready(function () {$("#stopButton").on("click", function() {var latestReply = $(".latest-reply");var latestReplyText = latestReply.text();clearInterval(interval); // 停止字符流输出$("#stopButton").hide();updateStop(lastId,latestReplyText);});});function listLastReply(tagId) {$.ajax({type: "GET",url: SERVER_PATH + "/chat/list",data: {tagId: tagId},xhrFields: {withCredentials: true},success: function (result) {if (result.status) {alertBox(result.data.message);return false;}set_conversations_last(result.data);}});
}function set_conversations_last(conversations) {if (!conversations) {return false;}$(".conversation-list").empty();var len=conversations.length;$.each(conversations, function (i, conversation) {var questionDiv = '<div class="question-container">' +'<table class="question">' +'<td>' +'<span>' + conversation.createTime + '</span>' +'<div class="user-message">' + conversation.userMessage + '</div>' +'</td>' +'<td type="text">' + conversation.username + '</td>' +'</table>' +'</div>';var answerDiv = '<div class="answer-container">' +'<table class="answer">' +'<td type="text">AI</td>' +'<td>' +'<span>' + conversation.createTime + '</span>' +'<div class="bot-message">' + conversation.botMessage + '</div>' +'</td>' +'</table>' +'</div>';if(i!=len-1){$(".conversation-list").append(questionDiv);$(".conversation-list").append(answerDiv);}});// 获取最新对话的回复var lastConversation = conversations[len - 1];lastId=lastConversation.id;var questionDiv = '<div class="question-container">' +'<table class="question">' +'<td>' +'<span>' + lastConversation.createTime + '</span>' +'<div class="user-message">' + lastConversation.userMessage + '</div>' +'</td>' +'<td type="text">' + lastConversation.username + '</td>' +'</table>' +'</div>';$(".conversation-list").append(questionDiv);var answerDiv = '<div class="answer-container">' +'<table class="answer">' +'<td type="text">AI</td>' +'<td>' +'<span>' + lastConversation.createTime + '</span>' +'<div class="bot-message latest-reply">' + lastConversation.botMessage + '</div>' +'</td>' +'</table>' +'</div>';$(".conversation-list").append(answerDiv);// 逐字显示最新回复var latestReply = $(".latest-reply");var latestReplyText = latestReply.text();latestReply.empty();var index = 0;interval = setInterval(function() {if (index < latestReplyText.length) {$("#stopButton").show();latestReply.append(latestReplyText.charAt(index));index++;} else {clearInterval(interval);$("#stopButton").hide();}}, 10); // 逐字显示的速度,您可以根据需要调整}function updateStop(tagId,message){$.ajax({type: "POST",url: SERVER_PATH + "/chat/updateStop",data: {id: tagId,botMessage: message},xhrFields: {withCredentials: true},success: function (result) {if (result.status) {alertBox(result.data.message);return false;}}});
}
ChatController
@PostMapping("/updateStop")public ResponseModel updateStop(Integer id,String botMessage){Conversation conversation=new Conversation();conversation.setId(id);conversation.setBotMessage(botMessage);chatService.updateChat(conversation);return new ResponseModel();}
v4版本:多轮对话
实现上下文有关的对话
多次调用qianfan.addMessage().addMessage()
QianfanUtil
public String addMessagePlus(List<Message> messages, String content) {ChatResponse response = qianfan.chatCompletion().messages(messages).addMessage("user", content).temperature(0.7).execute();return response.getResult();}
ChatController
@PostMapping("/chat")public ResponseModel chat(Integer tagId, String content) {if (tagId == null) {throw new BusinessException(PARAMETER_ERROR, "没有指定响应的tag");}if (StringUtils.isEmpty(content)) {throw new BusinessException(PARAMETER_ERROR, "输入内容不能为空");}Tag tag = tagService.searchById(tagId);if (tag == null) {throw new BusinessException(NOT_FIND, "没有找到对应的对话");}String username = userService.selectUserById(tag.getUserId()).getUsername();Conversation conversation = new Conversation(null, tagId, username, content, "回复中...", format(new Date()));chatService.addChat(conversation);// 异步处理AI回复CompletableFuture.runAsync(() -> {Integer id = conversation.getId();String res = null;try {
// res = qianfanUtil.addMessage(content);res = qianfanUtil.addMessagePlus(getMessages(tagId), content);} catch (Exception e) {res = "回复失败";}Conversation aiConversation = new Conversation();aiConversation.setId(id);aiConversation.setBotMessage(res);chatService.updateChat(aiConversation);});return new ResponseModel(conversation);}public List<Message> getMessages(Integer tagId) {List<Message> messages = new ArrayList<>();List<Conversation> conversations = chatService.searchByTagId(tagId);int size = conversations.size() - 1;//最新的不需要for (int i = 0; i < size; i++) {Conversation conversation = conversations.get(i);Message userMessage = new Message();userMessage.setRole("user");userMessage.setContent(conversation.getUserMessage());messages.add(userMessage);Message botMessage = new Message();botMessage.setRole("assistant");botMessage.setContent(conversation.getBotMessage());messages.add(botMessage);}return messages;}
v5:其他修改
前端样式:跳转到最后一个消息
在aichat.html中
<script>function scrollToLastMessage() {// 找到消息容器var messageContainer = document.querySelector(".message-container");// 找到消息容器中最后一个子元素var lastMessage = messageContainer.lastElementChild;// 将最后一个消息元素滚动到可见区域lastMessage.scrollIntoView({ behavior: 'auto', block: 'end' });}function onLoad() {setTimeout(scrollToLastMessage, 100); // 添加100毫秒的延迟}window.addEventListener('load', onLoad);</script>
前端样式:Message保留空白符
savePre(conversation.userMessage)
savePre(conversation.botMessage)
function savePre(content){return content.replace(/\n/g, "<br>").replace(/ /g, "<span> </span>");
}
前端样式:最新回复保留空白符
var botMessageWithBrAndSpace = lastConversation.botMessage.replace(/\n/g, "\\n");var answerDiv = '<div class="answer-container">' +'<table class="answer">' +'<td type="text">AI</td>' +'<td>' +'<span>' + lastConversation.createTime + '</span>' +'<div class="bot-message latest-reply">' + botMessageWithBrAndSpace + '</div>' +'</td>' +'</table>' +'</div>';$(".conversation-list").append(answerDiv);// 逐字显示最新回复var latestReply = $(".latest-reply");var latestReplyText = botMessageWithBrAndSpace;latestReply.empty();var index = 0;interval = setInterval(function() {if (index < latestReplyText.length) {$("#stopButton").show();if (latestReplyText.charAt(index) === "\\") {if (latestReplyText.charAt(index + 1) === "n") {latestReply.append("<br>");index++; // 跳过"n"} else {latestReply.append(latestReplyText.charAt(index));}} else if(latestReplyText.charAt(index)===' '){latestReply.append(" ");}else {latestReply.append(latestReplyText.charAt(index));}index++;} else {clearInterval(interval);$("#stopButton").hide();}}, 25); // 逐字显示的速度,您可以根据需要调整}
最后
2024-4-10 17:02:49
迎着日光月光星光,直面风霜雨霜雪霜。
相关文章:

AI 对话完善【人工智能】
AI 对话【人工智能】 前言版权开源推荐AI 对话v0版本:基础v1版本:对话数据表tag.jsTagController v2版本:回复中textarea.jsChatController v3版本:流式输出chatLast.jsChatController v4版本:多轮对话QianfanUtilChat…...
利用数组储存表格数据
原理以及普通数组储存表格信息 在介绍数组的时候说过,数组能够用来储存任何同类型的数据,这里的意思就表明只要是同一个类型的数组据就可以储存到一个数组中。那么在表格中同一行的数据是否可以储存到同一个数组中呢?答案自然是可以ÿ…...

[数据概念|数据技术]智能合约如何助力数据资产变现
“ 区块链上数据具有高可信度,智能合约将区块链变得更加智能化,以支持企业场景。” 之前鼹鼠哥已经发表了一篇文章,简单介绍了区块链,那么,智能合约又是什么呢?它又是如何助力数据资产变现的呢?…...
JS中的常见二进制数据格式
格式描述用途示例ArrayBuffer固定长度的二进制数据缓冲区,不直接操作具体的数据,而是通过类型数组或DataView对象来读写用于存储和处理大量的二进制数据,如文件、图像等let buffer new ArrayBuffer(16);TypedArray基于ArrayBuffer对象的视图…...

uniapp开发h5端使用video播放mp4格式视频黑屏,但有音频播放解决方案
mp4格式视频有一些谷歌播放视频黑屏,搜狗浏览器可以正常播放 可能和视频的编码格式有关,谷歌只支持h.264编码格式的视频播放 将mp4编码格式修改为h.264即可 转换方法: 如果是自己手动上传文件可以手动转换 如果是后端接口调取的地址就需…...

Hive的分区与排序
一、Hive分区 1.引入: 在大数据中,最常见的一种思想就是分治,我们可以把大的文件切割划分成一个个的小的文件,这样每次操作一个个小的文件就会很容易了,同样的道理,在hive当中也是支持这种思想的ÿ…...
Objective-C学习笔记(内存管理、property参数)4.9
1.引用计数器retainCount:每个对象都有这个属性,默认值为1,记录当前对象有多少人用。 为对象发送一条retain/release消息,对象的引用计数器加/减1,为对象发一条retainCount,得到对象的引用计数器值,当计数器…...

C语言进阶课程学习记录-第29课 - 指针和数组分析(下)
C语言进阶课程学习记录-第29课 - 指针和数组分析(下) 数组名与指针实验-数组形式转换实验-数组名与指针的差异实验-转化后数组名加一的比较实验-数组名作为函数形参小结 本文学习自狄泰软件学院 唐佐林老师的 C语言进阶课程,图片全部来源于课…...

一起学习python——基础篇(13)
前言,python编程语言对于我个人来说学习的目的是为了测试。我主要做的是移动端的开发工作,常见的测试主要分为两块,一块为移动端独立的页面功能,另外一块就是和其他人对接工作。 对接内容主要有硬件通信协议、软件接口文档。而涉…...

SOCKS代理概述
在网络技术的广阔领域中🌐,SOCKS代理是一个核心组件,它在提升在线隐私保护🛡️、实现匿名通信🎭以及突破网络访问限制🚫方面发挥着至关重要的作用。本文旨在深入探讨SOCKS代理的基础,包括其定义…...

AI助力M-OFDFT实现兼具精度与效率的电子结构方法
编者按:为了使电子结构方法突破当前广泛应用的密度泛函理论(KSDFT)所能求解的分子体系规模,微软研究院科学智能中心的研究员们基于人工智能技术和无轨道密度泛函理论(OFDFT)开发了一种新的电子结构计算框架…...

【数据结构】单链表(一)
上一篇【数据结构】顺序表-CSDN博客 我们了解了顺序表,但是呢顺序表涉及到了一些问题,比如,中间/头部的插入/删除,时间复杂度为O(N);增容申请空间、拷贝、释放旧空间会有不小的消耗;增容所浪费的空间... 我们如何去解…...

SCI一区 | Matlab实现INFO-TCN-BiGRU-Attention向量加权算法优化时间卷积双向门控循环单元注意力机制多变量时间序列预测
SCI一区 | Matlab实现INFO-TCN-BiGRU-Attention向量加权算法优化时间卷积双向门控循环单元注意力机制多变量时间序列预测 目录 SCI一区 | Matlab实现INFO-TCN-BiGRU-Attention向量加权算法优化时间卷积双向门控循环单元注意力机制多变量时间序列预测预测效果基本介绍模型描述程…...

Coursera吴恩达《深度学习》课程总结(全)
这里有Coursera吴恩达《深度学习》课程的完整学习笔记,一共5门课:《神经网络和深度学习》、《改善深层神经网络》、《结构化机器学习项目》、《卷积神经网络》和《序列模型》, 第一门课:神经网络和深度学习基础,介绍一…...

C# 操作PDF表单 - 创建、填写、删除PDF表单域
通常情况下,PDF文件是不可编辑的,但PDF表单提供了一些可编辑区域,允许用户填写和提交信息。PDF表单通常用于收集信息、反馈或进行在线申请,是许多行业中数据收集和交换的重要工具。 PDF表单可以包含各种类型的输入控件࿰…...

Astropy:探索宇宙奥秘的Python工具箱
Astropy:探索宇宙奥秘的Python工具箱 什么是Astropy库? Astropy 是一个面向天文学领域的 Python 库,旨在提供常用的天文学数据结构、单位转换、物理常数以及天文学计算方法等功能。它为天文学家和研究人员提供了丰富的工具,用于处理和分析天文…...

java数据结构与算法刷题-----LeetCode684. 冗余连接
java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.csdn.net/grd_java/article/details/123063846 文章目录 并查集 并查集 解题思路:时间复杂度O( n ∗ l o g 2…...

循环神经网络简介
卷积神经网络相当于人类的视觉,但是它并没有记忆能力,所以它只能处理一种特定的视觉任务,没办法根据以前的记忆来处理新的任务。比如,在一场电影中推断下一个时间点的场景,这个时候仅依赖于现在的场景还不够࿰…...
计算机网络 子网掩码与划分子网
一、实验要求与内容 1、需拓扑图和两个主机的IP配置截图。 2、设置网络A内的主机IP地址为“192.168.班内学号.2”,子网掩码为“255.255.255.128”,网关为“192.168.班内学号.1”;设置网络B内的主机IP地址为“192.168.班内学号100.2”&#…...

HUD抬头显示器中如何设计LCD的阳光倒灌实验
关键词:阳光倒灌实验、HUD光照温升测试、LCD光照温升测试、太阳光模拟器 HUD(Head-Up Display,即抬头显示器)是一种将信息直接投影到驾驶员视线中的技术,通常用于飞机、汽车等驾驶舱内。HUD系统中的LCD(Liq…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...

如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...

Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...

Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...

优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》
这段 Python 代码是一个完整的 知识库数据库操作模块,用于对本地知识库系统中的知识库进行增删改查(CRUD)操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 📘 一、整体功能概述 该模块…...

基于SpringBoot在线拍卖系统的设计和实现
摘 要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统,主要的模块包括管理员;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...