首页 > 其他分享 >图文并茂手把手教你基于React多种方案使用实现ChatGPT打字机效果

图文并茂手把手教你基于React多种方案使用实现ChatGPT打字机效果

时间:2023-11-12 22:05:09浏览次数:38  
标签:body console 图文并茂 value React done const ChatGPT log

代码仓库

前期准备

  • 前端项目
  • 后端接口(OpenAI接口即可)

启动一个新的 React 项目

  • 如果小伙伴们有现有项目,可跳过此步骤直接进入下一步~
  • Next.js 是一个全栈式的 React 框架。它用途广泛,可以让你创建任意规模的 React 应用——可以是静态博客,也可以是复杂的动态应用。要创建一个新的 Next.js 项目,请在你的终端运行:
npx create-next-app@latest

下载依赖


cd xiaojin-react-chatgpt

npm i

运行项目

npm run dev


引入 antd

安装并引入 antd

npm install antd --save

基础页面准备

  • 我们先使用简单的代码来实现效果
  • 修改src\app\page.js代码如下
"use client";
import { useState } from "react";
import { Input, Button } from "antd";

const { TextArea } = Input;
export default function Home() {
  let [outputValue, setOutputValue] = useState("");
  return (
    <main className="flex min-h-screen text-black flex-col items-center justify-between p-24">
      <h2>Chat GPT 打字机效果</h2>
      <TextArea rows={17} value={outputValue} />
      <Button>发送请求</Button>
    </main>
  );
}

页面效果如下

接口准备

  • 注册一个OpenAI账号(或者使用其他接口也可以)

接口文档示例

Chat聊天-聊天完成对象-参数说明

参数 类型 描述
id string 聊天完成的唯一标识符
choices array 聊天完成选项列表。如果n大于1,可以有多个选项
created integer 创建聊天完成的Unix时间戳(秒)
model string 用于聊天完成的模型
system_fingerprint string 该指纹表示模型运行的后端配置
object string 对象类型,总是 chat.completion
usage object 完成请求的使用统计信息
completion_tokens integer 生成的完成中的标记数
prompt_tokens integer 提示中的标记数
total_tokens integer 请求中使用的标记总数(提示 + 完成)

准备接口参数

 const data = {
      model: "XXX",
      messages: [
        {
          role: "user",
          content: "写一篇1000字关于春天的作文",
        },
      ],
      prompt: "写一篇1000字关于春天的作文",
      temperature: 0.75,
      stream: true,
    };

方案1:使用fetch来处理stream流实现打字机效果

使用流的方式处理 Fetch

  • mdn文档

  • Fetch API 允许你跨网络获取资源,它提供了现代化的 API 去替代 XHR。它有一系列的优点,真正好的是,浏览器最近增加了将 fetch 响应作为可读流使用的能力。

  • Request.body 和 Response.body 属性也是这样,它们将主体内容暴露作为一个可读流的 getter。

调用代码示例

    const response = await fetch(url, {
      method: "POST",
      body: JSON.stringify(data),
      headers: {
        "Content-Type": "application/json",
      },
    });

    const reader = response.body.getReader();
    while (true) {
      const { done, value } = await reader.read();
      if (done) {
        console.log("***********************done");
        console.log(value);
        break;
      }
      console.log("--------------------value");
      console.log(value);
    }
  • 在函数中,我们使用 response.body.getReader() 将 reader 锁定到该流,然后遵循我们之前看到的相同的模式——使用 reader 读取每个分块,在再次运行 read() 方法之前,检查 done 是否为 true,如果是 true,处理结束,如果是 false,读取下一个分块并且处理它。
  • 通过循环获取传输的数据

编写页面逻辑代码

  • 我们暂时使用固定参数来进行模拟
  • 写一个简单的demo来演示
"use client";
import { useState } from "react";
import { Input, Button } from "antd";
const { TextArea } = Input;
export default function Home() {
  let [outputValue, setOutputValue] = useState("");
  const send = async () => {
    const url = "http://10.169.112.194:7100/v1/chat/completions";
    const data = {
      model: "chatglm2-6b",
      messages: [
        {
          role: "user",
          content: "写一篇1000字关于春天的作文",
        },
      ],
      prompt: "写一篇1000字关于春天的作文",
      temperature: 0.75,
      stream: true,
    };
    const response = await fetch(url, {
      method: "POST",
      body: JSON.stringify(data),
      headers: {
        "Content-Type": "application/json",
      },
    });

    const reader = response.body.getReader();
    while (true) {
      const { done, value } = await reader.read();
      if (done) {
        console.log("***********************done");
        console.log(value);
        break;
      }
      console.log("--------------------value");
      console.log(value);
    }
  };
  return (
    <main className="flex min-h-screen text-black flex-col items-center justify-between p-24">
      <h2>Chat GPT 打字机效果</h2>
      <TextArea rows={17} value={outputValue} />
      <Button onClick={send}>发送请求</Button>
    </main>
  );
}

点击按钮查看打印结果

  • 我们可以看到打印出来的都是buffer字符串,我们需要对其进行解析才可以得知最终结果

解析buffer

const encode = new TextDecoder("utf-8");
const reader = response.body.getReader();
 while (true) {
      const { done, value } = await reader.read();
      const text = encode.decode(value);
      if (done) {
        console.log("***********************done");
        console.log(text);
        break;
      }
      console.log("--------------------value");
      console.log(text);
    }

