【gtpJavaScript】使用JavaScript实现套壳gtp与gtp打字输出效果

postman测试gtp接口

https://platform.openai.com/docs/api-reference/chat/create?lang=curl

导入到postman中

记得弄一个gtp的key

然后请求测试gtp接口:

纯前端实现gtp请求页面 

目录结构:

 

部分参考:GitHub - xxxjkk/chat-website: 简易版chat网站,拿来即用,静态部署 

 index.html

<!DOCTYPE html>
<html lang="en"><head><script>var password = ""var realpassword = atob("NjY4OA==")password = prompt('请输入密码 (本网站需输入密码才可进入):', '')if (password != realpassword) {alert("密码不正确,无法进入本站!!")// 密码不正确就关闭open(location, '_self').close()}  </script><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><!-- 设置小图标 --><link rel="icon" type="images/x-icon" href="./static/images/favicon.ico"><link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css"><link rel="stylesheet" href="./static/css/bootstrap.min.css"><link rel="stylesheet" href="./static/css/style.css"><title>ac-chat</title><style>#output {display: inline;}.cursor {display: inline-block;width: 10px;height: 20px;background-color: black;vertical-align: text-bottom;animation: blink 1s infinite;}@keyframes blink {50% {opacity: 0;}}</style>
</head><body><div class="container"><div class="row"><div class="col-xs-12"><div class="title"><h2 class="text-center">ChatGTP</h2></div><div class="key"><div class="input-group col-sm-6"><span class="input-group-addon"><input type="checkbox" class="ipt-1"></span><input type="password" class="form-control ipt-2" placeholder="使用自己的api key"></div></div><div class="answer"><div class="tips text-center"><h3 class="lead">仅做技术研究探讨使用!</h3></div><div id="chatWindow"></div><div class="input-group ipt"><div class="col-xs-12"><textarea id="chatInput" class="form-control" rows="1" style="min-height: 40px;"></textarea></div><button id="chatBtn" class="btn btn-primary" type="button">Go !</button></div></div></div></div><div class="row foot"><footer class="col-xs-12" style="margin-top: 10px;"><p class="lead text-center">“抢走工作的不会是AI,而是率先掌握AI能力的人”</p></footer></div></div></body><script src="./static/js/jquery-2.1.1.js"></script>
<script src="https://code.jquery.com/ui/1.13.1/jquery-ui.min.js"></script>
<script src="./static/js/bootstrap.min.js"></script>
<script src="./static/js/layer/layer.js"></script>
<script src="./static/js/custom.js"></script></html>

custom.js

// 封装弹窗layer组件等
var common_ops = {// 封装layer.alert(content, options, yes) - 普通信息框alert: function (msg, cb) {layer.alert(msg, {yes: function (index) {if (typeof cb == "function") {cb();}layer.close(index);}});},// 封装layer.confirm(content, options, yes, cancel) - 询问框confirm: function (msg, callback) {callback = (callback != undefined) ? callback : { 'ok': null, 'cancel': null };layer.confirm(msg, {btn: ['确定', '取消']}, function (index) {//确定事件if (typeof callback.ok == "function") {callback.ok();}layer.close(index);}, function (index) {//取消事件if (typeof callback.cancel == "function") {callback.cancel();}layer.close(index);});}
};$(document).ready(function () {// 查询按钮var chatBtn = $('#chatBtn');// 查询内容var chatInput = $('#chatInput');$("#chatInput").resizable();// 中间内容var chatWindow = $('#chatWindow');// 存储对话信息,实现连续对话var messages = []// 移除加载效果function deleteLoading() {chatWindow.find('#loading').remove();}// 将 HTML 字符串转义为纯文本function escapeHtml(html) {var text = document.createTextNode(html);var div = document.createElement('div');div.appendChild(text);return div.innerHTML;}// 创建输入的文本function addLoading() {// 隐藏 “仅做技术研究探讨使用!”$(".answer .tips").css({ "display": "none" });// 输入框清空chatInput.val('');// 加载动画var messageElement = $('<div id="loading" class="row message-bubble"><img class="chat-icon" src="./static/images/chatgpt.png"><p class="message-text"><img src="./static/images/loading-1.gif" alt="加载动画"></p></div>');chatWindow.append(messageElement);}function scrollToBottom(id) {var element = document.getElementById(id);element.scrollTop = element.scrollHeight;}// 添加消息到窗口 用户跟gtp文本消息function addMessage(message, imgName) {$(".answer .tips").css({ "display": "none" });chatInput.val('');var escapedMessage = escapeHtml(message);var messageElement = $('<div class="row message-bubble"><img class="chat-icon" src="./static/images/' + imgName + '"><p class="message-text">' + escapedMessage + '</p></div>');chatWindow.append(messageElement);}// 添加消息到窗口 自定义添加消息(异常啥的)function addFailMessage(message) {$(".answer .tips").css({ "display": "none" });chatInput.val('');var messageElement = $('<div class="row message-bubble"><img class="chat-icon" src="./static/images/chatgpt.png"><p class="message-text">' + message + '</p></div>');chatWindow.append(messageElement);}// 处理用户输入chatBtn.click(function () {// 解绑键盘事件 回车之后解绑,防止未获得结果时 又发一个请求chatInput.off("keydown", handleEnter);// 保存api key与对话数据var data = {"apiKey": "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", // 这里填写固定 apiKey}// 判断是否使用自己的api keyif ($(".key .ipt-1").prop("checked")) {var apiKey = $(".key .ipt-2").val();if (apiKey.length < 20) {common_ops.alert("请输入正确的 api key !", function () {chatInput.val('');// 重新绑定键盘事件chatInput.on("keydown", handleEnter);})return} else {data.apiKey = apiKey}}var message = chatInput.val();if (message.length == 0) {common_ops.alert("请输入内容!", function () {chatInput.val('');// 重新绑定键盘事件chatInput.on("keydown", handleEnter);})return}// 创建用户对话行addMessage(message, "avatar.png");// 将用户消息保存到数组messages.push({ "role": "user", "content": message })// 收到回复前让按钮不可点击chatBtn.attr('disabled', true)data.prompt = messages// 出现loading动画addLoading();// 发送信息到后台$.ajax({url: 'https://open.aiproxy.xyz/v1/chat/completions',method: 'POST',headers: {'Content-Type': 'application/json','Authorization': 'Bearer ' + data.apiKey},data: JSON.stringify({"messages": data.prompt,"model": "gpt-3.5-turbo","max_tokens": 2048,"temperature": 0.5,"top_p": 1,"n": 1}),success: function (res) {const resp = res["choices"][0]["message"];// 创建回复对话行addMessage(resp.content, "chatgpt.png");// 收到回复,让按钮可点击chatBtn.attr('disabled', false)// 重新绑定键盘事件chatInput.on("keydown", handleEnter);// 去除loading动画deleteLoading()// 将回复添加到数组messages.push(resp)},error: function (jqXHR, textStatus, errorThrown) {// 去除loading动画deleteLoading()addFailMessage('<span style="color:red;">' + '出错啦!请稍后再试!' + '</span>');chatBtn.attr('disabled', false)chatInput.on("keydown", handleEnter);messages.pop() // 失败就让用户输入信息从数组删除}});});// Enter键盘事件function handleEnter(e) {if (e.keyCode == 13) {chatBtn.click();}}// 绑定Enter键盘事件chatInput.on("keydown", handleEnter);// 禁用右键菜单document.addEventListener('contextmenu',function(e){e.preventDefault();  // 阻止默认事件});// 禁止键盘F12键document.addEventListener('keydown',function(e){if(e.key == 'F12'){e.preventDefault(); // 如果按下键F12,阻止事件}});
});

现在请求到数据之后是一下子全部显示,纯前端如何实现一字一字输出的打字效果呢?

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="referrer" content="no-referrer" /><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>打字效果</title><style>#output {display: inline;}.cursor {display: inline-block;width: 10px;height: 20px;background-color: black;vertical-align: text-bottom;animation: blink 1s infinite;}@keyframes blink {50% {opacity: 0;}}</style>
</head><body><h1>ChatGPT Typing Effect</h1><div id="output"></div><span class="cursor" id="cursor"></span><div id="givenText" style="display: none;"><strong>加粗文本</strong><br><em>斜体文本</em><br><u>下划线文本</u><br><span style="color: red;">红色文本</span><br><span style="font-size: 24px;">大字体文本</span><br><a href="https://github.com/azhu021/">链接示例</a></div><script>const outputElement = document.getElementById("output");const cursorElement = document.getElementById("cursor");const givenTextElement = document.getElementById("givenText");const givenText = givenTextElement.innerHTML;let currentIndex = 0;let currentHTML = "";function typeText() {if (currentIndex < givenText.length) {const currentChar = givenText.charAt(currentIndex);if (currentChar === "<") {const closingTagIndex = givenText.indexOf(">", currentIndex);currentHTML += givenText.slice(currentIndex, closingTagIndex + 1);currentIndex = closingTagIndex + 1;} else {currentHTML += currentChar;currentIndex++;}outputElement.innerHTML = currentHTML;setTimeout(typeText, 100); // 设置打字速度,单位为毫秒} else {// 当打印完成时,移除光标的闪烁效果cursorElement.classList.remove("cursor");}}typeText();</script>
</body></html>

将其效果移植到custom.js中

//XXXXXXXXXXXXXXXXXXXXXXXXlet currentIndex = 0;let currentHTML = "";function addMessageTwo(id, message) {if (currentIndex < message.length) {currentHTML = ''currentHTML += message.slice(0, currentIndex + 1);$(`#${id}`).text(currentHTML)currentIndex++setTimeout(() => addMessageTwo(id, message), 100);} else {currentIndex = 0}}// 处理用户输入chatBtn.click(function () {//XXXXXXXXXXXXXXXXXXXXXXXX// 发送信息到后台$.ajax({url: 'https://open.aiproxy.xyz/v1/chat/completions',method: 'POST',headers: {'Content-Type': 'application/json','Authorization': 'Bearer ' + data.apiKey},data: JSON.stringify({//XXXXXXXXXXXXXXXXXXXXXXXX}),success: function (res) {const resp = res["choices"][0]["message"];// 创建回复对话行// addMessage(resp.content, "chatgpt.png");$(".answer .tips").css({ "display": "none" });chatInput.val('');var escapedMessage = escapeHtml(resp.content);var messageElement = $('<div class="row message-bubble"><img class="chat-icon" src="./static/images/chatgpt.png"><p id=' + res["id"] + ' class="message-text"></p></div>');chatWindow.append(messageElement);addMessageTwo(res["id"], escapedMessage)//XXXXXXXXXXXXXXXXXXXXXXXX},});});//XXXXXXXXXXXXXXXXXXXXXXXX

上述通过前端的js实现一字一字打字输出效果,但还有问题:请求完获取数据之后才开始一字一字输出,如何返回的文本过长 需要等待很久,显然这种方式不行,那有没有那种实时的逐字输出呢? SSE

SSE(Sever-sent Events) 

服务器发送事件(Server-sent Events,简称 SSE)是一种在客户端浏览器和服务器之间进行单向通信的 Web 技术。它允许服务器向客户端推送数据,而不需要客户端主动请求。

SSE(Server-sent Events)和 WebSocket 的区别

单向 vs 双向通信

  • SSE 是一种单向通信机制,只能服务器向客户端发送数据。客户端无法主动向服务器发送消息。
  • WebSocket 是一种双向通信机制,允许客户端和服务器之间进行双向实时通信。客户端和服务器都可以主动发送和接收消息。

连接建立

  • SSE 基于传统的 HTTP 协议,连接通过 HTTP 请求建立,并保持长时间打开。因此,SSE 连接始终由客户端发起。
  • WebSocket 是一种独立的协议,它在创建连接时需要使用特殊的 WebSocket 握手协议。WebSocket 连接可以由客户端或服务器发起。

数据格式

  • SSE 使用简单的文本格式或者 JSON 格式来传输数据。服务器以文本块的形式将数据发送给客户端。
  • WebSocket 可以传输任意格式的数据,例如文本、二进制数据等。

app.js

const express = require('express');
const app = express()
const router = express.Router();app.use((req, res, next) => {res.setHeader('Access-Control-Allow-Origin', '*');res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');next();
});router.get('/sse', (req, res) => {res.setHeader('Content-Type', 'text/event-stream');res.setHeader('Cache-Control', 'no-cache');res.setHeader('Connection', 'keep-alive');const answer = '众所周知,ChatGPT API 是一个OpenAI 的聊天机器人接口,它可以根据用户的输入生成智能的回复,为了提高聊天的流畅性和响应速度,采用流失输出的响应方式,类似打字机的呈现效果';let i = 0;const intervalId = setInterval(() => {res.write('data:' + answer[i] + '\n\n');i++;if (i == answer.length) {clearInterval(intervalId);res.write('event:end\ndata: \n\n');  }}, 100);
});
app.use('/', router)
app.listen(3333, function () {console.log('api server running at http://127.0.0.1:3333')
})  

index.html

<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<meta name="referrer" content="no-referrer" /><head><title>SSE Example</title>
</head><body><h1>SSE Example</h1><button id="startButton">开始</button><div id="output">回答:</div><script>const startButton = document.getElementById('startButton');const outputElement = document.getElementById('output');startButton.addEventListener('click', function () {let eventSource = new EventSource('http://172.21.2.52:3333/sse');eventSource.onopen = function (event) {console.log('成功')};eventSource.onmessage = function (event) {const message = event.data;outputElement.innerHTML += message;};});</script>
</body></html>

效果图:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/67926.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux下的系统编程——文件与目录操作(六)

前言&#xff1a; 在Linux系统中&#xff0c;文件和目录的操作非常灵活。用户可以通过命令行或者图形界面来进行操作。下面是Linux文件和目录操作的一些常见操作&#xff1a; 目录 一、文件系统 1.inode 2.dentry 二、文件操作 1.stat/lstat&#xff1a; 2.link/unlink…

OpenCV:实现图像的负片

负片 负片是摄影中会经常接触到的一个词语&#xff0c;在最早的胶卷照片冲印中是指经曝光和显影加工后得到的影像。负片操作在很多图像处理软件中也叫反色&#xff0c;其明暗与原图像相反&#xff0c;其色彩则为原图像的补色。例如&#xff0c;颜色值A与颜色值B互为补色&#…

2.5 PE结构:导入表详细解析

导入表&#xff08;Import Table&#xff09;是Windows可执行文件中的一部分&#xff0c;它记录了程序所需调用的外部函数&#xff08;或API&#xff09;的名称&#xff0c;以及这些函数在哪些动态链接库&#xff08;DLL&#xff09;中可以找到。在Win32编程中我们会经常用到导…

【MySQL】MySQL 慢SQL如何避险

我们在日常开发中&#xff0c;一定遇见过某些SQL执行较慢的情况&#xff0c;我们俗称“慢SQL”&#xff0c;如果你对系统的接口性能要求较高的话&#xff0c;一定不会放过这种SQL&#xff0c;肯定会想办法进行解决&#xff0c;那么&#xff0c;导致慢 SQL 出现的原因&#xff0…

ref 操作 React 定时器

秒表 需要将 interval ID 保存在 ref 中&#xff0c;以便在需要时能够清除计时器。 import { useRef, useState } from "react";const SecondWatch () > {const [startTime, setStartTime] useState<any>(null);const [now, setNow] useState<any>…

【python爬虫】9.带着小饼干登录(cookies)

文章目录 前言项目&#xff1a;发表博客评论post请求 cookies及其用法session及其用法存储cookies读取cookies复习 前言 第1-8关我们学习的是爬虫最为基础的知识&#xff0c;从第9关开始&#xff0c;我们正式打开爬虫的进阶之门&#xff0c;学习爬虫更多的精进知识。 在前面几…

unity 之 如何获取父物体与子物体

文章目录 获取父物体获取子物体 获取父物体 在Unity中&#xff0c;你可以使用Transform组件的属性来获取对象的父物体。以下是在C#脚本中如何获取父物体的示例代码&#xff1a; using UnityEngine;public class GetParentExample : MonoBehaviour {void Start(){// 获取当前物…

【OpenCV实战】4.OpenCV 五种滤波使用实战(均值、盒状、中值、高斯、双边)

OpenCV 五种滤波使用实战(均值、盒状、中值、高斯、双边&#xff09; 〇、Coding实战内容一、滤波、核和卷积1.1 滤波1.2 核 & 滤波器1.3 公式1.4 例子 二、图片边界填充实战2.1 解决问题2.2 相关OpenCV函数2.3 Code 三. 均值滤波实战3.1 理论3.2 Blur3.3 Code 四. 盒状滤波…

南方科技大学博士研究生奖助学金,深圳大学

目录 南方科技大学 中南大学 南京大学 厦门大学 苏州大学 中南财经政法大学 深圳大学 南方科技大学 https://ocean.sustech.edu.cn/ocean/public/upload/download/3/2.pdf 南方科技大学的在读研究生&#xff0c;每人每年都会得到40000元的补助&#xff0c;这40000块钱分…

Flink中RPC实现原理简介

前提知识 Akka是一套可扩展、弹性和快速的系统&#xff0c;为此Flink基于Akka实现了一套内部的RPC通信框架&#xff1b;为此先对Akka进行了解 Akka Akka是使用Scala语言编写的库&#xff0c;基于Actor模型提供一个用于构建可扩展、弹性、快速响应的系统&#xff1b;并被应用…

Servlet属性、监听者和会话

没有servlet能单独存在。在当前的现代Web应用中&#xff0c;许多组件都是在一起协作共同完成一个目标。怎么让这些组件共享信息&#xff1f;如何隐藏信息&#xff1f;怎样让信息做到线程安全&#xff1f; 1 属性和监听者 1.1 初始化 容器初始化一个servlet时&#xff0c;会为…

LeetCode--HOT100题(47)

目录 题目描述&#xff1a;105. 从前序与中序遍历序列构造二叉树&#xff08;中等&#xff09;题目接口解题思路代码 PS: 题目描述&#xff1a;105. 从前序与中序遍历序列构造二叉树&#xff08;中等&#xff09; 给定两个整数数组 preorder 和 inorder &#xff0c;其中 preo…

基于Vgg-Unet模型自动驾驶场景检测

1.VGG VGG全称是Visual Geometry Group属于牛津大学科学工程系&#xff0c;其发布了一些列以VGG开头的卷积网络模型&#xff0c;可以应用在人脸识别、图像分类等方面,VGG的输入被设置为大小为224x244的RGB图像。为训练集图像上的所有图像计算平均RGB值&#xff0c;然后将该图像…

系统错误码指示确立+日志模块手动配置

1&#xff0c;系统错误码指示确立 对于前后端分离的系统设计中&#xff0c;后端建立错误码指示对于前端非常重要可以指示错误存在地方&#xff1b;以用户注册为例&#xff1b; public interface SystemCode{int SYSTEM_USER_ERROR_ADD_FAIL 10000;int SYSTEM_USER_INFO_ADD …

Miniconda3环境迁移

问题&#xff1a; conda之前安装的默认路径空间满了没法进行安装&#xff0c;为此将其进行迁移&#xff0c;但是迁移之后报错 bash: /data/anaconda3/bin/conda: /home/anaconda3/bin/python: 坏的解释器: 没有那个文件或目录解决方案&#xff1a; 1、修改~/.bashrc中的环境…

B093-springsecurity整合jwt和RSA

目录 前后端分离后springsecurity核心filter的应用场景介绍JWT令牌的组成部分JWT案例导包TestJwt RSARsaUtilsTestRSA分析图 JWTRSA导包JwtUtilsTestRSAJWT 完善spring-security整合后且不连数据库的代码案例流程分析图 前后端分离后springsecurity核心filter的应用场景介绍 账…

Java设计模式:四、行为型模式-09:模板模式

文章目录 一、定义&#xff1a;模板模式二、模拟场景&#xff1a;模板模式三、改善代码&#xff1a;模板模式3.0 引入依赖3.1 工程结构3.2 模板模式结构图3.3 爬取商品生成海报实现3.3.1 HTTP获取连接类3.3.2 定义执行顺序的抽象类3.3.3 当当爬取抽象实现类3.3.4 京东爬取抽象实…

分享2款微课录制软件,保证让你满意!

“录微课用什么软件呀&#xff0c;真的服了&#xff0c;平台自带的录屏画质太差了&#xff0c;完全看不清讲的内容&#xff0c;而且音质也不是很好&#xff0c;大家有没有微课录制的软件推荐&#xff0c;谢谢啦” 随着教育方式的转型和技术的发展&#xff0c;微课程成为了一种…

422规范详解

概述&#xff1a; 全称为EIA-TIA-422-B&#xff0c;于1994年发布。 典型电路由一个发送器和N个接收器以及一个中断匹配电阻组成。 发送器&#xff1a; 差分输出电压值在2V~10V之间。 4.1.1 发送器输出阻抗 要求A/B之间的差分阻抗≤100Ω。 4.1.2 开路特性 要求差分电压≤…

从过滤器初识责任链设计模式

下面用的过滤器都是注解方式 可以使用非注解方式,就是去web.xml配置映射关系 上面程序的执行输出是 再加一个过滤器 下面来看一段程序 输出结果 和过滤器是否非常相识 但是上面这段程序存在的问题:在编译阶段已经完全确定了调用关系,如果你想改变他们的调用顺序或者继续添加一…