原生js: AI聊天功能, 仿照chatGPT问答功能

ops/2024/10/18 12:21:47/
htmledit_views">

问:

现在我们需要一个ai聊天功能, 接口已经给出:

只要是message就是我们的数据, 是message_end就是结束信息, 其他的我们不需要管.

回答:

我们不使用传统的fetch请求这个接口, 而是使用sse, eventSource去请求,

当我们输入框回车 或者 点击元素, 获取到输入框中用户输入的值, 然后创建用户问题标签,

同时, 检查当前有无eventSource , 没有的话创建eventSource, eventSource要设置,withCredentials:true携带cookie.

当请求接口的时候没有返回值之前, 我们需要创建一个 "正在加载..."的标签, 给用户提示.

在eventSource.onmessage外面创建一个newStr空字段, 

注意: 要在eventSource.onmessage外面创建, 在里面创建会创建很多的newStr,

eventSource.onmessage处理返回的数据,

这里加了一个小功能: 接口返回文字我们的网页跟随, 返回文字增加一行我们就向下滑动,时刻是在最下面, 不需要用户手动下滑.

判断: 当时要是message_end, 就调用eventSource.close关闭连接.


 

问:

eventSource = new EventSource(fullUrl, { withCredentials: true });的{ withCredentials: true }什么呢意思?

回答:

在JavaScript中,`EventSource` 是用于接收服务器推送的一种技术,通常用于实现服务器发送事件(Server-Sent Events,SSE)。在你的代码片段中,`EventSource` 的初始化使用了一个配置对象 `{ withCredentials: true }`。

`withCredentials: true` 的意思是在跨域请求中携带凭据(credentials),比如说在请求中包括 cookies 和 HTTP认证信息(即使是跨域请求)。这对于需要在跨域请求中进行认证或会话管理的情况非常有用。具体来说:

- 如果 `withCredentials` 设置为 `true`,则 `EventSource` 在发送请求时会包括当前页面的 cookies 和 HTTP认证信息(如果存在的话)。
- 如果 `withCredentials` 设置为 `false` 或未指定,默认情况下,跨域请求中不会携带 cookies 和 HTTP认证信息。

使用 `withCredentials: true` 的场景包括需要进行用户身份验证或授权的跨域服务器推送。这确保了在跨域情况下能够正确地传递身份验证信息,使得服务器能够基于用户的会话状态提供个性化的数据或服务。

需要注意的是,为了确保安全性,跨域请求中的 `withCredentials` 功能通常需要服务器端的支持,并且需要服务器配置允许接收包含凭据的请求

问:

我们调用ai聊天接口, 触发一次事件, 会不停的调用这个接口, 请问为什么?

回答:

