0


【流式输出,前端如何接收】【模拟打字机打印效果】

解决流式输出接口获取数据后,模拟打印效果
技术:vue js

setTimeOut和setInterval都不好用,因为流式输出的时间是不稳定的,导致打出的字容易乱序,

尝试多种方案后寻到如下方案:这是文心一言给的方案, 靠谱咱就是说。

<template><div><button @click="startPrinting">开始打印</button><p>{{ currentChar }}</p></div></template><script>classQueue{constructor(){this.items =[];}// 入队操作  enqueue(element){this.items.push(element);}// 出队操作并返回元素  dequeue(){if(this.isEmpty()){returnnull;}returnthis.items.shift();}// 检查队列是否为空  isEmpty(){returnthis.items.length ===0;}}exportdefault{data(){return{queue:newQueue(),text:"Hello, Vue.js!",currentChar:'',printingInterval:null,};},methods:{startPrinting(){// 停止之前的打印(如果有的话)  if(this.printingInterval){clearInterval(this.printingInterval);}// 清空当前字符和队列  this.currentChar ='';this.queue.items =[];// 将字符串的每个字符入队  for(let char ofthis.text){this.queue.enqueue(char);}// 开始打印  this.printingInterval =setInterval(()=>{const char =this.queue.dequeue();if(char){this.currentChar = char;}else{// 队列为空,停止打印  clearInterval(this.printingInterval);this.printingInterval =null;}},500);// 例如,每500毫秒打印一个字符  },},beforeDestroy(){// 在组件销毁前停止打印  if(this.printingInterval){clearInterval(this.printingInterval);}},};</script>

顺便提一下,模拟光标闪烁的css

::v-deep .shink_cursor {display: inline-block;width: 2px;height: 14px;
  margin-bottom:-2px;
  background-color: black;animation: blink 1s infinite;
  @keyframes blink {0%{opacity:1;}50%{opacity:0;}100%{opacity:1;}}}

再附上流式接口调用代码:

// 流式对话// repeat 重新生成newChat(repeat =false){let clientId =this.chatUuid;this.flowMessage ={};//置空流式对话信息if(window.EventSource){this.eventSource =newEventSource("/base/business/api/v1/stream/connect?clientId="+ clientId
        );this.eventSource.onmessage=(event)=>{
          console.log("onmessage: "+ event.data);const dataJson =JSON.parse(event.data);if(dataJson.code ==200){if(dataJson.is_end ==="true"){this.eventSource.close();this.sendLoading =false;this.$store.dispatch("user/getInfo");// 刷新历史列表this.$EventBus.$emit("refreshHistory");
              console.log("flowMessage: ",this.flowMessage);}this.showFlowText(dataJson, repeat);}else{this.delErrMsg(dataJson.msg);this.sendLoading =false;}};this.eventSource.onopen=(event)=>{
          console.log("onopen:"+ event);};this.eventSource.onerror=(event)=>{
          console.log("onerror:"+ event,this.eventSource);
          console.log("对话中途中断~");};this.eventSource.close=(event)=>{
          console.log("close :"+ event);this.sendLoading =false;};}else{
        console.log("你的浏览器不支持SSE~");}
      console.log(" 测试 打印");},// 假设这是你的流式数据获取函数// repeat 重新生成fetchData(repeat =false){let history =[];let question =this.sendMsg;if(!repeat){//   新问题if(!this.sendMsg.trim()){this.$message.warning("请输入问题");return;}const newDailogContent =[{role:"user",content:this.sendMsg,},];this.chatInfos =this.chatInfos.concat(newDailogContent);
        history =[...this.chatInfos];}else{//   重新回答this.chatInfos[this.chatInfos.length -1].content ="";
        history =this.chatInfos.slice(0,-1);const len = history.length;
        question = history[len -1].content;}if(history.length >19){//   限制上下文长度
        history = history.slice(history.length -19, history.length);}// 开启流式对话this.newChat(repeat);this.sendLoading =true;// 使用 Fetch API 发送带参数的 POST 请求const data ={clientId:this.chatUuid,
        question,
        history,regen: repeat ?2:1,//是否重新生成 1-正常,2-重新生成};chatFetchToServe(data)// .then((response) => response.text()) // 将响应体转为文本.then((response)=>{// 检查响应是否成功if(!response.ok){thrownewError("网络请求失败");}//   // 创建一个阅读器来读取流式数据//   const reader = response.body.getReader();//   const dataContainer = document.getElementById('data-container');//   // 定义一个函数来处理数据流中的文本片段//   function handleTextFragment (fragment) {//     const textNode = document.createTextNode(fragment);//     dataContainer.appendChild(textNode);//   }//   // 定义一个函数来处理数据流中的完成事件//   function handleDone () {//     dataContainer.appendChild(document.createElement('br'));//     console.log('数据流已接收完毕');//   }//   // 定义一个函数来处理数据流中的错误事件//   function handleError (error) {//     console.error('数据流处理出错:', error);//   }//   // 使用ReadableStream的getReader方法获取阅读器//   const stream = response.body.getReader();//   // 循环处理数据流中的文本片段//   stream.read().then(({ done, value }) => {//     if (done) {//       handleDone();//     } else {//       handleTextFragment(value);//       stream.releaseLock();//     }//   }).catch(handleError);}).catch((error)=>{
          console.error("请求流式数据失败:", error);});this.sendMsg ="";},
标签: vue

本文转载自: https://blog.csdn.net/weixin_46139439/article/details/139011677
版权归原作者 艾玛钓到一只猫 所有, 如有侵权,请联系我们删除。

“【流式输出,前端如何接收】【模拟打字机打印效果】”的评论:

还没有评论