takumi0002 commited on
Commit
394eebf
Β·
verified Β·
1 Parent(s): 16ced91

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +58 -54
app.py CHANGED
@@ -1,24 +1,50 @@
1
  import os
2
  import requests
3
  import gradio as gr
 
4
 
5
  # ==========================================
6
- # ៑. αž•αŸ’αž“αŸ‚αž€αž”αž…αŸ’αž…αŸαž€αž‘αŸαžŸ API (Gemini, Llama & SEA-LION)
7
  # ==========================================
8
  class AIService:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  @staticmethod
10
  def translate_gemini(prompt):
11
  keys = [os.environ.get(f"GEMINI_API_KEY_{i}") for i in range(1, 6) if os.environ.get(f"GEMINI_API_KEY_{i}")]
12
  for key in keys:
13
  try:
14
  url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp:generateContent?key={key}"
15
- # αž€αŸ‚αžŸαž˜αŸ’αžšαž½αž›αž±αŸ’αž™αžœαžΆαž…αŸαŸ‡αžšαžΎαžŸαž–αžΆαž€αŸ’αž™αž”αžαŸ‹αž”αŸ‚αž“αžαžΆαž˜αž”αžšαž·αž”αž‘
16
- instruction = "Return ONLY the translated text. Be natural and accurate. If the user asks again, provide the best alternative translation. Preserve format."
17
  res = requests.post(url, json={"contents": [{"parts": [{"text": f"{instruction}\n\n{prompt}"}]}]}, timeout=15)
18
  if res.status_code == 200:
19
  return res.json()['candidates'][0]['content']['parts'][0]['text'].strip()
20
  except: continue
21
- return "❌ Gemini API Error"
22
 
23
  @staticmethod
24
  def translate_llama(prompt):
@@ -29,9 +55,10 @@ class AIService:
29
  payload = {
30
  "model": "llama-3.3-70b-versatile",
31
  "messages": [
32
- {"role": "system", "content": "Return ONLY the translation. Be accurate and natural. Provide context-appropriate synonyms if re-requested."},
33
  {"role": "user", "content": prompt}
34
- ]
 
35
  }
36
  res = requests.post("https://api.groq.com/openai/v1/chat/completions", headers=headers, json=payload, timeout=15)
37
  if res.status_code == 200:
@@ -41,7 +68,6 @@ class AIService:
41
 
42
  @staticmethod
43
  def translate_sealion(prompt):
44
- # αž”αž‰αŸ’αž…αžΌαž› SEA-LION αž˜αž€αžœαž·αž‰αžαžΆαž˜αž€αžΆαžšαž”αž‰αŸ’αž‡αžΆαž€αŸ‹αžšαž”αžŸαŸ‹αž˜αŸ
45
  key = os.environ.get("SEA_LION_API_KEY")
46
  if not key: return "❌ Missing SEA_LION_API_KEY"
47
  try:
@@ -49,64 +75,37 @@ class AIService:
49
  headers = {"Authorization": f"Bearer {key}", "Content-Type": "application/json"}
50
  payload = {
51
  "model": "aisingapore/Gemma-SEA-LION-v4-27B-IT",
52
- "messages": [
53
- {"role": "system", "content": "Return ONLY direct translation. Ensure natural phrasing. No chatter."},
54
- {"role": "user", "content": prompt}
55
- ],
56
- "max_completion_tokens": 1024,
57
- "temperature": 0.7 # αž”αž“αŸ’αžαŸ‚αž˜ Temperature αžŠαžΎαž˜αŸ’αž”αžΈαž±αŸ’αž™αžœαžΆαžŠαžΌαžšαž–αžΆαž€αŸ’αž™αž–αŸαž›αž…αž»αž…αž˜αŸ’αžαž„αž‘αŸ€αž
58
  }
59
  res = requests.post(url, headers=headers, json=payload, timeout=20)
60
  if res.status_code == 200:
61
  return res.json()['choices'][0]['message']['content'].strip()
