当前位置: 首页 > wzjs >正文

企业网站后台管理系统模板app引流推广软件

企业网站后台管理系统模板,app引流推广软件,网站开发如何验证,搜索广告推广摘要 这是本系列文章的第二篇,开始之前我们先回顾一下上一篇文章的内容: 从零实现一个GPT 【React Express】— 【1】初始化前后端项目,实现模型接入SSE 在这一篇中,我们主要创建了前端工程和后端工程,这里贴一下我…

摘要

这是本系列文章的第二篇,开始之前我们先回顾一下上一篇文章的内容:

从零实现一个GPT 【React + Express】— 【1】初始化前后端项目,实现模型接入+SSE

在这一篇中,我们主要创建了前端工程和后端工程,这里贴一下我的github地址:

https://github.com/TeacherXin/gpt-xin
https://github.com/TeacherXin/gpt-xin-server

最后我们实现了前端和后端部分的SSE内容,可以通过前端发送query,后端调用gpt模型通过流试返回内容。

而在这一篇中,我们主要把对话部分给实现出来,就是通过后端返回的内容来渲染对话流。

对话流的数据结构

首先我们来到前端项目,肯定是在components下创建一个DialogCardList组件,用来展示对话。

读者可以先在豆包上发送个对话试一下,可以看到对话区域主要是通过问答对的结构展示的。就是一问一答。

所以我们很容易就能设计出来,这个对话列表的数据结构应该是一个List,List下的每一个对象包含着,id,answer,question三个属性。

所以我们可以设计一下DialogCardList组件的store:

import { create } from 'zustand';interface DialogCard {question: string;answer: string;cardId: string;
}interface DialogCardListStore {sessionId: string;setSessionId: (id: string) => void;dialogCardList: DialogCard[];addDialogCard: (card: DialogCard) => void;changeLastAnswer: (question: string) => void;changeLastId: (id: string) => void;
}export const useDialogCardListStore = create<DialogCardListStore>((set) => ({sessionId: '',setSessionId: (id: string) => set(() => ({ sessionId: id })),dialogCardList: [],addDialogCard: (card: DialogCard) => set((state) => ({dialogCardList: [...state.dialogCardList, card],})),changeLastAnswer: (answer: string) => set((state) => {const dialogCard = state.dialogCardList[state.dialogCardList.length - 1];if (dialogCard) {dialogCard.answer += answer;}return { dialogCardList: [...state.dialogCardList] };}),changeLastId: (id: string) => set((state) => {const dialogCard = state.dialogCardList[state.dialogCardList.length - 1];if (dialogCard) {dialogCard.cardId = id;}return { dialogCardList: [...state.dialogCardList] };}),}));

dialogCardList就是代表每个问答对组成的列表;

changeLastAnswer方法主要是用来修改最后一个card的answer,这里是因为sse返回内容是流试的。所以我们要不停的更新最后一个节点的回答。

后端添加major事件

刚才我们说到,每个对话的card都有三个属性,id,question,answer,那id是从哪里来的呢,肯定是后端返回的。

后端可以在每次返回模型输出内容之前,先返回一个id。但是这个id肯定不能是message类型的,所以,我们可以在major事件里返回对应的id。

在getChat方法中,在for循环之前先发送一个major消息:

const eventName = 'major';
res.write(`event: ${eventName}\n`);
res.write(`data: ${JSON.stringify({id: Date.now()})}\n\n`);

这样我们再看一下接口的返回:

在这里插入图片描述

可以看到在SSE中会先返回一个major类型的消息。

本篇章里server端的内容就三行代码的修改,
具体的提交可以查看:

https://github.com/TeacherXin/gpt-xin-server/commit/1ecc36ceb29acec888df48102ec64edf0c3c676f

实现前端对话流

现在我们已经有了对话流的数据结构,现在我们来想一下流程应该是什么样子的。

最开始肯定是在输入框里面输入内容然后发送调用chat接口了,然后服务端通过SSE返回消息内容。

我们现在有三个回调,major,message,close。这三个函数调用的时机是什么,函数需要做什么呢。我们就来模拟整个流程来讲解。

【第一步】发送消息

给dialogCardList添加一个问答对,不过这个时候只有一个question,接口还没有返回。所以answer和cardId应该为空

const data = {message: inputStore.inputValue,
};dialogCardListStore.addDialogCard({question: inputStore.inputValue,answer: '',cardId: '',
});inputStore.setInputValue('');
inputStore.setInputLoading(true);

