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

postman测试gtp接口

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

【gtp&JavaScript】使用JavaScript实现套壳gtp与gtp打字输出效果_第1张图片

导入到postman中

【gtp&JavaScript】使用JavaScript实现套壳gtp与gtp打字输出效果_第2张图片

记得弄一个gtp的key

【gtp&JavaScript】使用JavaScript实现套壳gtp与gtp打字输出效果_第3张图片

然后请求测试gtp接口:

【gtp&JavaScript】使用JavaScript实现套壳gtp与gtp打字输出效果_第4张图片

纯前端实现gtp请求页面 

【gtp&JavaScript】使用JavaScript实现套壳gtp与gtp打字输出效果_第5张图片

目录结构:

 【gtp&JavaScript】使用JavaScript实现套壳gtp与gtp打字输出效果_第6张图片

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

 index.html





  

  
  
  
  
  
  
  
  
  ac-chat
  



  

ChatGTP

仅做技术研究探讨使用!

“抢走工作的不会是AI,而是率先掌握AI能力的人”

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 = $('

加载动画

'); 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 = $('

' + escapedMessage + '

'); chatWindow.append(messageElement); } // 添加消息到窗口 自定义添加消息(异常啥的) function addFailMessage(message) { $(".answer .tips").css({ "display": "none" }); chatInput.val(''); var messageElement = $('

' + message + '

'); chatWindow.append(messageElement); } // 处理用户输入 chatBtn.click(function () { // 解绑键盘事件 回车之后解绑,防止未获得结果时 又发一个请求 chatInput.off("keydown", handleEnter); // 保存api key与对话数据 var data = { "apiKey": "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", // 这里填写固定 apiKey } // 判断是否使用自己的api key if ($(".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('' + '出错啦!请稍后再试!' + ''); 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,阻止事件 } }); });

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





    
    

    
    打字效果
    



    

ChatGPT Typing Effect

【gtp&JavaScript】使用JavaScript实现套壳gtp与gtp打字输出效果_第7张图片

将其效果移植到custom.js中

//XXXXXXXXXXXXXXXXXXXXXXXX

  let 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 = $('

'); 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







    SSE Example



    

SSE Example

回答:

效果图:

【gtp&JavaScript】使用JavaScript实现套壳gtp与gtp打字输出效果_第8张图片

你可能感兴趣的:(Javascript与ES6~,javascript,前端,gtp)