【寄了】接力v佬,aipro流式支持(移步reno佬的真流式 https://linux.do/t/topic/65696)

V佬原贴:[世界是个炒菜班子] 自己部署免费GPT-4,https://ai-pro.org/

先感谢v佬的无私分享的精神,每次都会被这个男人感动到 :sob: :sob: :sob:

由于原api不支持流式,很多兄弟在NextChat用不了,这不流式支持就来了,cloudflare work代码如下:

addEventListener("fetch", event => {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  if (request.method === "OPTIONS") {
    return new Response(null, {
      headers: {
        'Access-Control-Allow-Origin': '*',
        "Access-Control-Allow-Headers": '*'
      }, status: 204
    })
  }
  // 确保请求是 POST 请求,并且路径正确
  if (request.method === "POST" && new URL(request.url).pathname === "/v1/chat/completions") {
    const url = 'https://multillm.ai-pro.org/api/openai-completion'; // 目标 API 地址
    const headers = new Headers(request.headers);

    // 添加或修改需要的 headers
    headers.set('Content-Type', 'application/json');

    // 获取请求的 body 并解析 JSON
    const requestBody = await request.json();
    const stream = requestBody.stream;  // 获取 stream 参数

    // 构造新的请求
    const newRequest = new Request(url, {
      method: 'POST',
      headers: headers,
      body: JSON.stringify(requestBody) // 使用修改后的 body
    });

    try {
      // 向目标 API 发送请求
      const response = await fetch(newRequest);

      // 根据 stream 参数确定响应类型
      if (stream) {
        const originalJson = await response.json(); // 一次性读取完整数据
        // 创建一个可读流
        const readableStream = new ReadableStream({
          start(controller) {
            // 发送开始数据
            const startData = createDataChunk(originalJson, "start");
            controller.enqueue(new TextEncoder().encode('data: ' + JSON.stringify(startData) + '\n\n'));

            // 假设根据 originalJson 处理并发送多个数据块
            // 例如,模拟分批次发送数据
            const content = originalJson.choices[0].message.content; // 假设这是要发送的内容
            const newData = createDataChunk(originalJson, "data", content);
            controller.enqueue(new TextEncoder().encode('data: ' + JSON.stringify(newData) + '\n\n'));

            // 发送结束数据
            const endData = createDataChunk(originalJson, "end");
            controller.enqueue(new TextEncoder().encode('data: ' + JSON.stringify(endData) + '\n\n'));

            controller.enqueue(new TextEncoder().encode('data: [DONE]'));
            // 标记流的结束
            controller.close();
          }
        });
        return new Response(readableStream, {
          headers: {
            'Access-Control-Allow-Origin': '*',
            "Access-Control-Allow-Headers": '*',
            'Content-Type': 'text/event-stream',
            'Cache-Control': 'no-cache',
            'Connection': 'keep-alive'
          }
        });
      } else {
        // 正常返回响应
        return new Response(response.body, {
          status: response.status,
          headers: response.headers
        });
      }
    } catch (e) {
      // 如果请求失败,返回错误信息
      return new Response(JSON.stringify({ error: 'Unable to reach the backend API' }), { status: 502 });
    }
  } else {
    // 如果请求方法不是 POST 或路径不正确,返回错误
    return new Response('Not found', { status: 404 });
  }
}

// 根据类型创建不同的数据块
function createDataChunk(json, type, content = {}) {
  switch (type) {
    case "start":
      return {
        id: json.id,
        object: "chat.completion.chunk",
        created: json.created,
        model: json.model,
        choices: [{ delta: {}, index: 0, finish_reason: null }]
      };
    case "data":
      return {
        id: json.id,
        object: "chat.completion.chunk",
        created: json.created,
        model: json.model,
        choices: [{ delta: { content }, index: 0, finish_reason: null }]
      };
    case "end":
      return {
        id: json.id,
        object: "chat.completion.chunk",
        created: json.created,
        model: json.model,
        choices: [{ delta: {}, index: 0, finish_reason: 'stop' }]
      };
    default:
      return {};
  }
}

说明:该流式api不是真正的流式,只是模拟流式返回,所以响应速度会比非流式还要慢一些,介意的话,就用非流式就行了。

不过,目前还有点小瑕疵,就是用nextchat调用会携带object Object如下图,请求前端的大佬们帮忙再完善一下,本人菜鸟一枚,前端无能。

image

在edwa佬的帮助下,已解决。
image

33 个赞

感谢分享,这就试试

2 个赞

好嘞,大佬帮忙一起看看那个object问题怎么解决掉 :sob:

2 个赞

这位佬的没有,你可以看看

3 个赞

start跟end的deta的content你传了json进去,所以被解析为object了。你忘把content:去掉了

3 个赞

哈哈,这哥们写的比我优雅,我直接暴力搓的,我当时想快点整完給佬友用上再上床躺着

2 个赞

接力了是吧~厉害了

2 个赞

谢谢佬,解决了 :+1: :+1: :+1:

2 个赞

不客气 :+1: :+1: :+1:

3 个赞

哈哈,也是想尽自己的微薄之力

2 个赞

佬的效率是真的高,我花了好长时间,要不是刚才兄弟告诉我,我还不知道已经有佬写好了

2 个赞

哈哈,兄弟激励我了,我把代码简化了一下,优雅多了

1 个赞

:+1: :+1: :+1:

2 个赞

:cow:

2 个赞

这个点发帖子,真实技术佬了

1 个赞

没有没有,纯属小白瞎折腾~

1 个赞

牛牛

1 个赞

可以更新到主代码里面

1 个赞

嚯 连续剧一样的接力 哈哈。 :+1:

2 个赞

哈哈,如雨后春笋一般,咱们论坛的分享氛围太好了~

1 个赞