html" title=javascript>javascript">function handleKeyPress(event) {if (event.keyCode === 13) {event.preventDefault();var input = document.getElementById('chat_input');var question = input.value.trim();if (question !== '') {var dialogueContainer = document.querySelector('.dialogue dl');let str = "";// 创建用户问题的对话框项var dt = document.createElement('dt');var dtParagraph = document.createElement('p');dtParagraph.textContent = '' + question + '';dt.appendChild(dtParagraph);dialogueContainer.appendChild(dt);const appinfo = getCookie('appinfo');var apiUrl = 'https://xxxx.xxxx.com/xxxx-xxxx/xxxx/xxxx';var params = {query: question,unicodeToChinese: 1,};if (appinfo) {params.appinfo = appinfo;}var queryString = new URLSearchParams(params).toString();var fullUrl = apiUrl + '?' + queryString;eventSource = new EventSource(fullUrl, { withCredentials: true });// 创建对话框和段落元素var dd = document.createElement('dd');var ddParagraph = document.createElement('p');dd.appendChild(ddParagraph);dialogueContainer.appendChild(dd);// 初始化段落元素的文本内容var newStr = '';// 处理消息事件eventSource.onmessage = function (event) {var data = JSON.parse(event.data);

这里我们触发handleKeyPress事件后, eventSource = new EventSoutce会一直调用, 所以就一直创建新的连接,

需要怎么改?

html" title=javascript>javascript">function handleKeyPress(event) {if (event.keyCode === 13) {event.preventDefault();var input = document.getElementById('chat_input');var question = input.value.trim();if (question !== '') {var dialogueContainer = document.querySelector('.dialogue dl');let str = "";// 创建用户问题的对话框项var dt = document.createElement('dt');var dtParagraph = document.createElement('p');dtParagraph.textContent = '' + question + '';dt.appendChild(dtParagraph);dialogueContainer.appendChild(dt);const appinfo = getCookie('appinfo');var apiUrl = 'https://xxxx.xxxx.com/xxxx-x/xxxx/xxxx';var params = {query: question,unicodeToChinese: 1,};if (appinfo) {params.appinfo = appinfo;}var queryString = new URLSearchParams(params).toString();var fullUrl = apiUrl + '?' + queryString;// 检查是否已有 EventSource 实例if (!eventSource || eventSource.readyState === EventSource.CLOSED) {eventSource = new EventSource(fullUrl, { withCredentials: true });

我们在创建eventSource = new EventSource之前先进入判断: 当前没有eventSource的情况采取创建连接,否则不创建连接.这样修改后触发一次handleKeyPress事件就创建一个eventSource连接.

其中遇到的问题:

接口返回得文字是一个字或者两个字或者三个字, 我们在页面展示的时候, 总是会按字数的增加递增或者一个字一行:

你好

你好啊

你好啊是

你好啊是啥

x

x

x

xxx

的一个

xx

xx

xx

x

x

xx

xx

x

xx

xx

深度

xx

xxx

xx

上面两种情况不是我们需要的, 

这个情况的原因是:

我们每次循环遍历文字我们都创建了一个p标签, 导致接口返回一个字我们就会重新开启一行, 这是p标签导致的.

最终代码:

html" title=javascript>javascript"><!-- 聊天显示 -->
<div class="dialogue"><dl><!--<dt><p>“财新数据通”是什么?</p></dt><dd><p>“财新数据通是集金融数据、权威资讯、品质服务于一体的金融数据资讯产品,帮助读者完成资讯获取、背景调查、数据分析和决策制定</p></dd>--></dl></div>
<!-- 聊天输入框 --><div class="customer_service"><p>联系客服</p><!-- <input class="chat_input" type="text" placeholder="请输入您想咨询的问题…"> --><input id="chat_input" class="chat_input" type="text" placeholder="请输入您想咨询的问题…"onkeydown="handleKeyPress(event)"></div>// 聊天函数
var eventSource; // 在函数外部定义 eventSource 变量,以便在整个作用域中访问, 控制回车, 只调用一次接口function handleKeyPress(event) {console.log(event, '聊天函数event');if (event.keyCode === 13 || event.type === 'click') {if (event.keyCode === 13) {event.preventDefault();event.stopPropagation(); // 阻止事件继续传播}var input = document.getElementById('chat_input');var question = event.type === 'click' ? event.question : input.value.trim(); // 获取问题文本if (question !== '') {var dialogueContainer = document.querySelector('.dialogue dl');let str = "";// 创建用户问题的对话框项var dt = document.createElement('dt');var dtParagraph = document.createElement('p');dtParagraph.textContent = '' + question + '';dtParagraph.style.textAlign = 'left'; // 样式设置为text-align:left;dt.appendChild(dtParagraph);dialogueContainer.appendChild(dt);const appinfo = getCookie('appinfo');var apiUrl = 'https://xxxx.xxxx.com/xxxx-xxxx/xxxx/xxxx';var params = {query: question,unicodeToChinese: 1,};if (appinfo) {params.appinfo = appinfo;}var queryString = new URLSearchParams(params).toString();var fullUrl = apiUrl + '?' + queryString;// 检查是否已有 EventSource 实例if (!eventSource || eventSource.readyState === EventSource.CLOSED) {eventSource = new EventSource(fullUrl, { withCredentials: true });// 创建对话框和段落元素//var dd = document.createElement('dd');//var ddParagraph = document.createElement('p');//dd.appendChild(ddParagraph);//dialogueContainer.appendChild(dd);var loadingAnswer = '正在加载...'; // 定义 loading 回答// 创建对话框和段落元素 创建 loading 回答的对话框项var loadingDt = document.createElement('dd');var loadingDtParagraph = document.createElement('p');loadingDtParagraph.textContent = loadingAnswer;loadingDt.appendChild(loadingDtParagraph);dialogueContainer.appendChild(loadingDt);// 初始化段落元素的文本内容var newStr = '';// 处理消息事件eventSource.onmessage = function (event) {var data = JSON.parse(event.data);if (data.event === "message") {// 使用每个新字符更新段落元素的文本内容 更新 loading 回答为接口返回的数据newStr += data.answer;loadingDtParagraph.textContent = newStr;// 滚动页面到底部window.scrollTo(0, document.body.scrollHeight);// 如果是第一个字符,显示对话框if (newStr.length === 1) {showDialogue();}// 如果接收到完整的回复,关闭 EventSource 对象if (data.complete) {eventSource.close();}} else if (data.event === "message_end") {eventSource.close();}};function showDialogue() {// 显示对话框和段落元素样式loadingDt.style.display = 'block'; // 或者使用其他适当的样式来显示对话框}}// 清空输入框input.value = '';}}
}


http://www.ppmy.cn/ops/90374.html

相关文章

使用React实现实时展示海康威视摄像头多画面

在现代web开发中&#xff0c;实时视频流的应用变得越来越普遍。无论是监控系统还是视频会议&#xff0c;能够轻松地将实时视频集成到前端应用中是一项重要的技能。本文将向你展示如何使用React来实现实时展示来自海康威视摄像头的多画面视频流。 准备工作 1. 环境搭建 确保你…

iview中Checkbox组件设置不勾选是0,勾选是1

正常情况: <Checkbox v-model"data.blow" true-value"1" false-value"0"><span>是否易燃易爆</span> </Checkbox>vue的data中&#xff0c;将Checkbox绑定的初始值设置成0。 data: function () {return {data: {blow: &…

【系统架构设计师】二十四、安全架构设计理论与实践③

目录 五、网络安全体系架构设计 5.1 OSI安全架构 5.2 认证框架 5.3 访问控制框架 5.4 机密性框架 5.5 完整性框架 5.6 抗抵赖框架 往期推荐 五、网络安全体系架构设计 5.1 OSI安全架构 OSI定义了7层协议&#xff0c;其中除第5层(会话层)外&#xff0c;每一层均能提供相…

Android 设置CheckBox框颜色

可以通过定义自定义的 CheckBox 样式来改变其外观。在 res 目录下的 styles.xml 文件中定义一个样式&#xff0c;然后在布局文件中将该样式应用到 CheckBox 上 <style name"MyCheckBox" parent"Theme.AppCompat.Light"><item name"colorCont…

[Unity]在场景中随机生成不同位置且不重叠的物体

1.前言 最近任务需要用到Unity在场景中随机生成物体&#xff0c;且这些物体不能重叠&#xff0c;简单记录一下。 参考资料:How to ensure that spawned targets do not overlap ? 2.结果与代码 结果如下所示&#xff1a; 代码如下所示&#xff1a; using System.Collec…

C#:具体类=>抽象类=>接口的变化过程详解

文章目录 简单复习继承与多态具体类抽象类及成员使用语法 接口抽象类到接口的进化 简单复习继承与多态 下面,我用一个交通工具的例子来快速复习一下. 1.首先我定义一个基类Vehicle,代表交通工具的总称.里面定义了一个可被重写的成员方法Run. class Vehicle{public virtual voi…

Python爬虫技术 第31节 持续集成和自动化部署

持续集成和自动化部署 Git版本控制 Git 是一个非常流行的分布式版本控制系统&#xff0c;用于跟踪对项目文件的修改。对于爬虫项目来说&#xff0c;使用Git可以帮助你管理代码的不同版本&#xff0c;协同开发&#xff0c;并且可以在出现问题时回滚到之前的版本。 基本操作&a…

KubeVirt虚拟机存储及网络卸载加速解决方案

1. 方案背景 1.1. KubeVirt介绍 随着云计算和容器技术的飞速发展&#xff0c;Kubernetes已成为业界公认的容器编排标准&#xff0c;为用户提供了强大、灵活且可扩展的平台来部署和管理各类应用。然而&#xff0c;在企业的实际应用中&#xff0c;仍有许多传统应用或遗留系统难…