62
- return f"❌ SEA-LION Error: {res.status_code}"
63
  except: return "❌ Connection Error"
64
 
65
  def translator_hub(text, target_lang, engine):
66
  if not text.strip(): return ""
67
  lang_name = target_lang.split(" ")[-1]
68
- prompt = f"Translate to {lang_name}:\n{text}"
69
 
70
  if "Gemini" in engine: return AIService.translate_gemini(prompt)
71
  elif "Llama" in engine: return AIService.translate_llama(prompt)
72
- elif "SEA-LION" in engine: return AIService.translate_sealion(prompt)
73
- return "Unknown Model"
74
 
75
  # ==========================================
76
- # ្. αžŸαŸ’αž‚αŸ’αžšαžΈαž” PWA αž–αž·αžŸαŸαžŸ (αžšαž€αŸ’αžŸαžΆαž€αžΌαžŠαžŠαžΎαž˜αž˜αŸαž‘αžΆαŸ†αž„αž’αžŸαŸ‹)
77
  # ==========================================
78
- pwa_ultimate_js = """
79
  function initPWA() {
80
- const script = document.createElement('script');
81
- script.src = 'https://cdn.jsdelivr.net/npm/canvas-confetti@1.6.0/dist/confetti.browser.min.js';
82
- document.head.appendChild(script);
83
-
84
- const manifest = {
85
- "name": "SRT SMART",
86
- "short_name": "SRT SMART",
87
- "start_url": window.location.href,
88
- "display": "standalone",
89
- "background_color": "#0d1117",
90
- "theme_color": "#0d1117",
91
- "icons": [{"src": "https://cdn-icons-png.flaticon.com/512/2800/2800115.png", "sizes": "512x512", "type": "image/png"}]
92
- };
93
 
94
- const blob = new Blob([JSON.stringify(manifest)], {type: 'application/json'});
95
- const manifestURL = URL.createObjectURL(blob);
96
- let link = document.createElement('link');
97
- link.rel = 'manifest'; link.href = manifestURL;
98
- document.head.appendChild(link);
99
-
100
- const metaTags = [
101
- {name: "apple-mobile-web-app-capable", content: "yes"},
102
- {name: "mobile-web-app-capable", content: "yes"},
103
- {name: "apple-mobile-web-app-status-bar-style", content: "black-translucent"}
104
- ];
105
- metaTags.forEach(tag => {
106
- let m = document.createElement('meta');
107
- m.name = tag.name; m.content = tag.content;
108
- document.head.appendChild(m);
109
- });
110
 
111
  window.addEventListener('click', (e) => {
112
  if (typeof confetti === 'function') {
@@ -117,16 +116,15 @@ function initPWA() {
117
  """
118
 
119
  css_style = """
120
- body { background-color: #0d1117 !important; cursor: crosshair; }
121
- textarea { resize: both !important; }
122
  .center-btn { justify-content: center !important; gap: 8px !important; }
123
  .small-btn { max-width: 85px !important; min-width: 70px !important; font-size: 13px !important; padding: 4px !important; }
124
  .translate-btn { min-width: 150px !important; font-weight: bold !important; background: linear-gradient(45deg, #1e40af, #3b82f6) !important; color: white !important; }
125
  """
126
 
127
- with gr.Blocks(css=css_style, head=f"<script>{pwa_ultimate_js}</script>") as demo:
128
  demo.load(None, None, None, js="() => { initPWA(); }")
129
-
130
  gr.Markdown("<h2 style='text-align: center; color: #60a5fa;'>πŸŽ† SRT SMART ULTIMATE πŸ‡°πŸ‡­</h2>")
131
 
132
  with gr.Column():
@@ -137,15 +135,21 @@ with gr.Blocks(css=css_style, head=f"<script>{pwa_ultimate_js}</script>") as dem
137
  value="πŸ‡°πŸ‡­ Khmer", label="αž”αž€αž”αŸ’αžšαŸ‚αž‡αžΆαž—αžΆαžŸαžΆ"
