takumi0002 commited on
Commit
a9e0c2a
Β·
verified Β·
1 Parent(s): 30dc47c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +56 -123
app.py CHANGED
@@ -9,12 +9,6 @@ key_status_registry = {}
9
  class AIService:
10
  @staticmethod
11
  def get_all_keys(prefix):
12
- # αž€αžšαžŽαžΈαž–αž·αžŸαŸαžŸαžŸαž˜αŸ’αžšαžΆαž”αŸ‹ DeepSeek αžŠαŸ‚αž›αž˜αžΆαž“ Key αžαŸ‚αž˜αž½αž™
13
- if prefix == "DEEPSEEK_API_KEY":
14
- key = os.environ.get("DEEPSEEK_API_KEY")
15
- return [key] if key else []
16
-
17
- # αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž˜αŸ‰αžΌαžŠαŸ‚αž›αž•αŸ’αžŸαŸαž„αž‘αŸ€αž αžšαž€αŸ’αžŸαžΆαžαžΆαž˜ Logic αžŠαžΎαž˜αžšαž”αžŸαŸ‹αž˜αŸ
18
  keys = []
19
  i = 1
20
  while True:
@@ -29,7 +23,6 @@ class AIService:
29
 
30
  @staticmethod
31
  def get_status_html(engine, target_lang=None):
32
- # αž€αŸ†αžŽαžαŸ‹ Prefix αž‘αŸ…αžαžΆαž˜αž˜αŸ‰αžΌαžŠαŸ‚αž›
33
  if "Gemini" in engine:
34
  prefix = "GEMINI_API_KEY_"
35
  elif "Llama" in engine:
@@ -43,40 +36,52 @@ class AIService:
43
  label = engine.split(" ")[-1]
44
  status_label = "αžŸαŸ’αžαžΆαž“αž—αžΆαž–/Status"
45
  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>"
46
-
47
- if not keys:
48
- html += "<span style='color: #ef4444; font-size: 10px;'>αžšαž€αž˜αž·αž“αžƒαžΎαž‰ Key</span>"
49
- else:
50
- for k in keys:
51
- state = key_status_registry.get(k, "ready")
52
- color = "#22c55e" if state == "ready" else "#ef4444"
53
- html += f"<div style='width: 10px; height: 10px; background: {color}; border-radius: 50%; box-shadow: 0 0 5px {color};'></div>"
54
  return html + "</div>"
55
 
56
  @staticmethod
57
  def call_api(engine, prompt):
58
- temp = 0.8
59
 
60
- # --- πŸ‹ DEEPSEEK (αž˜αŸ‰αžΌαžŠαŸ‚αž›αžαŸ’αž˜αžΈαžŠαŸ‚αž›αž˜αŸαž…αž„αŸ‹αž”αžΆαž“) ---
61
  if "DeepSeek" in engine:
62
  keys = AIService.get_all_keys("DEEPSEEK_API_KEY")
63
- if keys:
64
- key = keys[0]
65
- try:
66
- res = requests.post("https://api.deepseek.com/chat/completions",
67
- headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json"},
68
- json={
69
- "model": "deepseek-chat",
70
- "messages": [{"role": "user", "content": prompt}],
71
- "temperature": temp
72
- }, timeout=60)
73
- if res.status_code == 200:
74
- key_status_registry[key] = "ready"
75
- return res.json()['choices'][0]['message']['content'].strip()
76
- key_status_registry[key] = "dead"
77
- except: pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
- # --- πŸ’Ž Gemini (αžšαž€αŸ’αžŸαžΆαž‘αž»αž€αž“αŸ…αžŠαžŠαŸ‚αž›) ---
80
  elif "Gemini" in engine:
81
  keys = AIService.get_all_keys("GEMINI_API_KEY_")
82
  for key in keys:
@@ -84,7 +89,7 @@ class AIService:
84
  url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp:generateContent?key={key}"
85
  res = requests.post(url, json={
86
  "contents": [{"parts": [{"text": prompt}]}],
87
- "generationConfig": {"temperature": temp}
88
  }, timeout=45)
89
  if res.status_code == 200:
90
  key_status_registry[key] = "ready"
