takumi0002 commited on
Commit
dd0d837
Β·
verified Β·
1 Parent(s): 0f15f5c

Update app.py

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