138
  )
139
 
140
- input_text = gr.Textbox(label="αž’αžαŸ’αžαž”αž‘αžŠαžΎαž˜ (αž‘αžΆαž‰αž–αž„αŸ’αžšαžΈαž€αž”αžΆαž“)", lines=5, placeholder="αž”αž·αž‘αž—αŸ’αž‡αžΆαž”αŸ‹ SRT αž¬αž’αžαŸ’αžαž”αž‘...")
 
 
 
141
 
142
  with gr.Row(elem_classes="center-btn"):
143
  clear_btn = gr.Button("πŸ—‘οΈ αž›αž»αž”", variant="secondary", elem_classes="small-btn")
144
  submit_btn = gr.Button("οΏ½οΏ½οΏ½ αž”αž€αž”αŸ’αžšαŸ‚αž₯ទូវ", variant="primary", elem_classes="translate-btn")
145
  copy_btn = gr.Button("πŸ“‹ αž…αž˜αŸ’αž›αž„", variant="secondary", elem_classes="small-btn")
146
 
147
- output_text = gr.Textbox(label="αž›αž‘αŸ’αž’αž•αž› (αž‘αžΆαž‰αž–αž„αŸ’αžšαžΈαž€αž”αžΆαž“)", lines=8, interactive=False)
148
 
 
 
 
149
  submit_btn.click(fn=translator_hub, inputs=[input_text, lang_opt, engine_opt], outputs=output_text)
150
  clear_btn.click(lambda: ["", ""], None, [input_text, output_text])
151
  copy_btn.click(None, inputs=output_text, js="(v) => { if(v){ navigator.clipboard.writeText(v); alert('αž”αžΆαž“αž…αž˜αŸ’αž›αž„! πŸŽ†'); } }")
 
1
  import os
2
  import requests
3
  import gradio as gr
4
+ import time
5
 
6
  # ==========================================
7
+ # ៑. αž•αŸ’αž“αŸ‚αž€αž”αž…αŸ’αž…αŸαž€αž‘αŸαžŸ API (αž‡αžΆαž˜αž½αž™ Logic αž”αž‰αŸ’αž‡αžΌαž“αžŸαŸ’αžαžΆαž“αž—αžΆαž– Key)
8
  # ==========================================
9
  class AIService:
10
+ @staticmethod
11
+ def get_status_html(engine):
12
+ # αž”αž„αŸ’αž€αžΎαž UI αž—αŸ’αž›αžΎαž„αžŸαž‰αŸ’αž‰αžΆ Status αžŸαž˜αŸ’αžšαžΆαž”αŸ‹ Keys αž“αžΈαž˜αž½αž™αŸ—
13
+ if "Gemini" in engine:
14
+ keys = [os.environ.get(f"GEMINI_API_KEY_{i}") for i in range(1, 6)]
15
+ label = "Gemini Keys"
16
+ elif "Llama" in engine:
17
+ keys = [os.environ.get(f"GROQ_API_KEY_{i}") for i in range(1, 4)]
18
+ label = "Llama Keys"
19
+ else:
20
+ key = os.environ.get("SEA_LION_API_KEY")
21
+ keys = [key] if key else []
22
+ label = "SEA-LION Key"
23
+
24
+ html = f"<div style='display: flex; gap: 10px; align-items: center; margin-bottom: 10px;'>"
25
+ html += f"<b style='color: #94a3b8; font-size: 12px;'>{label}:</b>"
26
+ for i, k in enumerate(keys):
27
+ if k:
28
+ # αž—αŸ’αž›αžΎαž„αž–αžŽαŸŒαž”αŸƒαžαž„αž›αŸ„αž (Pulse) αž”αž‰αŸ’αž‡αžΆαž€αŸ‹αžαžΆ Key αž˜αžΆαž“αž€αŸ’αž“αž»αž„αž”αŸ’αžšαž–αŸαž“αŸ’αž’
29
+ html += f"<div title='Key {i+1} Ready' style='width: 12px; height: 12px; background: #22c55e; border-radius: 50%; box-shadow: 0 0 8px #22c55e; animation: pulse 1.5s infinite;'></div>"
30
+ else:
31
+ # αž—αŸ’αž›αžΎαž„αž–αžŽαŸŒαž€αŸ’αžšαž αž˜ αž”αž‰αŸ’αž‡αžΆαž€αŸ‹αžαžΆαž’αžαŸ‹αž˜αžΆαž“ Key
32
+ html += f"<div title='Key {i+1} Empty' style='width: 12px; height: 12px; background: #ef4444; border-radius: 50%;'></div>"
33
+ html += "</div>"
34
+ return html
35
+
36
  @staticmethod
