takumi0002's picture
Update app.py
dd0d837 verified
Raw
History Blame
7.47 kB
import os
import requests
import gradio as gr
import re
# Registry for Key Status
key_status_registry = {}
class AIService:
@staticmethod
def get_all_keys(prefix):
# αžŸαž˜αŸ’αžšαž½αž›αž˜αž€αž”αŸ’αžšαžΎ Key αžαŸ‚αž˜αž½αž™αž…αŸ†αŸ—αžŸαž˜αŸ’αžšαžΆαž”αŸ‹ Gemini αž“αž·αž„αž˜αŸ‰αžΌαžŠαŸ‚αž›αž•αŸ’αžŸαŸαž„αž‘αŸ€αž
# αžœαžΆαž“αžΉαž„αž†αŸ‚αž€αžšαž€αž˜αžΎαž›αžˆαŸ’αž˜αŸ„αŸ‡αžŠαžΌαž…αž‡αžΆ GEMINI_API_KEY ឬ GROQ_API_KEY αž•αŸ’αž‘αžΆαž›αŸ‹αžαŸ‚αž˜αŸ’αžŠαž„
env_name = prefix.rstrip('_') # αžŠαž€αžŸαž‰αŸ’αž‰αžΆ _ αž…αŸαž‰αžŠαžΎαž˜αŸ’αž”αžΈαž±αŸ’αž™αžαŸ’αžšαžΌαžœαž“αžΉαž„αžˆαŸ’αž˜αŸ„αŸ‡ Standard
key = os.environ.get(env_name)
if key:
return [key]
return []
@staticmethod
def get_status_html(engine, target_lang=None):
if "Gemini" in engine:
prefix = "GEMINI_API_KEY"
elif "Llama" in engine:
prefix = "GROQ_API_KEY"
else:
prefix = "SEA_LION_API_KEY"
keys = AIService.get_all_keys(prefix)
label = engine.split(" ")[-1]
status_label = "αžŸαŸ’αžαžΆαž“αž—αžΆαž–/Status"
html = f"<div style='display: flex; gap: 8px; align-items: center; margin-bottom: 10px;'><b style='color: #94a3b8; font-size: 12px;'>{label} {status_label}:</b>"
if not keys:
html += "<span style='color: #ef4444; font-size: 10px;'>αžšαž€αž˜αž·αž“αžƒαžΎαž‰ Key</span>"
else:
for k in keys:
state = key_status_registry.get(k, "ready")
color = "#22c55e" if state == "ready" else "#ef4444"
html += f"<div style='width: 10px; height: 10px; background: {color}; border-radius: 50%; box-shadow: 0 0 5px {color};'></div>"
return html + "</div>"
@staticmethod
def call_api(engine, prompt):
temp = 0.8
if "Gemini" in engine:
keys = AIService.get_all_keys("GEMINI_API_KEY")
for key in keys:
try:
# αž”αŸ’αžšαžΎαž˜αŸ‰αžΌαžŠαŸ‚αž› Gemini 2.0 Flash αž•αŸ’αž›αžΌαžœαž€αžΆαžš
url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key={key}"
res = requests.post(url, json={
"contents": [{"parts": [{"text": prompt}]}],
"generationConfig": {"temperature": temp},
"safetySettings": [
{"category": "HARM_CATEGORY_HARASSMENT", "threshold": "BLOCK_NONE"},
{"category": "HARM_CATEGORY_HATE_SPEECH", "threshold": "BLOCK_NONE"},
{"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "threshold": "BLOCK_NONE"},
{"category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_NONE"}
]
}, timeout=45)
if res.status_code == 200:
key_status_registry[key] = "ready"
return res.json()['candidates'][0]['content']['parts'][0]['text'].strip()
key_status_registry[key] = "dead"
except: continue
elif "Llama" in engine:
keys = AIService.get_all_keys("GROQ_API_KEY")
for key in keys:
try:
res = requests.post("https://api.groq.com/openai/v1/chat/completions",
headers={"Authorization": f"Bearer {key}"},
json={"model": "llama-3.3-70b-versatile", "messages": [{"role": "user", "content": prompt}], "temperature": temp}, timeout=30)
if res.status_code == 200:
key_status_registry[key] = "ready"
return res.json()['choices'][0]['message']['content'].strip()
key_status_registry[key] = "dead"
except: continue
else:
key = os.environ.get("SEA_LION_API_KEY")
try:
res = requests.post("https://api.sea-lion.ai/v1/chat/completions",
headers={"Authorization": f"Bearer {key}"},
json={
"model": "aisingapore/Gemma-SEA-LION-v4-27B-IT",
"messages": [{"role": "system", "content": "You are an expert translator. Output ONLY translation."},
{"role": "user", "content": prompt}],
"temperature": 0.7
}, timeout=60)
if res.status_code == 200:
key_status_registry[key] = "ready"
return res.json()['choices'][0]['message']['content'].strip()
key_status_registry[key] = "dead"
except: pass
return None
def translator_hub(text, target_lang, engine):
if not text.strip(): return "", AIService.get_status_html(engine)
lang_name = re.sub(r'[^\w\s]', '', target_lang).strip()
instruction = f"""Translate to {lang_name} STRICTLY:
1. OUTPUT ONLY translation. No notes.
2. SLANG & IDIOMS: Adapt naturally.
3. CONTEXT: Use proper pronouns (αž”αž„, αž’αžΌαž“, αž’αž‰, αž―αž„) based on mood.
4. SRT FORMAT: Preserve timing/numbering.
5. NO MIXED LANGUAGES: No English words in output."""
prompt = f"{instruction}\n\nCONTENT:\n{text}"
result = AIService.call_api(engine, prompt)
if result:
cleaned = re.sub(r'```[a-zA-Z]*\n?|```', '', result).strip()
return cleaned, AIService.get_status_html(engine)
return "❌ Error: αž˜αž·αž“αž’αžΆαž…αž‘αžΆαž€αŸ‹αž‘αž„αž‘αŸ… API αž”αžΆαž“αž‘αŸ (αž–αž·αž“αž·αžαŸ’αž™ Key αžšαž”αžŸαŸ‹αž˜αŸ)", AIService.get_status_html(engine)
# CSS configuration
custom_css = """
body { background: #0f172a !important; }
.gr-markdown h1 { background: linear-gradient(90deg, #60a5fa, #f472b6); -webkit-background-clip: text; color: transparent !important; }
.btn-trans { background: #10b981 !important; color: white !important; }
"""
with gr.Blocks(title="SRT Pro") as demo:
gr.Markdown("<h1>🎬 SMART TRANSLATOR PRO</h1>")
with gr.Row():
with gr.Column():
lang_opt = gr.Dropdown(["πŸ‡°πŸ‡­ Khmer", "πŸ‡ΊπŸ‡Έ English", "πŸ‡¨πŸ‡³ Chinese", "πŸ‡ΉπŸ‡­ Thai"], value="πŸ‡°πŸ‡­ Khmer", label="Language")
engine_opt = gr.Radio(["πŸ’Ž Gemini", "πŸ¦™ Llama", "🦁 SEA-LION"], value="πŸ’Ž Gemini", label="Model")
status_ui = gr.HTML(AIService.get_status_html("πŸ’Ž Gemini"))
input_box = gr.Textbox(label="Original Content", lines=10, placeholder="αžŠαžΆαž€αŸ‹αž’αžαŸ’αžαž”αž‘αž“αŸ…αž‘αžΈαž“αŸαŸ‡...")
btn_trans = gr.Button("⚑ Translate", variant="primary", elem_classes="btn-trans")
with gr.Column():
output_box = gr.Textbox(label="Result", lines=20, interactive=False)
btn_copy = gr.Button("πŸ“‹ Copy Result")
engine_opt.change(AIService.get_status_html, inputs=[engine_opt], outputs=[status_ui])
btn_trans.click(translator_hub, [input_box, lang_opt, engine_opt], [output_box, status_ui])
btn_copy.click(None, output_box, js="(v) => { navigator.clipboard.writeText(v); alert('βœ… αž…αž˜αŸ’αž›αž„αžšαž½αž…αžšαžΆαž›αŸ‹!'); }")
if __name__ == "__main__":
# αž”αž‰αŸ’αž…αžΌαž› CSS αž€αŸ’αž“αž»αž„ launch() αžŠαžΎαž˜αŸ’αž”αžΈαž‡αž½αžŸαž‡αž»αž› Gradio 6.0 Warning
demo.launch(server_name="0.0.0.0", server_port=7860, css=custom_css, ssr_mode=False)