@@ -92,29 +97,29 @@ class AIService:
92
  key_status_registry[key] = "dead"
93
  except: continue
94
 
95
- # --- πŸ¦™ Llama (αžšαž€αŸ’αžŸαžΆαž‘αž»αž€αž“αŸ…αžŠαžŠαŸ‚αž›) ---
96
  elif "Llama" in engine:
97
  keys = AIService.get_all_keys("GROQ_API_KEY_")
98
  for key in keys:
99
  try:
100
  res = requests.post("https://api.groq.com/openai/v1/chat/completions",
101
  headers={"Authorization": f"Bearer {key}"},
102
- json={"model": "llama-3.3-70b-versatile", "messages": [{"role": "user", "content": prompt}], "temperature": temp}, timeout=30)
103
  if res.status_code == 200:
104
  key_status_registry[key] = "ready"
105
  return res.json()['choices'][0]['message']['content'].strip()
106
  key_status_registry[key] = "dead"
107
  except: continue
108
 
109
- # --- 🦁 SEA-LION (αžšαž€αŸ’αžŸαžΆαž‘αž»αž€αž“αŸ…αžŠαžŠαŸ‚αž›) ---
110
- else:
111
  key = os.environ.get("SEA_LION_API_KEY")
112
  try:
113
  res = requests.post("https://api.sea-lion.ai/v1/chat/completions",
114
  headers={"Authorization": f"Bearer {key}"},
115
  json={
116
  "model": "aisingapore/Gemma-SEA-LION-v4-27B-IT",
117
- "messages": [{"role": "system", "content": "You are an expert translator. Preserve proper names. Output ONLY translation."},
118
  {"role": "user", "content": prompt}],
119
  "temperature": 0.7
120
  }, timeout=60)
@@ -129,107 +134,35 @@ def translator_hub(text, target_lang, engine):
129
  if not text.strip(): return "", AIService.get_status_html(engine)
130
  lang_name = re.sub(r'[^\w\s]', '', target_lang).strip()
131
 
132
- instruction = f"""Translate to {lang_name} STRICTLY:
133
- 1. OUTPUT ONLY translation. No notes, no preamble.
134
- 2. SLANG & IDIOMS: Understand and adapt slang, idioms, and metaphors naturally into {lang_name}. Don't translate literally; capture the true meaning and "vibe".
135
- 3. CONTEXT & PRONOUNS:
136
- - Modern Context: Use natural/contemporary slang.
137
- - Ancient Context: Use formal, poetic, or royal language where appropriate.
138
- - Family/Close: Use αž”αž„, αž’αžΌαž“, αž”αŸ’αž’αžΌαž“, αž˜αŸ‰αžΆαž€αŸ‹, αž”αŸ‰αžΆ, αž–αžΌ, αž˜αžΈαž„.
139
- - Couples: Use αž”αž„, αž’αžΌαž“.
140
- - Enemies/Fighting/Informal: Use αž’αž‰, αž―αž„, αž’αžΆαž αŸ‚αž„, αž›αŸ„αž€αž―αž„ where suitable for the mood.
141
- 4. SRT FORMAT: Preserve SRT timing/numbering. Keep proper names in ORIGINAL characters (e.g. Xiao Fan, Chang Sheng).
142
- 5. NO MIXED LANGUAGES: No English words allowed in the {lang_name} output.
143
- 6. VARIETY: Be creative. If asked to translate the same text again, provide subtle variations in vocabulary."""
144
-
145
  prompt = f"{instruction}\n\nCONTENT:\n{text}"
146
- result = AIService.call_api(engine, prompt)
147
 
 
148
  if result:
149
  cleaned = re.sub(r'```[a-zA-Z]*\n?|```', '', result).strip()
150
- cleaned = re.sub(r'(?i)^(here is|translation|translated content):', '', cleaned).strip()
151
  return cleaned, AIService.get_status_html(engine)
152
-
153
- return "❌ Error (API Connection)", AIService.get_status_html(engine)
154
 
