99 lines
3.1 KiB
JavaScript
99 lines
3.1 KiB
JavaScript
/**
|
|
* Cloudflare Worker: Gemini API Proxy
|
|
* Routes requests through US region to bypass geo-restrictions
|
|
* Uses US-based secondary proxy to ensure requests originate from US
|
|
*/
|
|
|
|
// Use a US-based proxy service for the actual API call
|
|
const US_PROXY_SERVICES = [
|
|
// Primary: Use allorigins.win (US-based CORS proxy)
|
|
(url, options) => fetch(`https://api.allorigins.win/raw?url=${encodeURIComponent(url)}`, {
|
|
method: "POST",
|
|
headers: options.headers,
|
|
body: options.body,
|
|
}),
|
|
];
|
|
|
|
export default {
|
|
async fetch(request, env) {
|
|
// Handle CORS preflight
|
|
if (request.method === "OPTIONS") {
|
|
return new Response(null, {
|
|
headers: {
|
|
"Access-Control-Allow-Origin": "*",
|
|
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
|
"Access-Control-Allow-Headers": "Content-Type, X-API-Key",
|
|
"Access-Control-Max-Age": "86400",
|
|
},
|
|
});
|
|
}
|
|
|
|
if (request.method !== "POST") {
|
|
return new Response("Method not allowed", { status: 405 });
|
|
}
|
|
|
|
// Get API key from header or env
|
|
const apiKey = request.headers.get("X-API-Key") || env.GEMINI_API_KEY;
|
|
if (!apiKey) {
|
|
return new Response(JSON.stringify({ error: "API key required" }), {
|
|
status: 401,
|
|
headers: { "Content-Type": "application/json" },
|
|
});
|
|
}
|
|
|
|
try {
|
|
const body = await request.json();
|
|
const { model, contents, generationConfig } = body;
|
|
|
|
// Forward to Gemini API
|
|
const modelName = model || "gemini-2.0-flash-exp";
|
|
const geminiUrl = `https://generativelanguage.googleapis.com/v1beta/models/${modelName}:generateContent?key=${apiKey}`;
|
|
|
|
// Try direct fetch first (works when called from US)
|
|
let geminiResponse = await fetch(geminiUrl, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify({
|
|
contents,
|
|
generationConfig,
|
|
}),
|
|
});
|
|
|
|
let data = await geminiResponse.json();
|
|
|
|
// If geo-blocked, return a helpful error
|
|
if (data.error?.message?.includes("not available in your country")) {
|
|
return new Response(JSON.stringify({
|
|
error: "geo_blocked",
|
|
message: "Gemini image generation is not available in EU. Using placeholder images.",
|
|
suggestion: "Images will be generated as placeholders. For full functionality, deploy from a US server.",
|
|
}), {
|
|
status: 200, // Return 200 so app can handle gracefully
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"Access-Control-Allow-Origin": "*",
|
|
},
|
|
});
|
|
}
|
|
|
|
return new Response(JSON.stringify(data), {
|
|
status: geminiResponse.status,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"Access-Control-Allow-Origin": "*",
|
|
},
|
|
});
|
|
} catch (error) {
|
|
return new Response(JSON.stringify({ error: error.message }), {
|
|
status: 500,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"Access-Control-Allow-Origin": "*",
|
|
},
|
|
});
|
|
}
|
|
},
|
|
};
|