134 lines
4.1 KiB
JavaScript
134 lines
4.1 KiB
JavaScript
export default {
|
||
async fetch(request, env) {
|
||
if (request.method === "POST" && request.url.includes("v1/chat/completions")) {
|
||
// todo 验证 key
|
||
|
||
try {
|
||
const requestData = await request.json();
|
||
|
||
const { model, messages } = requestData;
|
||
|
||
let isSteam = false;
|
||
if (requestData?.stream) {
|
||
isSteam = true;
|
||
}
|
||
|
||
// get the current time in epoch seconds
|
||
const created = Math.floor(Date.now() / 1000);
|
||
const uuid = crypto.randomUUID();
|
||
|
||
const stream = await env.AI.run("@cf/deepseek-ai/deepseek-r1-distill-qwen-32b", {
|
||
messages: messages,
|
||
stream: isSteam,
|
||
});
|
||
|
||
if (isSteam) {
|
||
// 创建一个转换流 (TransformStream) 以便实现流式返回
|
||
const { readable, writable } = new TransformStream();
|
||
const writer = writable.getWriter();
|
||
const reader = stream.getReader();
|
||
|
||
// 处理流读取数据并逐帧向客户端发送
|
||
async function processStream() {
|
||
const decoder = new TextDecoder();
|
||
const encoder = new TextEncoder();
|
||
|
||
try {
|
||
while (true) {
|
||
const { done, value } = await reader.read();
|
||
if (done) {
|
||
break;
|
||
}
|
||
|
||
// 确保 value 被转换为字符串类型
|
||
const stringValue = decoder.decode(value);
|
||
|
||
// 处理每行数据
|
||
const lines = stringValue.split("\n").filter((line) => !!line);
|
||
for (const line of lines) {
|
||
// 跳过非 JSON 数据(例如 [DONE] )
|
||
if (line.endsWith("data: [DONE]")) {
|
||
continue;
|
||
}
|
||
|
||
try {
|
||
const json = JSON.parse(line.replace(/^data: /, ""));
|
||
|
||
const formattedValue = `data: ${JSON.stringify({
|
||
id: uuid,
|
||
created,
|
||
object: "chat.completion.chunk",
|
||
model,
|
||
choices: [
|
||
{
|
||
delta: { content: json.response },
|
||
index: 0,
|
||
finish_reason: null,
|
||
},
|
||
],
|
||
})}\n\n`;
|
||
const encodedValue = encoder.encode(formattedValue);
|
||
await writer.write(encodedValue);
|
||
} catch (e) {
|
||
console.error("Failed to parse JSON: ", e);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 发送完成标识
|
||
await writer.write(encoder.encode("data: [DONE]\n\n"));
|
||
writer.close();
|
||
} catch (err) {
|
||
console.error("Stream processing error: ", err);
|
||
// 确保 writer 在错误情况下关闭
|
||
writer.close();
|
||
}
|
||
}
|
||
|
||
// 调用处理流函数
|
||
processStream().catch((err) => {
|
||
console.error("Stream processing error: ", err);
|
||
});
|
||
|
||
return new Response(readable, {
|
||
headers: {
|
||
"content-type": "text/event-stream",
|
||
"Cache-Control": "no-cache",
|
||
Connection: "keep-alive",
|
||
},
|
||
});
|
||
} else {
|
||
return Response.json({
|
||
id: uuid,
|
||
model,
|
||
created,
|
||
object: "chat.completion",
|
||
choices: [
|
||
{
|
||
index: 0,
|
||
message: {
|
||
role: "assistant",
|
||
content: stream.response,
|
||
},
|
||
finish_reason: "stop",
|
||
},
|
||
],
|
||
usage: {
|
||
prompt_tokens: 0,
|
||
completion_tokens: 0,
|
||
total_tokens: 0,
|
||
},
|
||
});
|
||
}
|
||
} catch (error) {
|
||
return new Response(JSON.stringify({ error: "Invalid request" }), {
|
||
status: 400,
|
||
headers: { "Content-Type": "application/json" },
|
||
});
|
||
}
|
||
}
|
||
|
||
return new Response("Not Found", { status: 404 });
|
||
},
|
||
};
|