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 = { "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 | null = null; async function buildModelProviderMap() { console.log("🚀 Building model-provider map..."); const map = new Map(); 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 { 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 }); }, );