Spaces:
Running
Running
| import gradio as gr | |
| import requests | |
| import json | |
| import os | |
| import time | |
| from collections import defaultdict | |
| from PIL import Image | |
| import io | |
| BASE_URL = "https://api.jigsawstack.com/v1" | |
| headers = { | |
| "x-api-key": os.getenv("JIGSAWSTACK_API_KEY") | |
| } | |
| # Rate limiting configuration | |
| request_times = defaultdict(list) | |
| MAX_REQUESTS = 20 # Maximum requests per time window | |
| TIME_WINDOW = 3600 # Time window in seconds (1 hour) | |
| def get_real_ip(request: gr.Request): | |
| """Extract real IP address using x-forwarded-for header or fallback""" | |
| if not request: | |
| return "unknown" | |
| forwarded = request.headers.get("x-forwarded-for") | |
| if forwarded: | |
| ip = forwarded.split(",")[0].strip() # First IP in the list is the client's | |
| else: | |
| ip = request.client.host # fallback | |
| return ip | |
| def check_rate_limit(request: gr.Request): | |
| """Check if the current request exceeds rate limits""" | |
| if not request: | |
| return True, "Rate limit check failed - no request info" | |
| ip = get_real_ip(request) | |
| now = time.time() | |
| # Clean up old timestamps outside the time window | |
| request_times[ip] = [t for t in request_times[ip] if now - t < TIME_WINDOW] | |
| # Check if rate limit exceeded | |
| if len(request_times[ip]) >= MAX_REQUESTS: | |
| time_remaining = int(TIME_WINDOW - (now - request_times[ip][0])) | |
| time_remaining_minutes = round(time_remaining / 60, 1) | |
| time_window_minutes = round(TIME_WINDOW / 60, 1) | |
| return False, f"Rate limit exceeded. You can make {MAX_REQUESTS} requests per {time_window_minutes} minutes. Try again in {time_remaining_minutes} minutes." | |
| # Add current request timestamp | |
| request_times[ip].append(now) | |
| return True, "" | |
| # ----------------- JigsawStack API Wrappers ------------------ | |
| def translate_text(text_input, target_lang, request: gr.Request): | |
| # Check rate limit first | |
| rate_limit_ok, rate_limit_msg = check_rate_limit(request) | |
| if not rate_limit_ok: | |
| return {"error": "Rate limit exceeded", "message": rate_limit_msg} | |
| # Validate required inputs | |
| if not text_input or not text_input.strip(): | |
| return {"error": "Text input is required"} | |
| if not target_lang or not target_lang.strip(): | |
| return {"error": "Target language code is required"} | |
| # Handle both single string and comma-separated multiple phrases | |
| if "," in text_input and not text_input.strip().startswith("["): | |
| text_payload = [t.strip() for t in text_input.split(",") if t.strip()] | |
| else: | |
| text_payload = text_input.strip() | |
| payload = { | |
| "text": text_payload, | |
| "target_language": target_lang.strip() | |
| } | |
| try: | |
| r = requests.post(f"{BASE_URL}/ai/translate", headers=headers, json=payload) | |
| r.raise_for_status() | |
| data = r.json() | |
| if not data.get("success"): | |
| return {"error": "Translation failed", "response": data} | |
| # Return a more comprehensive result matching the API response | |
| result = { | |
| "success": True, | |
| "translated_text": data.get("translated_text") | |
| } | |
| return result | |
| except requests.exceptions.RequestException as req_err: | |
| return {"error": "Request failed", "message": str(req_err)} | |
| except Exception as e: | |
| return {"error": "Unexpected error", "message": str(e)} | |
| # ----------------- Gradio UI ------------------ | |
| with gr.Blocks() as demo: | |
| gr.Markdown(""" | |
| <div style='text-align: center; margin-bottom: 24px;'> | |
| <h1 style='font-size:2.2em; margin-bottom: 0.2em;'>๐งฉ Text Translation</h1> | |
| <p style='font-size:1.2em; margin-top: 0;'>Translate text from one language to another with support for multiple text formats.</p> | |
| <p style='font-size:1em; margin-top: 0.5em;'>For more details and API usage, see the <a href='https://jigsawstack.com/docs/api-reference/ai/translate/translate' target='_blank'>documentation</a>.</p> | |
| </div> | |
| """) | |
| with gr.Row(): | |
| # Left Column: Inputs and Examples | |
| with gr.Column(scale=2): | |
| gr.Markdown("#### Input") | |
| text_input = gr.Textbox( | |
| label="Text to Translate", | |
| lines=4, | |
| placeholder="Enter text to translate (use commas to separate multiple phrases for batch translation)" | |
| ) | |
| gr.Markdown("#### Translation Options") | |
| target_lang = gr.Textbox( | |
| label="Target Language Code", | |
| placeholder="es (Spanish), fr (French), de (German), etc.", | |
| info="Common codes: es, fr, de, hi, ja, ko, zh, ar, ru, pt" | |
| ) | |
| gr.Markdown("#### Quick Examples") | |
| gr.Markdown("Click any example below to auto-fill the fields:") | |
| with gr.Row(): | |
| example_btn1 = gr.Button("๐ช๐ธ Hello World โ Spanish", size="sm") | |
| example_btn2 = gr.Button("๐ซ๐ท Good morning โ French", size="sm") | |
| example_btn3 = gr.Button("๐ฉ๐ช Thank you โ German", size="sm") | |
| with gr.Row(): | |
| example_btn4 = gr.Button("๐ฏ๐ต How are you? โ Japanese", size="sm") | |
| example_btn5 = gr.Button("๐จ๐ณ Welcome โ Chinese", size="sm") | |
| example_btn6 = gr.Button("๐ฐ๐ท Goodbye โ Korean", size="sm") | |
| with gr.Row(): | |
| example_btn7 = gr.Button("๐ฎ๐ณ Batch: Hello, Goodbye, Thank you โ Hindi", size="sm") | |
| example_btn8 = gr.Button("๐ท๐บ Business: Meeting, Project, Deadline โ Russian", size="sm") | |
| gr.Markdown("") # Spacer | |
| translate_btn = gr.Button("Translate", variant="primary") | |
| # Middle Column: Supported Languages | |
| with gr.Column(scale=1): | |
| gr.Markdown("#### Supported Languages") | |
| gr.Markdown(""" | |
| **Common Language Codes:** | |
| - `es` - Spanish | |
| - `fr` - French | |
| - `de` - German | |
| - `hi` - Hindi | |
| - `ja` - Japanese | |
| - `ko` - Korean | |
| - `zh` - Chinese | |
| - `ar` - Arabic | |
| - `ru` - Russian | |
| - `pt` - Portuguese | |
| - `tr` - Turkish | |
| - `bn` - Bengali | |
| - `fi` - Finnish | |
| - `sw` - Swahili | |
| *For a complete list of 162+ supported languages, visit the [Language Codes Reference](https://jigsawstack.com/docs/additional-resources/languages)* | |
| """) | |
| # Example functions to auto-fill fields | |
| def fill_example_1(): | |
| return "Hello World", "es" | |
| def fill_example_2(): | |
| return "Good morning", "fr" | |
| def fill_example_3(): | |
| return "Thank you", "de" | |
| def fill_example_4(): | |
| return "How are you?", "ja" | |
| def fill_example_5(): | |
| return "Welcome", "zh" | |
| def fill_example_6(): | |
| return "Goodbye", "ko" | |
| def fill_example_7(): | |
| return "Hello, Goodbye, Thank you", "hi" | |
| def fill_example_8(): | |
| return "Meeting, Project, Deadline", "ru" | |
| # Connect example buttons to auto-fill functions | |
| example_btn1.click(fill_example_1, outputs=[text_input, target_lang]) | |
| example_btn2.click(fill_example_2, outputs=[text_input, target_lang]) | |
| example_btn3.click(fill_example_3, outputs=[text_input, target_lang]) | |
| example_btn4.click(fill_example_4, outputs=[text_input, target_lang]) | |
| example_btn5.click(fill_example_5, outputs=[text_input, target_lang]) | |
| example_btn6.click(fill_example_6, outputs=[text_input, target_lang]) | |
| example_btn7.click(fill_example_7, outputs=[text_input, target_lang]) | |
| example_btn8.click(fill_example_8, outputs=[text_input, target_lang]) | |
| gr.Markdown("#### Translation Result") | |
| translate_result = gr.JSON() | |
| translate_btn.click( | |
| translate_text, | |
| inputs=[text_input, target_lang], | |
| outputs=translate_result, | |
| ) | |
| demo.launch() | |