37
  def translate_gemini(prompt):
38
  keys = [os.environ.get(f"GEMINI_API_KEY_{i}") for i in range(1, 6) if os.environ.get(f"GEMINI_API_KEY_{i}")]
39
  for key in keys:
40
  try:
41
  url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp:generateContent?key={key}"
42
+ instruction = "Return ONLY direct translation. Be natural. If asked again, provide an alternative phrasing. Preserve format."
 
43
  res = requests.post(url, json={"contents": [{"parts": [{"text": f"{instruction}\n\n{prompt}"}]}]}, timeout=15)
44
  if res.status_code == 200:
45
  return res.json()['candidates'][0]['content']['parts'][0]['text'].strip()
46
  except: continue
47
+ return "❌ Gemini API Error: Keys might be exhausted."
48
 
49
  @staticmethod
50
  def translate_llama(prompt):
 
55
  payload = {
56
  "model": "llama-3.3-70b-versatile",
57
  "messages": [
58
+ {"role": "system", "content": "DIRECT TRANSLATION ONLY. Be natural. Provide alternative wording on repeat requests."},
59
  {"role": "user", "content": prompt}
60
+ ],
61
+ "temperature": 0.7
62
  }
63
  res = requests.post("https://api.groq.com/openai/v1/chat/completions", headers=headers, json=payload, timeout=15)
64
  if res.status_code == 200:
 
68
 
69
  @staticmethod
70
  def translate_sealion(prompt):
 
71
  key = os.environ.get("SEA_LION_API_KEY")
72
  if not key: return "❌ Missing SEA_LION_API_KEY"
73
  try:
 
75
  headers = {"Authorization": f"Bearer {key}", "Content-Type": "application/json"}
76
  payload = {
77
  "model": "aisingapore/Gemma-SEA-LION-v4-27B-IT",
78
+ "messages": [{"role": "user", "content": f"Translate to Khmer (Natural phrasing, return ONLY translation): {prompt}"}],
79
+ "temperature": 0.7
 
 
 
 
80
  }
81
  res = requests.post(url, headers=headers, json=payload, timeout=20)
82
  if res.status_code == 200:
83
  return res.json()['choices'][0]['message']['content'].strip()
84
+ return f"❌ SEA-LION Error"
85
  except: return "❌ Connection Error"
86
 
87
  def translator_hub(text, target_lang, engine):
88
  if not text.strip(): return ""
89
  lang_name = target_lang.split(" ")[-1]
90
+ prompt = f"Target Language: {lang_name}\nText: {text}"
91
 
92
  if "Gemini" in engine: return AIService.translate_gemini(prompt)
93
  elif "Llama" in engine: return AIService.translate_llama(prompt)
94
+ else: return AIService.translate_sealion(prompt)
 
95
 
96
  # ==========================================
97
+ # ្. αžŸαŸ’αž‚αŸ’αžšαžΈαž” PWA, CSS αž“αž·αž„ UI Layout αžαŸ’αž˜αžΈ
98
  # ==========================================
