|
1 | 1 | import { GoogleGenerativeAI } from '@google/generative-ai'; |
2 | 2 |
|
3 | 3 | export interface Env { |
| 4 | + RATE_LIMIT: KVNamespace; |
4 | 5 | GEMINI_API_KEY: string; |
5 | 6 | } |
6 | 7 |
|
7 | | -export default { |
8 | | - async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> { |
9 | | - const corsHeaders = { |
10 | | - 'Access-Control-Allow-Origin': '*', |
11 | | - 'Access-Control-Allow-Methods': 'POST, OPTIONS', |
12 | | - 'Access-Control-Allow-Headers': 'Content-Type', |
13 | | - }; |
| 8 | +const corsHeaders = { |
| 9 | + 'Access-Control-Allow-Origin': '*', |
| 10 | + 'Access-Control-Allow-Methods': 'POST, OPTIONS', |
| 11 | + 'Access-Control-Allow-Headers': 'Content-Type', |
| 12 | +}; |
14 | 13 |
|
15 | | - if (request.method === 'OPTIONS') { |
16 | | - return new Response(null, { headers: corsHeaders }); |
17 | | - } |
| 14 | +const MAX_REQUESTS_ALLOWED = 10; |
| 15 | +const DURATION = 60_000; |
| 16 | + |
| 17 | +async function checkRateLimit(ip: string, env: Env) { |
| 18 | + const key = `ip_key:${ip}`; |
| 19 | + const now = Date.now(); |
| 20 | + let value = await env.RATE_LIMIT.get(key); |
| 21 | + let data = { count: 0, time: now }; |
18 | 22 |
|
| 23 | + if (value) { |
19 | 24 | try { |
20 | | - const { code, targetLanguage } = await request.json<{ code: string; targetLanguage: string }>(); |
| 25 | + data = JSON.parse(value); |
| 26 | + } catch { |
| 27 | + data = { count: 0, time: now }; |
| 28 | + } |
| 29 | + } |
21 | 30 |
|
22 | | - if (!code || !targetLanguage) { |
23 | | - return new Response(JSON.stringify({ error: "Missing 'code' or 'targetLanguage' in request body." }), { |
24 | | - status: 400, |
25 | | - headers: { ...corsHeaders, 'Content-Type': 'application/json' }, |
26 | | - }); |
27 | | - } |
| 31 | + if (now - data.time > DURATION) { |
| 32 | + data.count = 0; |
| 33 | + data.time = now; |
| 34 | + } |
28 | 35 |
|
29 | | - const genAI = new GoogleGenerativeAI(env.GEMINI_API_KEY); |
| 36 | + data.count += 1; |
| 37 | + await env.RATE_LIMIT.put(key, JSON.stringify(data), { expirationTtl: 65 }); |
30 | 38 |
|
31 | | - const model = genAI.getGenerativeModel({ model: 'gemini-2.0-flash' }); |
| 39 | + return data.count <= MAX_REQUESTS_ALLOWED; |
| 40 | +} |
| 41 | +async function handleTranslate(request: Request, model: ReturnType<GoogleGenerativeAI['getGenerativeModel']>) { |
| 42 | + const { code, targetLanguage } = await request.json<{ code: string; targetLanguage: string }>(); |
| 43 | + |
| 44 | + if (!code || !targetLanguage) { |
| 45 | + return new Response(JSON.stringify({ error: "Missing 'code' or 'targetLanguage' in request body." }), { |
| 46 | + status: 400, |
| 47 | + headers: { ...corsHeaders, 'Content-Type': 'application/json' }, |
| 48 | + }); |
| 49 | + } |
32 | 50 |
|
33 | | - const prompt = `Translate the following code snippet to ${targetLanguage}. |
| 51 | + const prompt = `Translate the following code snippet to ${targetLanguage}. |
34 | 52 | Do not add any explanation, commentary, or markdown formatting like \`\`\` around the code. |
35 | | -**IMPORTANT: Preserve all original comments and their exact placement in the translated code. do not add extra spaces in between.** |
| 53 | +**IMPORTANT: Preserve all original comments and their exact placement in the translated code. Do not add extra spaces in between.** |
36 | 54 | Only provide the raw, translated code itself. |
37 | 55 |
|
38 | 56 | Original Code: |
39 | 57 | ${code}`; |
40 | 58 |
|
41 | | - const result = await model.generateContent(prompt); |
42 | | - const geminiResponse = result.response; |
43 | | - const translatedCode = geminiResponse.text(); |
| 59 | + const result = await model.generateContent(prompt); |
| 60 | + const translatedCode = result.response.text(); |
| 61 | + |
| 62 | + return new Response(JSON.stringify({ translation: translatedCode }), { |
| 63 | + status: 200, |
| 64 | + headers: { ...corsHeaders, 'Content-Type': 'application/json' }, |
| 65 | + }); |
| 66 | +} |
| 67 | + |
| 68 | +async function handleExplain(request: Request, model: ReturnType<GoogleGenerativeAI['getGenerativeModel']>) { |
| 69 | + const { code } = await request.json<{ code: string }>(); |
| 70 | + |
| 71 | + if (!code) { |
| 72 | + return new Response(JSON.stringify({ error: "Missing 'code' in request body." }), { |
| 73 | + status: 400, |
| 74 | + headers: { ...corsHeaders, 'Content-Type': 'application/json' }, |
| 75 | + }); |
| 76 | + } |
| 77 | + |
| 78 | + const prompt = `Explain the following code snippet in detail: |
| 79 | +1. Provide a clear breakdown of what each part (functions, variables, logic blocks) does. |
| 80 | +2. If applicable, describe the overall purpose or intent of the code. |
| 81 | +3. Offer a step-by-step explanation of how the code executes. |
| 82 | +4. If the code is executable, show a sample input and the corresponding output. |
| 83 | +5. Keep the explanation beginner-friendly but technically accurate. |
| 84 | +
|
| 85 | +Code: |
| 86 | +${code}`; |
| 87 | + |
| 88 | + const result = await model.generateContent(prompt); |
| 89 | + const explanation = result.response.text(); |
| 90 | + |
| 91 | + return new Response(JSON.stringify({ explanation }), { |
| 92 | + status: 200, |
| 93 | + headers: { ...corsHeaders, 'Content-Type': 'application/json' }, |
| 94 | + }); |
| 95 | +} |
| 96 | + |
| 97 | +export default { |
| 98 | + async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> { |
| 99 | + if (request.method === 'OPTIONS') { |
| 100 | + return new Response(null, { headers: corsHeaders }); |
| 101 | + } |
| 102 | + |
| 103 | + try { |
| 104 | + const ip = request.headers.get('CF-Connecting-IP') || 'unknown'; |
| 105 | + const allowed = await checkRateLimit(ip, env); |
| 106 | + if (!allowed) { |
| 107 | + return new Response(JSON.stringify({ error: "Too many requests. Try again later." }), { |
| 108 | + status: 429, |
| 109 | + headers: { ...corsHeaders, 'Content-Type': 'application/json' }, |
| 110 | + }); |
| 111 | + } |
| 112 | + const url = new URL(request.url); |
| 113 | + const path = url.pathname; |
| 114 | + const genAI = new GoogleGenerativeAI(env.GEMINI_API_KEY); |
| 115 | + const model = genAI.getGenerativeModel({ model: 'gemini-2.0-flash' }); |
| 116 | + |
| 117 | + if(path==="/test-rate-limit"){ |
| 118 | + return new Response(JSON.stringify("Proceed !")) |
| 119 | + } |
| 120 | + if (path === '/' || path === '/v1/translate') { |
| 121 | + return await handleTranslate(request, model); |
| 122 | + } |
| 123 | + |
| 124 | + if (path === '/v1/explain') { |
| 125 | + return await handleExplain(request, model); |
| 126 | + } |
44 | 127 |
|
45 | | - return new Response(JSON.stringify({ translation: translatedCode }), { |
46 | | - status: 200, |
| 128 | + return new Response(JSON.stringify({ error: 'Route not found.' }), { |
| 129 | + status: 404, |
47 | 130 | headers: { ...corsHeaders, 'Content-Type': 'application/json' }, |
48 | 131 | }); |
49 | 132 | } catch (error) { |
50 | | - console.error('Error during translation:', error); |
51 | | - return new Response(JSON.stringify({ error: 'An error occurred while translating the code.' }), { |
| 133 | + console.error('Error during request:', error); |
| 134 | + return new Response(JSON.stringify({ error: 'An internal error occurred.' }), { |
52 | 135 | status: 500, |
53 | 136 | headers: { ...corsHeaders, 'Content-Type': 'application/json' }, |
54 | 137 | }); |
|
0 commit comments