Spaces:
Build error
Build error
| const WORKER_API_KEY = Deno.env.get("WORKER_API_KEY") || ""; | |
| const PROXY_URL = Deno.env.get("PROXY_URL") || "http://127.0.0.1:17285"; | |
| const SERVICE_PORT = Number(Deno.env.get("SERVICE_PORT") || "8000"); | |
| type ProviderConfig = { | |
| name: string; | |
| upstreamHost: string; | |
| models?: string[]; | |
| modelsPath?: string; | |
| chatPath: string; | |
| }; | |
| const PROVIDER_CONFIG: Record<string, ProviderConfig> = { | |
| "api.airforce": { | |
| name: "Airforce API", | |
| upstreamHost: "api.airforce", | |
| models: ["gpt-5-mini", "gpt-4o-mini"], | |
| chatPath: "/v1/chat/completions", | |
| }, | |
| "anondrop.net": { | |
| name: "AnonDrop", | |
| upstreamHost: "anondrop.net", | |
| modelsPath: "/v1/models", | |
| chatPath: "/v1/chat/completions", | |
| }, | |
| "gpt4free.pro": { | |
| name: "GPT4Free.pro", | |
| upstreamHost: "gpt4free.pro", | |
| modelsPath: "/v1/models", | |
| chatPath: "/v1/chat/completions", | |
| }, | |
| gemini: { | |
| name: "Google Gemini (via g4f)", | |
| upstreamHost: "g4f.dev", | |
| modelsPath: "/api/gemini/models", | |
| chatPath: "/api/gemini/chat/completions", | |
| }, | |
| grok: { | |
| name: "Grok (via g4f)", | |
| upstreamHost: "g4f.dev", | |
| modelsPath: "/api/grok/models", | |
| chatPath: "/api/grok/chat/completions", | |
| }, | |
| "pollinations.ai": { | |
| name: "Pollinations.ai (via g4f)", | |
| upstreamHost: "g4f.dev", | |
| modelsPath: "/api/pollinations.ai/models", | |
| chatPath: "/api/pollinations.ai/chat/completions", | |
| }, | |
| ollama: { | |
| name: "Ollama (via g4f)", | |
| upstreamHost: "g4f.dev", | |
| modelsPath: "/api/ollama/models", | |
| chatPath: "/api/ollama/chat/completions", | |
| }, | |
| huggingface: { | |
| name: "HuggingFace (via g4f)", | |
| upstreamHost: "g4f.dev", | |
| modelsPath: | |
| "/api/huggingface/models?inference=warm&&expand[]=inferenceProviderMapping", | |
| chatPath: "/api/huggingface/chat/completions", | |
| }, | |
| }; | |
| let MODEL_PROVIDER_MAP: Map<string, { | |
| providerId: string; | |
| upstreamHost: string; | |
| chatPath: string; | |
| }> | null = null; | |
| async function buildModelProviderMap() { | |
| console.log("π Building model-provider map..."); | |
| const map = new Map<string, { | |
| providerId: string; | |
| upstreamHost: string; | |
| chatPath: string; | |
| }>(); | |
| await Promise.all( | |
| Object.entries(PROVIDER_CONFIG).map(async ([providerId, cfg]) => { | |
| try { | |
| // Hardcoded models | |
| if (cfg.models && !cfg.modelsPath) { | |
| cfg.models.forEach((m) => | |
| map.set(m, { | |
| providerId, | |
| upstreamHost: cfg.upstreamHost, | |
| chatPath: cfg.chatPath, | |
| }) | |
| ); | |
| return; | |
| } | |
| // Dynamic models | |
| if (cfg.modelsPath) { | |
| const url = `https://${cfg.upstreamHost}${cfg.modelsPath}`; | |
| const r = await fetch(url, { | |
| headers: { | |
| Accept: "application/json", | |
| Origin: "https://g4f.dev", | |
| Referer: "https://g4f.dev", | |
| }, | |
| }); | |
| if (!r.ok) throw new Error(r.statusText); | |
| const data = await r.json(); | |
| let models: string[] = []; | |
| if (Array.isArray(data)) { | |
| models = data.map((m) => m.id || m.name).filter(Boolean); | |
| } else if (data.data) { | |
| models = data.data.map((m: any) => m.id).filter(Boolean); | |
| } else if (data.models) { | |
| models = data.models.map((m: any) => m.name).filter(Boolean); | |
| } | |
| models.forEach((m) => | |
| map.set(m, { | |
| providerId, | |
| upstreamHost: cfg.upstreamHost, | |
| chatPath: cfg.chatPath, | |
| }) | |
| ); | |
| } | |
| } catch (e: any) { | |
| console.log(`β Fetch models failed for ${providerId}: ${e.message}`); | |
| } | |
| }) | |
| ); | |
| MODEL_PROVIDER_MAP = map; | |
| console.log("β Model map built."); | |
| } | |
| async function routeChat(request: Request): Promise<Response> { | |
| if (request.method !== "POST") { | |
| return new Response("Method Not Allowed", { status: 405 }); | |
| } | |
| const auth = request.headers.get("Authorization"); | |
| if (auth !== `Bearer ${WORKER_API_KEY}`) { | |
| return new Response("Unauthorized", { status: 401 }); | |
| } | |
| const body = await request.json(); | |
| const model = body.model; | |
| if (!model) { | |
| return new Response('Missing "model"', { status: 400 }); | |
| } | |
| if (!MODEL_PROVIDER_MAP) { | |
| return new Response("Model map not ready", { status: 503 }); | |
| } | |
| const provider = MODEL_PROVIDER_MAP.get(model); | |
| if (!provider) { | |
| return new Response(`Model '${model}' not found`, { | |
| status: 404, | |
| }); | |
| } | |
| const targetUrl = `https://${provider.upstreamHost}${provider.chatPath}`; | |
| const proxyReq = new Request(PROXY_URL, { | |
| method: "POST", | |
| headers: { | |
| "Content-Type": "application/json", | |
| }, | |
| body: JSON.stringify({ | |
| target: targetUrl, | |
| payload: body, | |
| }), | |
| }); | |
| try { | |
| const resp = await fetch(proxyReq); | |
| return new Response(resp.body, { | |
| status: resp.status, | |
| headers: { | |
| "Content-Type": resp.headers.get("Content-Type") || "application/json", | |
| "Access-Control-Allow-Origin": "*", | |
| }, | |
| }); | |
| } catch (e: any) { | |
| return new Response( | |
| `Proxy upstream error: ${e.message}`, | |
| { status: 502 }, | |
| ); | |
| } | |
| } | |
| function handleModels() { | |
| if (!MODEL_PROVIDER_MAP) { | |
| return new Response("Model map not ready", { | |
| status: 503, | |
| }); | |
| } | |
| const arr = [...MODEL_PROVIDER_MAP.entries()].map(([id, p]) => ({ | |
| id, | |
| object: "model", | |
| owned_by: p.providerId, | |
| })); | |
| return new Response( | |
| JSON.stringify({ object: "list", data: arr }), | |
| { headers: { "Content-Type": "application/json" } }, | |
| ); | |
| } | |
| console.log(`Starting service on ${SERVICE_PORT}`); | |
| Deno.serve( | |
| { port: SERVICE_PORT, hostname: "0.0.0.0" }, | |
| async (req) => { | |
| const url = new URL(req.url); | |
| if (!MODEL_PROVIDER_MAP) await buildModelProviderMap(); | |
| if (url.pathname === "/v1/models") return handleModels(); | |
| if (url.pathname === "/v1/chat/completions") return routeChat(req); | |
| return new Response("Not Found", { status: 404 }); | |
| }, | |
| ); | |