155
- css = """
156
- * { cursor: default; }
157
- button, .btn-trans, .btn-clear, .btn-copy { cursor: pointer !important; }
158
- textarea { cursor: text !important; }
159
- body {
160
- background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%) !important;
161
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
162
- }
163
- .gr-markdown h1 {
164
- text-align: center;
165
- background: linear-gradient(90deg, #60a5fa, #a78bfa, #f472b6);
166
- -webkit-background-clip: text;
167
- background-clip: text;
168
- color: transparent !important;
169
- font-weight: 800;
170
- font-size: 2.5rem !important;
171
- padding: 20px 0;
172
- margin-bottom: 10px !important;
173
- }
174
- .gr-box, .gr-panel {
175
- background: rgba(30, 41, 59, 0.9) !important;
176
- backdrop-filter: blur(10px);
177
- border: 1px solid rgba(255, 255, 255, 0.1) !important;
178
- border-radius: 12px !important;
179
- }
180
- textarea {
181
- background: rgba(15, 23, 42, 0.8) !important;
182
- color: #e2e8f0 !important;
183
- }
184
- .btn-trans {
185
- background: linear-gradient(135deg, #059669 0%, #10b981 100%) !important;
186
- color: white !important;
187
- }
188
- .btn-copy {
189
- background: linear-gradient(135deg, #2563eb 0%, #3b82f6 100%) !important;
190
- color: white !important;
191
- }
192
- """
193
 
194
  with gr.Blocks(title="SRT Pro", css=css) as demo:
195
- gr.Markdown("<h1>🎬 SMART TRANSLATOR PRO</h1>")
196
 
197
  with gr.Row():
198
  with gr.Column(scale=1):
199
- lang_opt = gr.Dropdown(
200
- ["πŸ‡°πŸ‡­ Khmer", "πŸ‡ΊπŸ‡Έ English", "πŸ‡¨πŸ‡³ Chinese", "πŸ‡ΉπŸ‡­ Thai", "πŸ‡―πŸ‡΅ Japanese", "πŸ‡°πŸ‡· Korean"],
201
- value="πŸ‡°πŸ‡­ Khmer",
202
- label="Target Language (αž—αžΆαžŸαžΆαž‚αŸ„αž›αžŠαŸ…)"
203
- )
204
- engine_opt = gr.Radio(
205
- ["πŸ’Ž Gemini", "πŸ‹ DeepSeek", "πŸ¦™ Llama", "🦁 SEA-LION"],
206
- value="πŸ’Ž Gemini",
207
- label="AI Model (αž˜αŸ‰αžΌαžŠαŸ‚αž›)"
208
- )
209
  status_ui = gr.HTML(AIService.get_status_html("πŸ’Ž Gemini"))
210
- input_box = gr.Textbox(
211
- label="Original Content (αž’αžαŸ’αžαž”αž‘αžŠαžΎαž˜)",
212
- lines=12,
213
- placeholder="Paste text or SRT content here..."
214
- )
215
-
216
- with gr.Row():
217
- btn_clear = gr.Button("πŸ—‘οΈ Clear", variant="secondary")
218
- btn_trans = gr.Button("⚑ Translate", variant="primary", elem_classes="btn-trans")
219
 
220
  with gr.Column(scale=1):
221
- output_box = gr.Textbox(
222
- label="Translated Result (αž›αž‘αŸ’αž’αž•αž›αž”αž€αž”αŸ’αžšαŸ‚)",
223
- lines=23,
224
- interactive=False
225
- )
226
- btn_copy = gr.Button("πŸ“‹ Copy Result", elem_classes="btn-copy")
227
 
228
- # Update Status UI when switching model
229
  engine_opt.change(AIService.get_status_html, inputs=[engine_opt], outputs=[status_ui])
230
-
231
  btn_trans.click(translator_hub, [input_box, lang_opt, engine_opt], [output_box, status_ui])
232
- btn_clear.click(lambda: ("", ""), None, [input_box, output_box])
233
  btn_copy.click(None, output_box, js="(v) => { navigator.clipboard.writeText(v); alert('βœ… Copied!'); }")
234
 
235
  if __name__ == "__main__":
 
9
  class AIService:
10
  @staticmethod
11
  def get_all_keys(prefix):
 
 
 
 
 
 
12
  keys = []
13
  i = 1
14
  while True:
 
23
 