【第二步】设置三种事件类型的回调

const url = 'http://localhost:3002/chat';const messageCallback = (message: Message) => {dialogCardListStore.changeLastAnswer(message.content);
};const closeCallback = () => {inputStore.setInputLoading(false);
};const majorCallback = (major: Major) => {dialogCardListStore.changeLastId(major.id);
};connectSSE(url, data, {message: messageCallback,major: majorCallback,close: closeCallback,
});

我们需要在messageCallback,不停的更新dialogCardList中,最后一个card的answer。
在majorCallback中,更新最后一个card的id
在closeCallback中,更新一下输入框的loading状态。
然后传给connectSSE方法即可。

【第三步】实现DialogCardList组件

有了数据结构以及更新流程之后,我们就可以实现DialogCardList组件了:

const DialogCardList: React.FunctionComponent = () => {const dialogCardListStore = useDialogCardListStore();return (<div className={styles.scrollContainer}><div className={styles.dialogCardList}>{dialogCardListStore.dialogCardList.map((item) => {return (<div className={styles.dialogCard} key={item.cardId}><div className={styles.question}><p>{item.question}</p></div><div className={styles.answer}>{item.answer}</div></div>);})}</div></div>);
};

只需要遍历dialogCardList把对应的问答对展示出来即可,CSS的样式这里我就不写了,可以直接看我的提交记录(贴在后面了)。

最终我们就可以通过发送query实现对话功能了,这里展示一下效果:

请添加图片描述

停止生成

现在我们发送完对话,如何停止生成,让这个对话结束呢。

其实我们只需要把SSE的请求取消即可,回到我们的sse.ts中,在最外层定义个abortController

let abortController = new AbortController();

然后修改connectSSE方法,把abortController传给fetch请求:

const res = await fetch(url, {headers: {'Content-Type': 'application/json', // 必须设置Accept: 'text/event-stream','Cache-Control': 'no-cache',},method: 'POST',body: JSON.stringify(params),signal: abortController.signal, // 用于取消请求});

最后再实现一个stopSSE方法,这里注意一下,每次停止生成都要生成一个新的AbortController,因为下次发送fetch请求不能用之前的AbortController,不然所有的请求都发不出去了:

const stopSSE = () => {abortController.abort(); // 取消 fetch 请求abortController = new AbortController();
}

当inputLoading为true的时候,点击按钮就停止生成。

前端部分在这一篇的内容也就实现完了,具体的代码变更可以看下面的提交记录:
https://github.com/TeacherXin/gpt-xin/commit/6cb2c719cce51ae9cd6af92cad1283de41c485c9

http://www.dtcms.com/wzjs/471468.html

相关文章:

  • 深圳美食教学网站制作seo 重庆
  • 做淘宝banner的网站网上商城网站开发
  • python怎么搭建网站站长之家ip地址查询
  • 苏州做网站的单位如何建立一个自己的网站啊
  • 网站建设洛阳seo词条
  • 织梦手机网站模板安装seo怎么推排名
  • 温州做网站掌熊号全媒体广告投放平台
  • 教学网站开发应用指导方案搜索网站排行
  • 郑州网站建设公司制作定制百度收录查询方法
  • 自己网站如何做关键词公司官网制作多少钱
  • 合肥高新城创建设投资有限公司网站房管局备案查询网站
  • 网站策划的知识站长之家
  • 龙华三网合一网站建设seo在线短视频发布页运营
  • 青岛开发区网站建设服务跟我学seo
  • wordpress 公众号登录seo排名影响因素主要有
  • 公司建设网站网络营销成功案例有哪些
  • ecshop 网站首页不显示怎么办苹果cms永久免费建站程序
  • 做1个自己的贷款网站新浪疫情实时数据
  • 建设网站包括哪些费用网络营销名词解释答案
  • wordpress打包成appseo技术外包 乐云践新专家
  • 那些网站专门做游戏辅助的拉新app推广接单平台
  • 网站制作应该注意到的问题帮人推广注册app的平台
  • wordpress微信注册登录南京seo公司
  • 什么网站专做韩国美妆批发的免费网站收录入口
  • 做房产网站有哪些怎么在百度上发布个人文章
  • 东营两学一做网站软文推广公司
  • 做球服的网站有哪些长沙疫情最新情况
  • 长沙招聘网站网店怎么推广和宣传
  • 天津微信网站建设廊坊seo外包公司费用
  • 青阳网站建设日本粉色iphone