99
+ pwa_js = """
100
  function initPWA() {
101
+ const s = document.createElement('script');
102
+ s.src = 'https://cdn.jsdelivr.net/npm/canvas-confetti@1.6.0/dist/confetti.browser.min.js';
103
+ document.head.appendChild(s);
 
 
 
 
 
 
 
 
 
 
104
 
105
+ // Pulse animation for API lights
106
+ const style = document.createElement('style');
107
+ style.innerHTML = `@keyframes pulse { 0% { opacity: 1; } 50% { opacity: 0.4; } 100% { opacity: 1; } }`;
108
+ document.head.appendChild(style);
 
 
 
 
 
 
 
 
 
 
 
 
109
 
110
  window.addEventListener('click', (e) => {
111
  if (typeof confetti === 'function') {
 
116
  """
117
 
118
  css_style = """
119
+ body { background-color: #0d1117 !important; color: white !important; }
120
+ .api-box { background: #161b22; border-radius: 8px; padding: 10px; border: 1px solid #30363d; margin-top: -10px; margin-bottom: 10px; }
121
  .center-btn { justify-content: center !important; gap: 8px !important; }
122
  .small-btn { max-width: 85px !important; min-width: 70px !important; font-size: 13px !important; padding: 4px !important; }
123
  .translate-btn { min-width: 150px !important; font-weight: bold !important; background: linear-gradient(45deg, #1e40af, #3b82f6) !important; color: white !important; }
124
  """
125
 
126
+ with gr.Blocks(css=css_style, head=f"<script>{pwa_js}</script>") as demo:
127
  demo.load(None, None, None, js="() => { initPWA(); }")
 
128
  gr.Markdown("<h2 style='text-align: center; color: #60a5fa;'>πŸŽ† SRT SMART ULTIMATE πŸ‡°πŸ‡­</h2>")
129
 
130
  with gr.Column():
 
135
  value="πŸ‡°πŸ‡­ Khmer", label="αž”αž€αž”αŸ’αžšαŸ‚αž‡αžΆαž—αžΆαžŸαžΆ"
136
  )
137
 
138
+ # αž”αŸ’αžšαž’αž”αŸ‹αž”αž„αŸ’αž αžΆαž‰ Status API Keys
139
+ api_status_ui = gr.HTML(AIService.get_status_html("πŸ’Ž Gemini"), elem_classes="api-box")
140
+
141
+ input_text = gr.Textbox(label="αž’αžαŸ’αžαž”αž‘αžŠαžΎαž˜", lines=5, placeholder="αž”αž·αž‘αž—αŸ’αž‡αžΆαž”αŸ‹ SRT αž¬αž’αžαŸ’αžαž”αž‘...")
142
 
143
  with gr.Row(elem_classes="center-btn"):
144
  clear_btn = gr.Button("πŸ—‘οΈ αž›αž»αž”", variant="secondary", elem_classes="small-btn")
145
  submit_btn = gr.Button("οΏ½οΏ½οΏ½ αž”αž€αž”αŸ’αžšαŸ‚αž₯ទូវ", variant="primary", elem_classes="translate-btn")
146
  copy_btn = gr.Button("πŸ“‹ αž…αž˜αŸ’αž›αž„", variant="secondary", elem_classes="small-btn")
147
 
148
+ output_text = gr.Textbox(label="αž›αž‘αŸ’αž’αž•αž›", lines=8, interactive=False)
149
 
150
+ # αž”αŸ’αžαžΌαžš Status αž—αŸ’αž›αžΎαž„αž–αŸαž›αžŠαžΌαžšαž˜αŸ‰αžΌαžŠαŸ‚αž›
151
+ engine_opt.change(fn=AIService.get_status_html, inputs=engine_opt, outputs=api_status_ui)
152
+
153
  submit_btn.click(fn=translator_hub, inputs=[input_text, lang_opt, engine_opt], outputs=output_text)
154
  clear_btn.click(lambda: ["", ""], None, [input_text, output_text])
155
  copy_btn.click(None, inputs=output_text, js="(v) => { if(v){ navigator.clipboard.writeText(v); alert('αž”αžΆαž“αž…αž˜αŸ’αž›αž„! πŸŽ†'); } }")