@@ -2,6 +2,7 @@ import { GoogleGenerativeAI } from '@google/generative-ai';
22
33export interface Env {
44 RATE_LIMIT : KVNamespace ;
5+ LANG_TRANSLATION_ANALYTICS : KVNamespace ;
56 GEMINI_API_KEY : string ;
67}
78
@@ -15,7 +16,7 @@ const MAX_REQUESTS_ALLOWED = 10;
1516const DURATION = 60_000 ;
1617
1718async function checkRateLimit ( ip : string , env : Env ) {
18- const key = `ip_key:${ ip } ` ;
19+ const key = `ip_key:${ ip } ` . toLowerCase ( ) ;
1920 const now = Date . now ( ) ;
2021 let value = await env . RATE_LIMIT . get ( key ) ;
2122 let data = { count : 0 , time : now } ;
@@ -38,7 +39,27 @@ async function checkRateLimit(ip: string, env: Env) {
3839
3940 return data . count <= MAX_REQUESTS_ALLOWED ;
4041}
41- async function handleTranslate ( request : Request , model : ReturnType < GoogleGenerativeAI [ 'getGenerativeModel' ] > ) {
42+
43+ async function updateAnalytics ( source : string , dest : string , env : Env ) {
44+ const normalizedSource = source . trim ( ) . toLowerCase ( ) ;
45+ const normalizedDest = dest . trim ( ) . toLowerCase ( ) ;
46+ const key = `${ normalizedSource } -${ normalizedDest } ` ;
47+ let value = await env . LANG_TRANSLATION_ANALYTICS . get ( key ) ;
48+
49+ let data = { count : 0 } ;
50+ if ( value ) {
51+ try {
52+ data = JSON . parse ( value ) ;
53+ } catch {
54+ data = { count : 0 } ;
55+ }
56+ }
57+
58+ data . count += 1 ; // increment usage count
59+
60+ await env . LANG_TRANSLATION_ANALYTICS . put ( key , JSON . stringify ( data ) ) ;
61+ }
62+ async function handleTranslate ( request : Request , model : ReturnType < GoogleGenerativeAI [ 'getGenerativeModel' ] > , env : Env ) {
4263 const { code, targetLanguage } = await request . json < { code : string ; targetLanguage : string } > ( ) ;
4364
4465 if ( ! code || ! targetLanguage ) {
@@ -47,7 +68,7 @@ async function handleTranslate(request: Request, model: ReturnType<GoogleGenerat
4768 headers : { ...corsHeaders , 'Content-Type' : 'application/json' } ,
4869 } ) ;
4970 }
50-
71+ const sourceLanguage = await detectLanguage ( code , model ) ;
5172 const prompt = `Translate the following code snippet to ${ targetLanguage } .
5273Do not add any explanation, commentary, or markdown formatting like \`\`\` around the code.
5374**IMPORTANT: Preserve all original comments and their exact placement in the translated code. Do not add extra spaces in between.**
@@ -58,8 +79,8 @@ ${code}`;
5879
5980 const result = await model . generateContent ( prompt ) ;
6081 const translatedCode = result . response . text ( ) ;
61-
62- return new Response ( JSON . stringify ( { translation : translatedCode } ) , {
82+ await updateAnalytics ( sourceLanguage , targetLanguage , env ) ;
83+ return new Response ( JSON . stringify ( { translation : translatedCode } ) , {
6384 status : 200 ,
6485 headers : { ...corsHeaders , 'Content-Type' : 'application/json' } ,
6586 } ) ;
@@ -102,23 +123,39 @@ export default {
102123
103124 try {
104125 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- }
126+ const allowed = await checkRateLimit ( ip , env ) ;
127+ if ( ! allowed ) {
128+ return new Response ( JSON . stringify ( { error : ' Too many requests. Try again later.' } ) , {
129+ status : 429 ,
130+ headers : { ...corsHeaders , 'Content-Type' : 'application/json' } ,
131+ } ) ;
132+ }
112133 const url = new URL ( request . url ) ;
113134 const path = url . pathname ;
114135 const genAI = new GoogleGenerativeAI ( env . GEMINI_API_KEY ) ;
115136 const model = genAI . getGenerativeModel ( { model : 'gemini-2.0-flash' } ) ;
137+ if ( path === '/v1/analytics' ) {
138+ const list = await env . LANG_TRANSLATION_ANALYTICS . list ( ) ;
139+ const stats : Record < string , any > = { } ;
140+ for ( const key of list . keys ) {
141+ const val = await env . LANG_TRANSLATION_ANALYTICS . get ( key . name ) ;
142+ try {
143+ stats [ key . name ] = JSON . parse ( val || '{}' ) ;
144+ } catch ( e ) {
145+ console . error ( `Failed to parse analytics value for key "${ key . name } ":` , e ) ;
146+ stats [ key . name ] = { } ;
147+ }
148+ }
149+ return new Response ( JSON . stringify ( stats , null , 2 ) , {
150+ headers : { ...corsHeaders , 'Content-Type' : 'application/json' } ,
151+ } ) ;
152+ }
116153
117- if ( path === " /test-rate-limit" ) {
118- return new Response ( JSON . stringify ( " Proceed !" ) )
154+ if ( path === ' /test-rate-limit' ) {
155+ return new Response ( JSON . stringify ( ' Proceed !' ) ) ;
119156 }
120157 if ( path === '/' || path === '/v1/translate' ) {
121- return await handleTranslate ( request , model ) ;
158+ return await handleTranslate ( request , model , env ) ;
122159 }
123160
124161 if ( path === '/v1/explain' ) {
@@ -138,3 +175,14 @@ export default {
138175 }
139176 } ,
140177} ;
178+
179+ async function detectLanguage ( code : string , model : ReturnType < GoogleGenerativeAI [ 'getGenerativeModel' ] > ) {
180+ const prompt = `Identify the programming language of the following code.
181+ Only respond with the exact language name (e.g., "python", "javascript", "c++", "java", etc.) without any extra text or punctuation.
182+
183+ Code:
184+ ${ code } `;
185+
186+ const result = await model . generateContent ( prompt ) ;
187+ return result . response . text ( ) . trim ( ) . toLowerCase ( ) ;
188+ }
0 commit comments