NurseCitizenDeveloper commited on
Commit
e57fc7d
Β·
verified Β·
1 Parent(s): 8a50211

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +286 -48
app.py CHANGED
@@ -1,6 +1,18 @@
1
  import gradio as gr
 
2
  from carebridge_client import CareBridgeTranslator
3
 
 
 
 
 
 
 
 
 
 
 
 
4
  translator = None
5
 
6
  def load_translator():
@@ -9,83 +21,309 @@ def load_translator():
9
  translator = CareBridgeTranslator()
10
  return translator
11
 
12
- LANGUAGES = ["English", "Polish", "Romanian", "Punjabi", "Urdu", "Portuguese", "Spanish", "Arabic", "Bengali", "Gujarati", "Italian"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  def translate_message(text, source_lang, target_lang):
15
  if not text:
16
  return "", "", None
17
- yield "Translating...", "<div style='font-size:2rem;text-align:center;padding:40px;background:#dbeafe;border-radius:16px;'>Translating...</div>", None
 
18
  app_translator = load_translator()
19
  result = app_translator.translate_text(text, source_lang, target_lang)
20
  tts_file = app_translator.speak_text(result, target_lang)
21
- yield result, f"<div style='font-size:2.5rem;text-align:center;padding:40px;background:linear-gradient(135deg,#dbeafe,#e0e7ff);border-radius:16px;border:2px solid #6366f1;font-weight:600;'>{result}</div>", tts_file
 
22
 
23
  def translate_speech(audio, source_lang, target_lang):
24
  if audio is None:
25
  return "", "", None
26
- yield "Listening...", "<div style='font-size:2rem;text-align:center;padding:40px;background:#dbeafe;border-radius:16px;'>Processing...</div>", None
 
27
  app_translator = load_translator()
28
  result = app_translator.translate_audio(audio, source_lang, target_lang)
29
  tts_file = app_translator.speak_text(result, target_lang)
30
- yield result, f"<div style='font-size:2.5rem;text-align:center;padding:40px;background:linear-gradient(135deg,#dbeafe,#e0e7ff);border-radius:16px;border:2px solid #6366f1;font-weight:600;'>{result}</div>", tts_file
 
31
 
32
  def translate_leaflet(image, source_lang, target_lang):
33
  if image is None:
34
  return "", "", None
35
- yield "Scanning...", "<div style='font-size:2rem;text-align:center;padding:40px;background:#dbeafe;border-radius:16px;'>Scanning...</div>", None
 
36
  app_translator = load_translator()
37
  result = app_translator.translate_image(image, source_lang, target_lang)
38
  tts_file = app_translator.speak_text(result, target_lang)
39
- yield result, f"<div style='font-size:1.5rem;padding:20px;background:#f8fafc;border-radius:12px;'>{result}</div>", tts_file
 
40
 
41
- css = """
42
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');
43
- * { font-family: 'Inter', sans-serif !important; }
44
- .gradio-container { max-width: 1200px !important; margin: auto !important; }
45
- """
 
 
 
 
 
46
 
47
- with gr.Blocks(css=css, title="SIMBOTI Live") as app:
48
- gr.HTML("<div style='text-align:center;padding:40px;background:white;border-radius:20px;margin-bottom:30px;box-shadow:0 4px 20px rgba(0,0,0,0.08);'><h1 style='font-size:2.5rem;font-weight:700;background:linear-gradient(135deg,#4F46E5,#06B6D4);-webkit-background-clip:text;-webkit-text-fill-color:transparent;'>SIMBOTI Live</h1><p style='color:#64748b;'>Speech Intelligent Multimodal Bot for Outreach Translation Implementation</p><p style='margin-top:16px;'>Built with <span style='background:#fef3c7;padding:2px 6px;border-radius:4px;font-weight:600;'>TranslateGemma 4B</span></p></div>")
49
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  with gr.Row():
51
- source_lang = gr.Dropdown(LANGUAGES, value="English", label="From (Source)")
52
- target_lang = gr.Dropdown(LANGUAGES, value="Polish", label="To (Target)")
53
-
54
- with gr.Tabs():
55
- with gr.TabItem("πŸ’¬ Text"):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  with gr.Row():
57
- with gr.Column():
58
- clinician_text = gr.Textbox(label="Your Message", placeholder="e.g., Do you have any allergies?", lines=4)
59
- translate_btn = gr.Button("πŸš€ Translate & Speak", variant="primary")
60
- with gr.Column():
61
- patient_output_html = gr.HTML()
62
- patient_audio = gr.Audio(label="Audio", autoplay=True)
 
 
 
 
63
  patient_output_raw = gr.Textbox(visible=False)
64
- translate_btn.click(translate_message, [clinician_text, source_lang, target_lang], [patient_output_raw, patient_output_html, patient_audio])
65
-
66
- with gr.TabItem("πŸŽ™οΈ Speech"):
 
 
 
 
 
 
 
 
 
 
 
 
67
  with gr.Row():
68
- with gr.Column():
69
- mic_input = gr.Audio(sources=["microphone"], type="filepath", label="Record")
70
- speech_btn = gr.Button("πŸš€ Translate", variant="primary")
71
- with gr.Column():
72
- speech_html = gr.HTML()
73
- speech_audio = gr.Audio(label="Audio", autoplay=True)
74
- speech_raw = gr.Textbox(visible=False)
75
- speech_btn.click(translate_speech, [mic_input, source_lang, target_lang], [speech_raw, speech_html, speech_audio])
76
-
77
- with gr.TabItem("πŸ“„ Document"):
 
 
 
 
 
 
 
 
 
 
 
 
78
  with gr.Row():
79
- with gr.Column():
80
- doc_image = gr.Image(type="pil", label="Upload Photo")
81
- doc_btn = gr.Button("πŸš€ Scan & Translate", variant="primary")
82
- with gr.Column():
83
- doc_html = gr.HTML()
84
- doc_audio = gr.Audio(label="Audio")
85
- doc_raw = gr.Textbox(visible=False)
86
- doc_btn.click(translate_leaflet, [doc_image, source_lang, target_lang], [doc_raw, doc_html, doc_audio])
87
-
88
- gr.HTML("<div style='text-align:center;padding:30px;color:#64748b;'>πŸ”’ Privacy First: All translations run on-device via ZeroGPU</div>")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
 
90
  if __name__ == "__main__":
91
  app.launch()
 
1
  import gradio as gr
2
+ import os
3
  from carebridge_client import CareBridgeTranslator
4
 
5
+ # --- Asset Management ---
6
+ if not os.path.exists("simboti_logo.jpg"):
7
+ try:
8
+ from assets import LOGO_BASE64
9
+ import base64
10
+ with open("simboti_logo.jpg", "wb") as f:
11
+ f.write(base64.b64decode(LOGO_BASE64))
12
+ except ImportError:
13
+ pass # Ignore if assets.py not found
14
+
15
+ # --- Initialize Client ---
16
  translator = None
17
 
18
  def load_translator():
 
21
  translator = CareBridgeTranslator()
22
  return translator
23
 
24
+ # --- Languages ---
25
+ LANGUAGES = [
26
+ "English", "Polish", "Romanian", "Punjabi", "Urdu",
27
+ "Portuguese", "Spanish", "Arabic", "Bengali", "Gujarati", "Italian"
28
+ ]
29
+
30
+ # --- Custom CSS for Premium Design ---
31
+ CUSTOM_CSS = """
32
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
33
+
34
+ * {
35
+ font-family: 'Inter', sans-serif !important;
36
+ }
37
+
38
+ .gradio-container {
39
+ max-width: 1200px !important;
40
+ margin: auto !important;
41
+ background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%) !important;
42
+ }
43
+
44
+ .main-header {
45
+ text-align: center;
46
+ padding: 40px 20px;
47
+ background: white;
48
+ border-radius: 20px;
49
+ margin-bottom: 30px;
50
+ box-shadow: 0 4px 20px rgba(0,0,0,0.08);
51
+ }
52
+
53
+ .main-header h1 {
54
+ font-size: 2.5rem;
55
+ font-weight: 700;
56
+ background: linear-gradient(135deg, #4F46E5 0%, #06B6D4 100%);
57
+ -webkit-background-clip: text;
58
+ -webkit-text-fill-color: transparent;
59
+ margin-bottom: 10px;
60
+ }
61
+
62
+ .main-header p {
63
+ color: #64748b;
64
+ font-size: 1.1rem;
65
+ }
66
+
67
+ .feature-card {
68
+ background: white;
69
+ border-radius: 16px;
70
+ padding: 24px;
71
+ box-shadow: 0 2px 12px rgba(0,0,0,0.06);
72
+ border: 1px solid #e2e8f0;
73
+ transition: all 0.3s ease;
74
+ }
75
+
76
+ .feature-card:hover {
77
+ box-shadow: 0 8px 30px rgba(0,0,0,0.12);
78
+ transform: translateY(-2px);
79
+ }
80
+
81
+ .card-title {
82
+ font-size: 1.25rem;
83
+ font-weight: 600;
84
+ color: #1e293b;
85
+ margin-bottom: 8px;
86
+ }
87
+
88
+ .card-subtitle {
89
+ color: #64748b;
90
+ font-size: 0.9rem;
91
+ }
92
+
93
+ .highlight {
94
+ background: linear-gradient(120deg, #fef3c7 0%, #fef3c7 100%);
95
+ padding: 2px 6px;
96
+ border-radius: 4px;
97
+ font-weight: 600;
98
+ }
99
 
100
+ .patient-display {
101
+ font-size: 2.5rem !important;
102
+ color: #1e293b !important;
103
+ font-weight: 600 !important;
104
+ text-align: center !important;
105
+ padding: 40px !important;
106
+ background: linear-gradient(135deg, #dbeafe 0%, #e0e7ff 100%) !important;
107
+ border-radius: 16px !important;
108
+ border: 2px solid #6366f1 !important;
109
+ min-height: 120px !important;
110
+ }
111
+
112
+ .primary-btn {
113
+ background: linear-gradient(135deg, #4F46E5 0%, #6366f1 100%) !important;
114
+ border: none !important;
115
+ color: white !important;
116
+ padding: 14px 28px !important;
117
+ font-weight: 600 !important;
118
+ border-radius: 12px !important;
119
+ font-size: 1rem !important;
120
+ transition: all 0.3s ease !important;
121
+ }
122
+
123
+ .primary-btn:hover {
124
+ transform: scale(1.02) !important;
125
+ box-shadow: 0 8px 20px rgba(79, 70, 229, 0.4) !important;
126
+ }
127
+
128
+ .language-selector {
129
+ background: white !important;
130
+ border-radius: 12px !important;
131
+ border: 2px solid #e2e8f0 !important;
132
+ }
133
+
134
+ .tab-nav button {
135
+ font-weight: 600 !important;
136
+ padding: 12px 24px !important;
137
+ }
138
+
139
+ .tab-nav button.selected {
140
+ background: linear-gradient(135deg, #4F46E5 0%, #6366f1 100%) !important;
141
+ color: white !important;
142
+ }
143
+
144
+ footer {
145
+ display: none !important;
146
+ }
147
+ """
148
+
149
+ # --- UI Functions ---
150
  def translate_message(text, source_lang, target_lang):
151
  if not text:
152
  return "", "", None
153
+
154
+ yield "Translating...", "<div class='patient-display'>⏳ Translating...</div>", None
155
  app_translator = load_translator()
156
  result = app_translator.translate_text(text, source_lang, target_lang)
157
  tts_file = app_translator.speak_text(result, target_lang)
158
+ large_display = f"<div class='patient-display'>{result}</div>"
159
+ yield result, large_display, tts_file
160
 
161
  def translate_speech(audio, source_lang, target_lang):
162
  if audio is None:
163
  return "", "", None
164
+
165
+ yield "Listening...", "<div class='patient-display'>🎧 Processing audio...</div>", None
166
  app_translator = load_translator()
167
  result = app_translator.translate_audio(audio, source_lang, target_lang)
168
  tts_file = app_translator.speak_text(result, target_lang)
169
+ large_display = f"<div class='patient-display'>{result}</div>"
170
+ yield result, large_display, tts_file
171
 
172
  def translate_leaflet(image, source_lang, target_lang):
173
  if image is None:
174
  return "", "", None
175
+
176
+ yield "Scanning...", "<div class='patient-display'>πŸ“„ Scanning document...</div>", None
177
  app_translator = load_translator()
178
  result = app_translator.translate_image(image, source_lang, target_lang)
179
  tts_file = app_translator.speak_text(result, target_lang)
180
+ large_display = f"<div class='patient-display'>{result}</div>"
181
+ yield result, large_display, tts_file
182
 
183
+ def translate_video(video, source_lang, target_lang):
184
+ if video is None:
185
+ return "", "", None
186
+
187
+ yield "Processing...", "<div class='patient-display'>πŸŽ₯ Analyzing video...</div>", None
188
+ app_translator = load_translator()
189
+ result = app_translator.translate_video(video, source_lang, target_lang)
190
+ tts_file = app_translator.speak_text(result, target_lang)
191
+ large_display = f"<div class='patient-display'>{result}</div>"
192
+ yield result, large_display, tts_file
193
 
194
+ # --- App Layout ---
195
+ with gr.Blocks(css=CUSTOM_CSS, title="SIMBOTI Live") as app:
196
 
197
+ # Header
198
+ gr.HTML("""
199
+ <div class="main-header">
200
+ <img src="file/simboti_logo.jpg" style="width: 100px; height: 100px; border-radius: 20px; margin-bottom: 16px;" />
201
+ <h1>SIMBOTI Live</h1>
202
+ <p><strong>S</strong>peech <strong>I</strong>ntelligent <strong>M</strong>ultimodal <strong>B</strong>ot for <strong>O</strong>utreach <strong>T</strong>ranslation <strong>I</strong>mplementation</p>
203
+ <p style="margin-top: 16px;">
204
+ Built with <span class="highlight">TranslateGemma 4B</span> β€’ Supports 11 clinical languages β€’ Privacy-first
205
+ </p>
206
+ </div>
207
+ """)
208
+
209
+ # Language Selection
210
  with gr.Row():
211
+ with gr.Column(scale=1):
212
+ gr.HTML("<div class='feature-card'><div class='card-title'>🌍 Source Language</div><div class='card-subtitle'>What language are you speaking?</div></div>")
213
+ source_lang = gr.Dropdown(LANGUAGES, value="English", show_label=False, container=False)
214
+ with gr.Column(scale=1):
215
+ gr.HTML("<div class='feature-card'><div class='card-title'>🎯 Target Language</div><div class='card-subtitle'>What language does the patient speak?</div></div>")
216
+ target_lang = gr.Dropdown(LANGUAGES, value="Polish", show_label=False, container=False)
217
+
218
+ gr.HTML("<br>")
219
+
220
+ # Main Tabs
221
+ with gr.Tabs() as tabs:
222
+
223
+ # Tab 1: Text Translation
224
+ with gr.TabItem("πŸ’¬ Text Translation"):
225
+ gr.HTML("""
226
+ <div class="feature-card" style="margin-bottom: 20px;">
227
+ <div class="card-title">Quick Text Translation</div>
228
+ <div class="card-subtitle">Type your message and it will be translated and <span class="highlight">spoken aloud</span> for the patient.</div>
229
+ </div>
230
+ """)
231
  with gr.Row():
232
+ with gr.Column(scale=1):
233
+ clinician_text = gr.Textbox(
234
+ label="Your Message",
235
+ placeholder="e.g., Do you have any allergies?",
236
+ lines=4
237
+ )
238
+ translate_btn = gr.Button("πŸš€ Translate & Speak", elem_classes=["primary-btn"])
239
+ with gr.Column(scale=1):
240
+ patient_output_html = gr.HTML(label="Patient Display")
241
+ patient_audio = gr.Audio(label="πŸ“’ Audio Output", autoplay=True)
242
  patient_output_raw = gr.Textbox(visible=False)
243
+
244
+ translate_btn.click(
245
+ translate_message,
246
+ inputs=[clinician_text, source_lang, target_lang],
247
+ outputs=[patient_output_raw, patient_output_html, patient_audio]
248
+ )
249
+
250
+ # Tab 2: Live Speech
251
+ with gr.TabItem("πŸŽ™οΈ Live Speech"):
252
+ gr.HTML("""
253
+ <div class="feature-card" style="margin-bottom: 20px;">
254
+ <div class="card-title">Voice-to-Voice Translation</div>
255
+ <div class="card-subtitle">Speak into the microphone and SIMBOTI will <span class="highlight">translate in real-time</span>.</div>
256
+ </div>
257
+ """)
258
  with gr.Row():
259
+ with gr.Column(scale=1):
260
+ mic_input = gr.Audio(sources=["microphone"], type="filepath", label="🎀 Record Your Voice")
261
+ speech_translate_btn = gr.Button("πŸš€ Translate Speech", elem_classes=["primary-btn"])
262
+ with gr.Column(scale=1):
263
+ speech_output_html = gr.HTML(label="Patient Display")
264
+ speech_audio = gr.Audio(label="πŸ“’ Translated Audio", autoplay=True)
265
+ speech_output_raw = gr.Textbox(visible=False)
266
+
267
+ speech_translate_btn.click(
268
+ translate_speech,
269
+ inputs=[mic_input, source_lang, target_lang],
270
+ outputs=[speech_output_raw, speech_output_html, speech_audio]
271
+ )
272
+
273
+ # Tab 3: Document Scan
274
+ with gr.TabItem("πŸ“„ Document Scan"):
275
+ gr.HTML("""
276
+ <div class="feature-card" style="margin-bottom: 20px;">
277
+ <div class="card-title">Document & Leaflet Translation</div>
278
+ <div class="card-subtitle">Upload a photo of medication instructions, consent forms, or any clinical document.</div>
279
+ </div>
280
+ """)
281
  with gr.Row():
282
+ with gr.Column(scale=1):
283
+ doc_image = gr.Image(type="pil", label="πŸ“· Upload Document Photo")
284
+ doc_translate_btn = gr.Button("πŸš€ Scan & Translate", elem_classes=["primary-btn"])
285
+ with gr.Column(scale=1):
286
+ doc_result_html = gr.HTML(label="Translated Text")
287
+ doc_audio = gr.Audio(label="πŸ“’ Read Aloud", autoplay=False)
288
+ doc_result_raw = gr.Textbox(visible=False)
289
+
290
+ doc_translate_btn.click(
291
+ translate_leaflet,
292
+ inputs=[doc_image, source_lang, target_lang],
293
+ outputs=[doc_result_raw, doc_result_html, doc_audio]
294
+ )
295
+
296
+ # Tab 4: Video OCR
297
+ with gr.TabItem("πŸŽ₯ Video Translation"):
298
+ gr.HTML("""
299
+ <div class="feature-card" style="margin-bottom: 20px;">
300
+ <div class="card-title">Video Text Extraction</div>
301
+ <div class="card-subtitle">Extract and translate text from videos - useful for <span class="highlight">instructional videos</span>.</div>
302
+ </div>
303
+ """)
304
+ with gr.Row():
305
+ with gr.Column(scale=1):
306
+ video_input = gr.Video(label="🎬 Upload Video")
307
+ video_translate_btn = gr.Button("πŸš€ Process Video", elem_classes=["primary-btn"])
308
+ with gr.Column(scale=1):
309
+ video_result_html = gr.HTML(label="Translated Text")
310
+ video_audio = gr.Audio(label="πŸ“’ Read Aloud", autoplay=False)
311
+ video_result_raw = gr.Textbox(visible=False)
312
+
313
+ video_translate_btn.click(
314
+ translate_video,
315
+ inputs=[video_input, source_lang, target_lang],
316
+ outputs=[video_result_raw, video_result_html, video_audio]
317
+ )
318
+
319
+ # Footer
320
+ gr.HTML("""
321
+ <div style="text-align: center; padding: 30px; margin-top: 40px; color: #64748b; font-size: 0.9rem;">
322
+ <p>πŸ”’ <strong>Privacy First</strong>: All translations run on-device via ZeroGPU. No data is stored.</p>
323
+ <p style="margin-top: 8px;">Powered by SIMBOTI β€’ Built with TranslateGemma 4B</p>
324
+ </div>
325
+ """)
326
 
327
+ # Launch
328
  if __name__ == "__main__":
329
  app.launch()