查看解析

我们可以看到解析结果格式如下

data: {"id": "chatcmpl-3zmRJUd4TTpm9xP9NbQVHw", "model": "chatglm2-6b", "choices": [{"index": 0, "delta": {"content": "希望"}, "finish_reason": null}]}

使用正则解析数据

我们编写一个函数~~然后打印数据

 const getReaderText = (str) => {
    // 定义正则表达式匹配模式
    let result = str.match(/{"content": "(\S*)"}, "finish_reason":/);
    return result && result[1] ? result[1] : "";
  };

赋值数据到文本框


解决换行问题

解决textarea显示\n但是并没有换行的问题,经过排查发现,是接口返回的数据是\n,所以渲染有异常,因此我们可以用下面的方式去解决.

replaceAll(/\\n/g,'\r\n')

初步实现简易打字机效果

代码块支持(待补充)

自动滚动(等我忙完补充)

方案2:axios请求方式(等我忙完补充)等待补充

今天就写到这里啦~

  • 小伙伴们,( ̄ω ̄( ̄ω ̄〃 ( ̄ω ̄〃)ゝ我们明天再见啦~~
  • 大家要天天开心哦

欢迎大家指出文章需要改正之处~
学无止境,合作共赢

在这里插入图片描述

欢迎路过的小哥哥小姐姐们提出更好的意见哇~~

标签:body,console,图文并茂,value,React,done,const,ChatGPT,log
From: https://www.cnblogs.com/sugartang/p/17827309.html

相关文章

  • 文心一言 VS 讯飞星火 VS chatgpt (133)-- 算法导论11.2 5题
    五、用go语言,假设将一个具有n个关键字的集合存储到一个大小为m的散列表中。试说明如果这些关键字均源于全域U,且|U|>nm,则U中还有一个大小为n的子集,其由散列到同一槽位中的所有关键字构成,使得链接法散列的查找时间最坏情况下为O(n)。文心一言:这个问题涉及到的是散列表(哈希表)的基......
  • #yyds干货盘点#react之useEffect
    React的HooksAPI为我们提供了一种新的处理副作用的方式——useEffect。useEffect函数接受两个参数:一个是_副作用函数_和一个_依赖数组_。副作用函数是在组件render之后运行,而依赖数组告诉React何时应该执行或跳过该副作用。如果没有提供依赖数组,`useEffect`将在每次渲染后运行。......
  • chatgpt的api联网报错问题解决:openai公司的api联网报错解决
    chatgpt是啥,这里不讲,openai是啥这里也不讲。要知道我们不论是通过网页web使用chatgpt还是使用api方式通过客户端使用chatgpt都是需要使用外国IP的,     ......
  • ScholarAI ChatGPT Plugin Tutorial, Use Cases & Prompts
    https://roihacks.com/scholarai-chatgpt-plugin/?utm_source=youtube&utm_medium=social&utm_campaign=scholarai-chatgpt-plugin......
  • ReactNative进阶(十):WebView 应用详解
    (文章目录)一、WebView组件介绍使用WebView组件可通过url来加载显示一个网页,也可以传入一段html代码来显示。下面对其主要属性和方法进行介绍。1.主要属性source:在WebView中载入一段静态的html代码或是一个url(还可以附带一些header选项);automaticallyAdjustCon......
  • #yyds干货盘点#react的useState源码分析
    简单说下为什么React选择函数式组件,主要是class组件比较冗余、生命周期函数写法不友好,骚写法多,functional组件更符合React编程思想等等等。更具体的可以拜读dan大神的blog。其中Functioncomponentscapturetherenderedvalues这句十分精辟的道出函数式组件的优势。但是在16.8之......
  • 【chatgpt问答记录】双端队列、栈和函数调用栈
    collections.deque和queue.Queue的区别Q:collections.deque()跟queue.Queue()有什么区别?collections.deque()和queue.Queue是两种不同的数据结构,它们有一些区别:实现方式:collections.deque()是Python标准库提供的双端队列数据结构,使用双向链表实现,具有高效的在两端进行......
  • react组件间通信
    1.父组件向子组件通信import{useState}from'react';functionButton(props){return(<div>{props.name}</div>)}functionApp(){constmsg=useState('神雕侠侣')return(<divclassName="App">&l......
  • 打工笔记-------------------------.NET Reactor使用方法
    .NETReactor是一个用于保护.NET应用程序的代码混淆器和加密器。它可以防止应用程序被反编译和篡改使用步骤下载和安装.NETReactor:从DongleSoftware的官方网站下载.NETReactor5.9.8.0的安装程序,并按照提示进行安装。创建或导入项目:在.NETReactor中,创建一个新的......
  • OpenAI重磅推出GPTs,无需编码人人可以自定ChatGPT!
    原创|文BFT机器人在11月7日深夜2点(北京时间),美国旧金山举办了首届开发者大会,该活动由AI领域的知名公司OpenAI主办。尽管这是该公司的首届大会,但其盛大的规模和影响力已将其誉为“AI春晚”。在会议上,SamAltman用了45分钟的时间发布了多款新产品,微软首席执行官SatyaNadella也亲自......