admin 发表于 2024-10-1 08:26:56

轻松使用 cf works 访问 coze.cn API。

```javascript
const FOLLOW_UP_ENABLED = true; // 控制是否输出 follow_up 内容
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
});
const encoder = new TextEncoder();
const API_URL = "https://api.coze.cn/open_api/v2/chat";
async function handleRequest(request) {
if (request.method === "OPTIONS") {
    return handleOptionsRequest(request);
}
if (request.method !== "POST") {
    return new Response("OK", { status: 200 });
}
const authorizationHeader = request.headers.get("Authorization");
if (!authorizationHeader || !authorizationHeader.startsWith("Bearer ")) {
    return new Response("未提供有效的API密钥", { status: 200 });
}
const apiKey = authorizationHeader.slice(7);
const requestBody = await request.json();
const messages = requestBody.messages;
const isStream = requestBody.stream;
const model = requestBody.model;
const newRequestBody = {
    conversation_id: "123",
    bot_id: model,
    user: "29032201862555",
    query: messages.content,
    stream: isStream,
    chat_history: messages.slice(0, -1).map(message => ({
      role: message.role,
      content: message.content,
      content_type: "text"
    }))
};
const response = await fetch(API_URL, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": `Bearer ${apiKey}`
    },
    body: JSON.stringify(newRequestBody)
});
const corsHeaders = {
    "Access-Control-Allow-Origin": "*",
    "Access-Control-Allow-Methods": "GET,POST,PUT,DELETE,OPTIONS",
    "Access-Control-Allow-Headers": "*",
    "Access-Control-Allow-Credentials": "true",
};
if (isStream) {
    let decoder = new TextDecoder();
    let reader = response.body.getReader();
    let contentBuffer = "";
    let followUps = [];
    return new Response(new ReadableStream({
      async start(controller) {
      while (true) {
          const { done, value } = await reader.read();
          if (done) break;
          let chunk = decoder.decode(value);
          contentBuffer += chunk;
          while (contentBuffer.includes("\n")) {
            const newlineIndex = contentBuffer.indexOf("\n");
            const line = contentBuffer.slice(0, newlineIndex);
            contentBuffer = contentBuffer.slice(newlineIndex + 1);
            if (line.startsWith("data:")) {
            try {
                const data = JSON.parse(line.slice(5));
                if (data.event === "message") {
                  const message = data.message;
                  if (message.type === "follow_up" && FOLLOW_UP_ENABLED) {
                  followUps.push(message.content);
                  } else if (message.type !== "verbose" && message.type !== "follow_up" && message.type !== "tool_response") {
                  const formattedData = {
                      id: "chatcmpl-" + Math.random().toString(36).slice(2),
                      object: "chat.completion.chunk",
                      created: Math.floor(Date.now() / 1000),
                      model: model,
                      choices: [{
                        index: 0,
                        delta: {
                        content: message.content
                        },
                        finish_reason: data.is_finish ? "stop" : null
                      }]
                  };
                  controller.enqueue(encoder.encode(`data: ${JSON.stringify(formattedData)}\n\n`));
                  }
                }
            } catch (error) {
                console.error("解析JSON时出错:", error, "原始数据:", line);
            }
            }
          }
      }
      if (FOLLOW_UP_ENABLED && followUps.length > 0) {
          const followUpText = "\n----follow_up----\n" + followUps.join("\n");
          const followUpData = {
            id: "chatcmpl-" + Math.random().toString(36).slice(2),
            object: "chat.completion.chunk",
            created: Math.floor(Date.now() / 1000),
            model: model,
            choices: [{
            index: 0,
            delta: {
                content: followUpText
            },
            finish_reason: "stop"
            }]
          };
          controller.enqueue(encoder.encode(`data: ${JSON.stringify(followUpData)}\n\n`));
      }
      const doneData = {
          id: "chatcmpl-" + Math.random().toString(36).slice(2),
          object: "chat.completion.chunk",
          created: Math.floor(Date.now() / 1000),
          model: model,
          choices: [{
            index: 0,
            delta: {},
            finish_reason: "stop"
          }]
      };
      controller.enqueue(encoder.encode(`data: ${JSON.stringify(doneData)}\n\n`));
      controller.enqueue(encoder.encode(`data: \n\n`));
      controller.close();
      }
    }), {
      headers: { ...corsHeaders, "Content-Type": "text/event-stream" }
    });
} else {
    const responseText = await response.text();
    const data = JSON.parse(responseText);
    const answerMessages = data.messages.filter(message => message.type !== "verbose" && message.type !== "follow_up" && message.type !== "tool_response");
    const followUpMessages = FOLLOW_UP_ENABLED ? data.messages.filter(message => message.type === "follow_up") : [];
    const formattedData = {
      id: "chatcmpl-" + Math.random().toString(36).slice(2),
      object: "chat.completion",
      created: Math.floor(Date.now() / 1000),
      model: model,
      choices: [{
      index: 0,
      message: {
          role: "assistant",
          content: answerMessages.map(message => message.content).join("") +
            (FOLLOW_UP_ENABLED && followUpMessages.length > 0 ? "\n----follow_up----\n" + followUpMessages.map(message => message.content).join("\n") : "")
      },
      finish_reason: "stop"
      }],
      usage: {
      prompt_tokens: JSON.stringify(newRequestBody).length,
      completion_tokens: answerMessages.reduce((sum, message) => sum + message.content.length, 0) +
          (FOLLOW_UP_ENABLED && followUpMessages.length > 0 ? followUpMessages.reduce((sum, message) => sum + message.content.length, 0) + 20 : 0),
      total_tokens: JSON.stringify(newRequestBody).length +
          answerMessages.reduce((sum, message) => sum + message.content.length, 0) +
          (FOLLOW_UP_ENABLED && followUpMessages.length > 0 ? followUpMessages.reduce((sum, message) => sum + message.content.length, 0) + 20 : 0)
      }
    };
    return new Response(JSON.stringify(formattedData), {
      headers: { ...corsHeaders, "Content-Type": "application/json" }
    });
}
}
function handleOptionsRequest(request) {
const headers = {
    "Access-Control-Allow-Origin": "*",
    "Access-Control-Allow-Methods": "GET,POST,PUT,DELETE,OPTIONS",
    "Access-Control-Allow-Headers": "*",
    "Access-Control-Allow-Credentials": "true",
    "Access-Control-Max-Age": "43200",
};
return new Response(null, {
    status: 204,
    headers: headers,
});
}
```
页: [1]
查看完整版本: 轻松使用 cf works 访问 coze.cn API。