g4f / main.ts
hongshi-files's picture
Update main.ts
35479d9 verified
raw
history blame
5.97 kB
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 });
},
);