import { serve } from "https://deno.land/std@0.220.1/http/server.ts"; // 定义常量 const BASE_URL = "https://api.codegpt.co/api"; const PORT = 7860; interface CodegptModel { id: string; org_id: string; name: string; model: string; } // 从请求头中获取API_KEY function getApiKeyFromRequest(req: Request): string | null { const authHeader = req.headers.get("authorization"); if (!authHeader) return null; // 支持 "Bearer sk-xxx" 或直接 "sk-xxx" 格式 const match = authHeader.match(/^(Bearer\s+)?(sk-[a-zA-Z0-9-]+)$/); return match ? match[2] : null; } // 获取模型列表 async function getModels(apiKey: string): Promise { try { const response = await fetch( `${BASE_URL}/v1/agent`, { method: "GET", headers: { "Accept": "application/json", "Authorization": `Bearer ${apiKey}`, }, }, ); if (!response.ok) { const errorData = await response.json(); if (errorData.message === "Invalid credentials") { throw new Error("🚀 ~ Your API key or access token is invalid.!"); } throw new Error(`Failed to get models: ${response.status}`); } const data = await response.json(); // console.log("🚀 ~ codegpt agents 响应:", data); return data; } catch (error) { console.error("Error getting models:", error); throw error; } } // 将 codegpt agent 转换为 OpenAI model 格式 function transformModelsToOpenAIFormat(models: CodegptModel[]) { return { object: "list", data: models.map((model) => ({ id: model.id, name: model.model, object: "model", created: Date.now(), owned_by: "codegpt", permission: [{ id: `modelperm-${model.model}`, object: "model_permission", created: Date.now(), allow_create_engine: false, allow_sampling: true, allow_logprobs: false, allow_search_indices: false, allow_view: true, allow_fine_tuning: false, organization: "*", group: null, is_blocking: false, }], root: model.model, parent: null, })), }; } // 处理聊天完成请求 async function handleChatCompletions( apiKey: string, requestBody: any, stream: boolean, ) { const CodegptBody = { stream: stream, agentId: requestBody.model, messages: requestBody.messages, format: "json", }; // console.log("🚀 ~ 内部实际请求: ", CodegptBody); const response = await fetch( `${BASE_URL}/v1/chat/completions`, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${apiKey}`, "Accept": stream ? "text/event-stream" : "application/json", }, body: JSON.stringify(CodegptBody), }, ); // console.log("🚀 ~ 内部请求实际响应: \n", response); if (!response.ok) { throw new Error(`Chat completion failed: ${response.status}`); } return response; } // 转换流式响应 async function* transformStreamResponse( readableStream: ReadableStream, ) { const reader = readableStream.getReader(); const decoder = new TextDecoder(); let buffer = ""; try { while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split("\n"); buffer = lines.pop() || ""; for (const line of lines) { if (line.trim() === "" || !line.startsWith("data:")) continue; const data = line.substring(5).trim(); if (data === "[DONE]") { yield "data: [DONE]\n\n"; continue; } try { const CodegptEvent = JSON.parse(data); // 转换为OpenAI格式的事件 const openAIEvent = { id: CodegptEvent.agentName || `chatcmpl-${Date.now()}`, object: "chat.completion.chunk", created: Math.floor(Date.now() / 1000), model: CodegptEvent.model || CodegptEvent.agentName, choices: [ { index: 0, delta: { reasoning_content: CodegptEvent.choices?.[0]?.delta?.contents?.[0]?.type === "think" ? CodegptEvent.choices[0].delta.contents[0].content || "" : "", content: CodegptEvent.choices?.[0]?.delta?.content || "", }, finish_reason: CodegptEvent.choices?.[0]?.finish_reason || null, }, ], }; yield `data: ${JSON.stringify(openAIEvent)}\n\n`; } catch (e) { console.error("Error parsing event:", e, "Line:", line); } } } } finally { reader.releaseLock(); } } // 转换非流式响应 async function transformNonStreamResponse(response: Response) { const CodegptResponse = await response.json(); return { id: CodegptResponse.id || `chatcmpl-${Date.now()}`, object: "chat.completion", created: Math.floor(Date.now() / 1000), model: CodegptResponse.model || CodegptResponse.agentName, choices: [ { index: 0, message: { role: "assistant", content: CodegptResponse.choices?.[0]?.message?.content || "", }, finish_reason: CodegptResponse.choices?.[0]?.finish_reason || "stop", }, ], usage: CodegptResponse.usage || { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0, }, }; } // 主处理函数 async function handler(req: Request): Promise { const url = new URL(req.url); const path = url.pathname; const apiKey = getApiKeyFromRequest(req); if (!apiKey) { return new Response( // 没有填写 apikey 时返回的错误信息 JSON.stringify({ error: "Unauthorized", message: "Your API key or access token is invalid." }), { status: 401, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, } ); } // CORS预检请求处理 if (req.method === "OPTIONS") { return new Response(null, { status: 204, headers: { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET, POST, OPTIONS", "Access-Control-Allow-Headers": "Content-Type, Authorization", "Access-Control-Max-Age": "86400", }, }); } try { // 模型列表接口 if (path === "/v1/models" && req.method === "GET") { const models = await getModels(apiKey); const openAIModels = transformModelsToOpenAIFormat(models); // console.log("🚀 ~ openAI格式models: ", openAIModels); return new Response(JSON.stringify(openAIModels), { status: 200, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }); } // 聊天完成接口 else if (path === "/v1/chat/completions" && req.method === "POST") { const requestBody = await req.json(); // console.log("🚀 ~ 外部客户端请求: ", requestBody); const stream = requestBody.stream === true; const codegptResponse = await handleChatCompletions(apiKey, requestBody, stream); if (stream) { const transformedStream = new ReadableStream({ async start(controller) { try { for await (const chunk of transformStreamResponse(codegptResponse.body!)) { controller.enqueue(new TextEncoder().encode(chunk)); } controller.close(); } catch (error) { console.error("Stream transformation error:", error); controller.error(error); } }, }); return new Response(transformedStream, { headers: { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", "Connection": "keep-alive", "Access-Control-Allow-Origin": "*", }, }); } else { const transformedResponse = await transformNonStreamResponse(codegptResponse); return new Response(JSON.stringify(transformedResponse), { status: 200, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }); } } // 未找到路由 else { return new Response( JSON.stringify({ error: "Not found", message: "Endpoint not supported" }), { status: 404, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }, ); } } catch (error) { console.error("Request handling error:", error); return new Response( JSON.stringify({ error: "Internal server error", message: error.message }), { status: 500, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }, ); } } console.log(`Starting server on port ${PORT}...`); serve(handler, { port: PORT });