• 作者:老汪软件技巧
  • 发表时间:2024-11-11 07:03
  • 浏览量:

前言废话

这两周我经历了太多,

这个想法大概两周前就有了,本来当时想写一篇博客记录一下,但是女朋友跟我分手了...

这两周悲痛欲绝,从来没有这么哭过,这种滋味太难受了 ┭┮﹏┭┮

但是在我不懈的努力下,似乎有复合的倾向,趁着今晚高兴,将这个想法记录下来,希望可以帮到其他人!

正言

最近公司做一个跨平台的app,技术使用uniapp,用到chat,需要对接sse接口。

vue使用的是v3,想查一下是否有v3的sse解决方案,查了一圈发现两种办法,renderjs 和 原生插件,因为renderjs不兼容v3,最后想用原生插件解决。

结果去uniapp插件市场花20块买了个sse原生插件不兼容ios...

同事关于v3的chat代码涉及几千行,这咋办呢。

后来我在看一个uniapp组件库源码的时候给了我灵感,可以将renderjs用v2的语法封装到一个组件里,然后将事件提供给父组件,这样就可以兼容v3和v2了,详情请看下文,

renderjsrenderjs介绍

那么renderjs是什么呢?下面是官方的解释:

image.png

emmmm,简单点说就是可以在renderjs跑js的代码。

安卓浏览器框架_浏览器组件是什么意思_

renderjs 语法


<script module="demo" lang="renderjs">
export default {
  methods: {
   hadnle(data) {
      let utf8Str = new TextEncoder().encode("Hello, World!");
      let base64Str = btoa(String.fromCharCode(...utf8Str));
      this.$ownerInstance.callMethod('receive', base64Str);
   },
  }
}
script>
<template>
  <view
    :hadnleData="hadnleData"
    :change:hadnleData="demo.hadnle"
  >
    <button @click="start">startbutton>
  view>
template>

上面是一个简单的字符串转base64代码,可以看到我们在renderjs使用了new TextEncoder(),它是一个web api,如果在app环境使用会报错:ReferenceError: TextEncoder is not defined,但是可以在renderjs正常运行。

我们可以在app环境用renderjs运行所有js库,有了以上的认识,我们只需要在renderjs使用@microsoft/fetch-event-source即可。

@microsoft/fetch-event-sources是一个由微软开发的 npm 库,它提供了一个改进的 API,用于发起 Event Source 请求,也称为服务器发送事件(Server-Sent Events)。这个库基于 Fetch API,提供了比默认浏览器 EventSource API 更多的功能。

实现代码核心组件

下面的代码非常简单,大家自己看吧


<script module="chat" lang="renderjs">
import { fetchEventSource } from '@microsoft/fetch-event-source';
export default {
  data() {
   return {
    ctrl: null,
   }
  },
  methods: {
   /**
    * 停止生成
    */
   stopChatCore() {
    this.ctrl?.abort();
   },
   /**
    * 开始对话
    */
   startChatCore({ url, body, headers }) {
    if (!url) return;
    try {
     this.ctrl = new AbortController();
     fetchEventSource(
      url,
      {
       method: 'POST',
       openWidthHidden: true,
       signal: this.ctrl.signal,
       headers: {
        "Content-Type": "application/json",
        ...headers,
       },
       body: body,
       onopen: () => {
        this.$ownerInstance.callMethod('open');
       },
       onmessage: ({ data }) => {
        this.$ownerInstance.callMethod('message', data);
       },
       onerror: (err) => {
        this.$ownerInstance.callMethod('error', err);
       },
      }).then(() => {
       this.$ownerInstance.callMethod('finish');
     }).catch(err => {
      this.$ownerInstance.callMethod('error', err);
     })
    } catch (e) {
     console.log(e);
    }
   }
  }
}
script>
<template>
  <view
   :renderjsData="renderjsData"
   :change:renderjsData="chat.startChatCore"
   :stopCount="stopCount"
   :change:stopCount="chat.stopChatCore"
  />
template>

使用demo


<script setup>
import ChatSSEClient from "../../components/gao-ChatSSEClient.vue";
import { ref } from 'vue'
const chatSSEClientRef = ref(null);
const responseText = ref("");
const loading = ref(false);
const openLoading = ref(false);
const openCore = () => {
  openLoading.value = false;
  console.log("open sse");
}
const errorCore = (err) => {
  console.log("error sse:", err);
}
const messageCore = (msg) => {
  console.log("message sse:", msg);
  responseText.value += `${msg}\n`
}
const finishCore = () => {
  console.log("finish sse")
  loading.value = false;
}
const start = () => {
  if (loading.value) return;
  openLoading.value = true;
  loading.value = true;
  responseText.value = "";
  chatSSEClientRef.value.startChat({
    // 将它换成你的地址
    url: "",
    headers: {
      authorization: "",
    },
    body: {
      "messages":[
        { "role":"user", "content": "你好!" }
      ],
      "stream":true,
      "model":"deepseek-chat",
      "temperature":1,
      "presence_penalty":0,
      "frequency_penalty":0,
      "top_p":1
    },
  })
}
const stop = () => {
  chatSSEClientRef.value.stopChat()
  console.log("stop");
}
script>

uniapp 插件

代码上传到了uniapp插件市场,有需要的同学可以去这上面下载,包含了完整demo项目。

sse 客户端组件,支持v2、v3、安卓、ios、浏览器 - DCloud 插件市场

最后,希望对大家有帮助,再见!


上一条查看详情 +Spring Boot集成Access DB实现数据导入和解析
下一条 查看详情 +没有了