24
  @staticmethod
25
  def get_status_html(engine, target_lang=None):
 
26
  if "Gemini" in engine:
27
  prefix = "GEMINI_API_KEY_"
28
  elif "Llama" in engine:
 
36
  label = engine.split(" ")[-1]
37
  status_label = "αžŸαŸ’αžαžΆαž“αž—αžΆαž–/Status"
38
  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>"
39
+ for k in keys:
40
+ state = key_status_registry.get(k, "ready")
41
+ color = "#22c55e" if state == "ready" else "#ef4444"
42
+ html += f"<div style='width: 10px; height: 10px; background: {color}; border-radius: 50%; box-shadow: 0 0 5px {color};'></div>"
 
 
 
 
43
  return html + "</div>"
44
 
45
  @staticmethod
46
  def call_api(engine, prompt):
47
+ temp = 0.7
48
 
49
+ # --- πŸ‹ DEEPSEEK SECTION (Combined Logic for Free Tier) ---
50
  if "DeepSeek" in engine:
51
  keys = AIService.get_all_keys("DEEPSEEK_API_KEY")
52
+ # αž”αž‰αŸ’αž‡αžΈαž˜αŸ‰αžΌαžŠαŸ‚αž›αžŠαŸ‚αž›αžαŸ’αžšαžΌαžœαžŸαžΆαž€αž›αŸ’αž”αž„ (V3 αž˜αž»αž“, αžšαž½αž…αž˜αž€ R1)
53
+ model_attempts = ["deepseek-chat", "deepseek-reasoner"]
54
+
55
+ for key in keys:
56
+ for ds_model in model_attempts:
57
+ try:
58
+ res = requests.post("https://api.deepseek.com/chat/completions",
59
+ headers={
60
+ "Authorization": f"Bearer {key}",
61
+ "Content-Type": "application/json"
62
+ },
63
+ json={
64
+ "model": ds_model,
65
+ "messages": [
66
+ {"role": "system", "content": "You are a professional SRT translator. Output translation only."},
67
+ {"role": "user", "content": prompt}
68
+ ],
69
+ "temperature": 1.0 if ds_model == "deepseek-reasoner" else temp
70
+ }, timeout=90)
71
+
72
+ if res.status_code == 200:
73
+ key_status_registry[key] = "ready"
74
+ content = res.json()['choices'][0]['message']['content'].strip()
75
+ # αž›αž»αž”αž€αžΆαžšαž‚αž·αžαžšαž”αžŸαŸ‹ R1 αž…αŸαž‰αž”αžΎαžœαžΆαž˜αžΆαž“αžŸαž›αŸ‹αž˜αž€
76
+ return re.sub(r'<think>.*?</think>', '', content, flags=re.DOTALL).strip()
77
+
78
+ # αž”αžΎ Error 429 (Rate Limit) ឬ αž•αŸ’αžŸαŸαž„αŸ— αžœαžΆαž“αžΉαž„αžŸαžΆαž€αž˜αŸ‰αžΌαžŠαŸ‚αž›αž”αž“αŸ’αž‘αžΆαž”αŸ‹ ឬ Key αž”αž“αŸ’αž‘αžΆαž”αŸ‹
79
+ continue
80
+ except:
81
+ continue
82
+ key_status_registry[key] = "dead"
83
 
84
+ # --- πŸ’Ž Gemini (Original) ---
85
  elif "Gemini" in engine:
86
  keys = AIService.get_all_keys("GEMINI_API_KEY_")
87
  for key in keys:
 
89
  url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp:generateContent?key={key}"
90
  res = requests.post(url, json={
91
  "contents": [{"parts": [{"text": prompt}]}],
92
+ "generationConfig": {"temperature": 0.8}
93
  }, timeout=45)
94
  if res.status_code == 200:
95
  key_status_registry[key] = "ready"
 
97
  key_status_registry[key] = "dead"
98
  except: continue
99
 
100
+ # --- πŸ¦™ Llama (Original) ---
101
  elif "Llama" in engine:
102
  keys = AIService.get_all_keys("GROQ_API_KEY_")
103
  for key in keys:
104
  try:
