Skip to content
导航栏

yao stream api 接口

适用版本

0.10.3 或以上

配置

在配置 api 接口时,在 out 节点里设置text/event-stream作为 type 字段的前缀,这个接口的服务端处理器将会使用 stream 流式处理。注意流式处理器的类型必须是 js 脚本,比如 scripts.xxx.xx。在流处理器(js 脚本中)里可以使用两个全局函数ssEvent/cancel

  • ssEvent 在服务器端脚本里向流发送数据。
  • cancel 在服务器脚本里调用,取消请求。
json
{
  "path": "/ask-stream",
  "method": "POST",
  "guard": "-",
  "process": "scripts.ai.stream.Call",
  "in": [":payload"],
  "out": {
    "status": 200,
    "type": "text/event-stream; charset=utf-8"
  }
}

流式处理器向客户端请求发送实时消息。

如果要配合浏览器的 EventSource.onmessage 事件处理,一定要是发送 ssEvent('message')事件。

js
function collect(content) {
  // 客户端会接收到事件"event:message"
  ssEvent('message', content);
  // console.log(`content:${content}`);
}

示例代码

xgen react 使用 EventSource 的示例 xgen-v1.0/packages/xgen/layouts/components/Neo/hooks/useEventStream.ts

yao-chatgpt 的 vue 使用 fetch 函数进行 api 调用示例:front-end\src\chatpgt.ts

yao-chatgpt 0.10.3 分支

sh
git clone https://github.com/wwsheng009/yao-chatgpt.git

cd yao-chatgpt && git checkout 0.10.3
js
export function post<T = any>({
  url,
  data,
  headers,
  onDownloadProgress,
}: HttpOption) {
  const p = new Promise<Response<T>>((resolve, reject) => {
    // return new Promise((resolve, reject) => {
    fetch(url, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Accept: "text/event-stream",
        "Cache-Control": "no-cache",
        Connection: "keep-alive",
        ...headers,
      },
      body: JSON.stringify({
        stream: true,
        ...data,
      }),
    })
      .then((response) => {
        const reader = response.body?.getReader();
        function readStream() {
          if (reader) {
            reader
              .read()
              .then(({ value, done }) => {
                const data = new TextDecoder().decode(value);
                // console.log(`data :${data}`);
                // console.log(`done:${done}`);
                if (!done) {
                  const lines = data.split("\n\n");
                  for (const key in lines) {
                    const line = lines[key];
                    if (line.startsWith("event:session_id\ndata:")) {
                      let sesseion_id = line.substring(
                        "event:session_id\ndata:".length
                      );
                      onDownloadProgress?.({ sesseion_id: sesseion_id });
                    } else {
                      // 有可能有nil值,还不知是哪里来的
                      if (!line.includes("event:messages")) {
                        continue;
                      }
                      let newLines = line.replace(/event:messages\n/g, "");
                      newLines = newLines.replace(/data:/g, "");
                      onDownloadProgress?.({ message: newLines });
                    }
                  }

                  return readStream();
                } else {
                  // eslint-disable-next-line no-console
                  console.log("done");
                  resolve({
                    data: { data: "" },
                    message: "",
                    status: 200,
                  } as unknown as Response<T>);
                }
              })
              .catch((error) => {
                reject(error);
              });
          }
        }
        return readStream();
      })
      .catch((error) => {
        reject(error);
      });
  });
  return p;
  // return Promise.resolve({ data: '' } as Response<T>)
}