【JavaScript】fetch 处理流式数据,实现类 chatgpt 对话

本文只包含最基础的请求后端大佬给得对话接口,大部分模型的传参是差不多的,核心还是如何处理 fetch 获取的流数据

ts 复制代码
import { defineStore } from 'pinia';
import { ElMessage } from 'element-plus';

type Role = 'system' | 'user' | 'assistant';
export interface Message {
  role: Role;
  content: string;
}
interface ChatStore {
  model: 'Gnosis' | 'chatglm2-6b' | 'cc-13b-chat';
  chatApi: string;
  messages: Message[];
  done: boolean | null;
}
const DEFAULT_PROMPT = `你应该根据用户回答生成答案。答案必须尽可能简明扼要。字数控制在512个字符以内`;

export const useChatStore = defineStore({
  id: 'chatStore',
  state: (): ChatStore => {
    return {
      model: 'cc-13b-chat',
      chatApi: 'chat_api/chat/knowledge_base_chat',
      messages: [
        {
          role: 'system',
          content: DEFAULT_PROMPT,
        },
      ],
      done: null,
    };
  },
  actions: {
    async fetchChat(query: string) {
      this.messages.push({
        role: 'user',
        content: query,
      });
      let response: any = null;
      try {
        response = await fetch(this.chatApi, {
          headers: {
            'Content-Type': 'application/json',
          },
          method: 'POST',
          body: JSON.stringify({
            query: query,
            history: this.messages,
            model_name: this.model,
            stream: true,
            knowledge_base_name: 'lb_test',
            top_k: 1,
            score_threshold: 1,
            temperature: 0.7,
            max_tokens: 4096,
            prompt_name: 'default',
          }),
        });
      } catch (error) {
        console.log(error);
        ElMessage.error('请求失败');
        return;
      }
      const data = response.body;
      this.messages.push({
        role: 'assistant',
        content: '',
      });
      // 处理流式数据
      if (data) {
        const reader = data.getReader();
        const decoder = new TextDecoder('utf-8');
        this.done = false;
        while (!this.done) {
          const { value, done: readerDone } = await reader.read();
          // value值
          // {"answer": "帮助解决"}
          if (value) {
            const char = decoder.decode(value);
            console.log(char);
            // if (char === '\n') {
            //   this.messages[this.messages.length - 1].content += '\n';
            //   continue;
            // }
            if (char) {
              const res = JSON.parse(char);
              this.messages[this.messages.length - 1].content += res.answer ?? '';
            }
          }
          if (!this.done) {
            this.done = readerDone;
          }
        }
      }
      // 对话结束
      this.done = null;
    },
  },
  // persist: {
  //   key: 'store',
  //   storage: window.localStorage,
  // },
});
相关推荐
程序员-Benothing38 分钟前
如何实现高并发系统订单30分钟自动关闭?
开发语言·c#·wpf
郝学胜-神的一滴2 小时前
Python 高级编程 026:内置数据结构之骈文纵论
开发语言·数据结构·python·程序人生·软件工程
Mh8 小时前
别再只会 `find` 了:Map 在前端业务里的真实用法
前端·javascript
隐积9 小时前
3.1.7.Qt容器大家族(3):QVariant——万能盒子
开发语言·qt
kyriewen12 小时前
别再这样写TypeScript了——Code Review中最常见的8个反模式
前端·javascript·typescript
名字还没想好☜12 小时前
Next.js ‘use client‘ 到底加在哪:Server/Client Components 边界与常见报错
开发语言·前端·javascript·react·next.js
初级代码游戏13 小时前
iOS开发 Swift 速记1:变量和基本数据类型
开发语言·ios·swift
Liekkas Kono13 小时前
Codex(ChatGPT 桌面版)支持SSH连接远程服务器
chatgpt·ssh·swhl
飘尘14 小时前
一文讲清楚前端面试会问到的所有缓存
前端·javascript·面试
酷在前行14 小时前
【R生态】PERMANOVA 进阶实战:距离选择、PERMDISP、两两比较与受限置换(保姆级教程)
开发语言·r语言