105
  res = requests.post("https://api.groq.com/openai/v1/chat/completions",
106
  headers={"Authorization": f"Bearer {key}"},
107
+ json={"model": "llama-3.3-70b-versatile", "messages": [{"role": "user", "content": prompt}], "temperature": 0.8}, timeout=30)
108
  if res.status_code == 200:
109
  key_status_registry[key] = "ready"
110
  return res.json()['choices'][0]['message']['content'].strip()
111
  key_status_registry[key] = "dead"
112
  except: continue
113
 
114
+ # --- 🦁 SEA-LION (Original) ---
115
+ else:
116
  key = os.environ.get("SEA_LION_API_KEY")
117
  try:
118
  res = requests.post("https://api.sea-lion.ai/v1/chat/completions",
119
  headers={"Authorization": f"Bearer {key}"},
120
  json={
121
  "model": "aisingapore/Gemma-SEA-LION-v4-27B-IT",
122
+ "messages": [{"role": "system", "content": "You are an expert translator."},
123
  {"role": "user", "content": prompt}],
124
  "temperature": 0.7
125
  }, timeout=60)
 
134
  if not text.strip(): return "", AIService.get_status_html(engine)
135
  lang_name = re.sub(r'[^\w\s]', '', target_lang).strip()
136
 
137
+ instruction = f"Translate to {lang_name} STRICTLY. OUTPUT ONLY translation. Keep SRT timing and names original."
 
 
 
 
 
 
 
 
 
 
 
 
138
  prompt = f"{instruction}\n\nCONTENT:\n{text}"
 
139
 
140
+ result = AIService.call_api(engine, prompt)
141
  if result:
142
  cleaned = re.sub(r'```[a-zA-Z]*\n?|```', '', result).strip()
 
143
  return cleaned, AIService.get_status_html(engine)
144
+ return "❌ Error: API Unavailable", AIService.get_status_html(engine)
 
145
 
146
+ css = "* { cursor: default; } .btn-trans { background: linear-gradient(135deg, #059669 0%, #10b981 100%) !important; color: white !important; }"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
 
148
  with gr.Blocks(title="SRT Pro", css=css) as demo:
149
+ gr.Markdown("<h1 style='text-align: center;'>🎬 SMART TRANSLATOR PRO</h1>")
150
 
151
  with gr.Row():
152
  with gr.Column(scale=1):
153
+ lang_opt = gr.Dropdown(["πŸ‡°πŸ‡­ Khmer", "πŸ‡ΊπŸ‡Έ English", "πŸ‡¨πŸ‡³ Chinese", "πŸ‡ΉπŸ‡­ Thai"], value="πŸ‡°πŸ‡­ Khmer", label="Target Language")
154
+ # αž”αž„αŸ’αž αžΆαž‰αžαŸ‚ DeepSeek αž˜αž½αž™αž‚αžαŸ‹αžαžΆαž˜αž˜αŸαž…αž„αŸ‹αž”αžΆαž“
155
+ engine_opt = gr.Radio(["πŸ’Ž Gemini", "πŸ‹ DeepSeek", "πŸ¦™ Llama", "🦁 SEA-LION"], value="πŸ’Ž Gemini", label="AI Model")
 
 
 
 
 
 
 
156
  status_ui = gr.HTML(AIService.get_status_html("πŸ’Ž Gemini"))
157
+ input_box = gr.Textbox(label="Original Content", lines=10)
158
+ btn_trans = gr.Button("⚑ Translate", variant="primary", elem_classes="btn-trans")
 
 
 
 
 
 
 
159
 
160
  with gr.Column(scale=1):
161
+ output_box = gr.Textbox(label="Translated Result", lines=20, interactive=False)
162
+ btn_copy = gr.Button("πŸ“‹ Copy Result")
 
 
 
 
163
 
 
164
  engine_opt.change(AIService.get_status_html, inputs=[engine_opt], outputs=[status_ui])
 
165
  btn_trans.click(translator_hub, [input_box, lang_opt, engine_opt], [output_box, status_ui])
 
166
  btn_copy.click(None, output_box, js="(v) => { navigator.clipboard.writeText(v); alert('βœ… Copied!'); }")
167
 
168
  if __name__ == "__main__":