syafiqq02 commited on
Commit
618375e
Β·
1 Parent(s): 01ce616

gradio commit

Browse files
Files changed (1) hide show
  1. app.py +68 -466
app.py CHANGED
@@ -65,25 +65,16 @@ def validate_audio_duration(audio_file):
65
  def start_recording():
66
  """Function yang dipanggil ketika tombol record ditekan"""
67
  print("πŸŽ™οΈ Recording started...")
68
- return (
69
- "πŸŽ™οΈ Sedang merekam... Klik stop untuk menyelesaikan",
70
- gr.update(elem_classes=["record-audio-section", "recording-active"]) # Add red border
71
- )
72
 
73
  def stop_recording(audio):
74
  """Function yang dipanggil ketika recording selesai"""
75
  if audio is not None:
76
  print("βœ… Recording completed!")
77
- return (
78
- "βœ… Recording selesai! Audio siap diproses",
79
- gr.update(elem_classes=["record-audio-section", "recording-completed"]) # Add blue border
80
- )
81
  else:
82
  print("❌ No audio recorded")
83
- return (
84
- "❌ Tidak ada audio yang direkam",
85
- gr.update(elem_classes=["record-audio-section"]) # Reset to default
86
- )
87
 
88
  def test_microphone():
89
  """Function untuk test microphone"""
@@ -92,10 +83,7 @@ def test_microphone():
92
 
93
  def reset_recording_status():
94
  """Function untuk reset status recording"""
95
- return (
96
- "πŸ“± Siap untuk merekam - Klik tombol record",
97
- gr.update(elem_classes=["record-audio-section"]) # Reset to default
98
- )
99
 
100
  def handle_audio(audio_file):
101
  """Handle audio processing - returns (validation_message, transcript, soap, tags)"""
@@ -160,8 +148,6 @@ def toggle_inputs_with_refresh(choice):
160
  gr.update(visible=(choice == "Upload Audio")), # validasi upload
161
  gr.update(visible=(choice == "Realtime Recording")), # validasi realtime
162
  gr.update(visible=(choice == "Input Teks")), # validasi teks
163
- gr.update(visible=(choice == "Realtime Recording")), # recording status group
164
- gr.update(visible=(choice == "Realtime Recording"), elem_classes=["record-audio-section"]), # record audio group with reset border
165
  gr.update(value=""), # transcript
166
  gr.update(value=""), # soap
167
  gr.update(value=""), # tags
@@ -175,11 +161,10 @@ def clear_all_data():
175
  gr.update(value=""), # validation_upload
176
  gr.update(value=""), # validation_realtime
177
  gr.update(value=""), # validation_text
178
- gr.update(value="πŸ“± Siap untuk merekam"), # recording_status
179
  gr.update(value=""), # transcript_output
180
  gr.update(value=""), # soap_output
181
  gr.update(value=""), # tags_output
182
- gr.update(elem_classes=["record-audio-section"]), # reset record audio group border
183
  )
184
 
185
  def process_data(choice, audio_upload, audio_record, text_input):
@@ -228,409 +213,54 @@ def process_data(choice, audio_upload, audio_record, text_input):
228
  # Default case - clear all
229
  return ("", "", "", "", "", "")
230
 
231
- # Custom CSS untuk tampilan modern dengan alignment yang diperbaiki dan border dinamis
232
- modern_css = """
233
- <style>
234
- /* Background gradient yang modern */
235
- .gradio-container {
236
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
237
- min-height: 100vh;
238
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
239
- }
240
-
241
- /* Header styling */
242
- .main-header {
243
- text-align: center;
244
- padding: 2rem 0;
245
- color: white;
246
- margin-bottom: 2rem;
247
- }
248
-
249
- .main-header h1 {
250
- font-size: 3rem;
251
- font-weight: 700;
252
- margin-bottom: 0.5rem;
253
- text-shadow: 0 2px 4px rgba(0,0,0,0.3);
254
- }
255
-
256
- .main-header p {
257
- font-size: 1.2rem;
258
- opacity: 0.9;
259
- font-weight: 300;
260
- }
261
-
262
- /* Card styling */
263
- .input-card {
264
- background: rgba(255, 255, 255, 0.95);
265
- border-radius: 20px;
266
- padding: 2rem;
267
- margin: 0.8rem 0;
268
- box-shadow: 0 8px 32px rgba(0,0,0,0.1);
269
- backdrop-filter: blur(10px);
270
- border: 1px solid rgba(255,255,255,0.2);
271
- }
272
-
273
- .output-card {
274
- background: rgba(255, 255, 255, 0.95);
275
- border-radius: 20px;
276
- padding: 2rem;
277
- box-shadow: 0 8px 32px rgba(0,0,0,0.1);
278
- backdrop-filter: blur(10px);
279
- border: 1px solid rgba(255,255,255,0.2);
280
- }
281
-
282
- /* Record audio section with padding - default state */
283
- .record-audio-section {
284
- background: rgba(255, 255, 255, 0.95);
285
- border-radius: 20px;
286
- padding: 2rem;
287
- margin: 0.8rem 0;
288
- box-shadow: 0 8px 32px rgba(0,0,0,0.1);
289
- backdrop-filter: blur(10px);
290
- border: 1px solid rgba(255,255,255,0.2);
291
- transition: all 0.3s ease;
292
- }
293
-
294
- /* Recording active state - RED border */
295
- .record-audio-section.recording-active {
296
- border: 3px solid #ff4757 !important;
297
- box-shadow: 0 8px 32px rgba(255, 71, 87, 0.3), 0 0 20px rgba(255, 71, 87, 0.2) !important;
298
- background: rgba(255, 245, 245, 0.98) !important;
299
- }
300
-
301
- /* Recording completed state - BLUE border */
302
- .record-audio-section.recording-completed {
303
- border: 3px solid #3742fa !important;
304
- box-shadow: 0 8px 32px rgba(55, 66, 250, 0.3), 0 0 20px rgba(55, 66, 250, 0.2) !important;
305
- background: rgba(245, 245, 255, 0.98) !important;
306
- }
307
-
308
- /* Output header styling - aligned properly */
309
- .output-header {
310
- text-align: left;
311
- margin-bottom: 1.5rem;
312
- padding-left: 0;
313
- }
314
-
315
- .output-header h3 {
316
- font-size: 1.5rem;
317
- font-weight: 600;
318
- color: #2d3436;
319
- margin: 0;
320
- display: flex;
321
- align-items: center;
322
- }
323
-
324
- /* Spacing adjustments */
325
- .input-section {
326
- margin-bottom: 1rem;
327
- }
328
-
329
- .button-section {
330
- margin-top: 0.5rem;
331
- margin-bottom: 1rem;
332
- }
333
-
334
- /* Updated output section styling with proper alignment */
335
- .output-section {
336
- background: rgba(255, 255, 255, 0.98);
337
- border-radius: 15px;
338
- padding: 1.5rem;
339
- margin: 1rem 0 0 0;
340
- box-shadow: 0 4px 20px rgba(0,0,0,0.08);
341
- }
342
-
343
- /* Ensure all output components are aligned consistently */
344
- .output-container {
345
- display: flex;
346
- flex-direction: column;
347
- gap: 1rem;
348
- }
349
-
350
- /* Button styling */
351
- .record-btn {
352
- background: linear-gradient(45deg, #ff6b6b, #ee5a24);
353
- border: none;
354
- border-radius: 50px;
355
- padding: 1rem 2rem;
356
- color: white;
357
- font-weight: 600;
358
- font-size: 1.1rem;
359
- cursor: pointer;
360
- transition: all 0.3s ease;
361
- box-shadow: 0 4px 15px rgba(238, 90, 36, 0.4);
362
- }
363
-
364
- .record-btn:hover {
365
- transform: translateY(-2px);
366
- box-shadow: 0 6px 20px rgba(238, 90, 36, 0.6);
367
- }
368
-
369
- .test-btn {
370
- background: linear-gradient(45deg, #74b9ff, #0984e3);
371
- border: none;
372
- border-radius: 50px;
373
- padding: 0.8rem 1.5rem;
374
- color: white;
375
- font-weight: 500;
376
- cursor: pointer;
377
- transition: all 0.3s ease;
378
- }
379
-
380
- .test-btn:hover {
381
- transform: translateY(-1px);
382
- box-shadow: 0 4px 15px rgba(116, 185, 255, 0.4);
383
- }
384
-
385
- .reset-btn {
386
- background: linear-gradient(45deg, #a29bfe, #6c5ce7);
387
- border: none;
388
- border-radius: 15px;
389
- padding: 0.4rem 1rem;
390
- font-size: 0.8rem;
391
- color: white;
392
- font-weight: 500;
393
- cursor: pointer;
394
- transition: all 0.3s ease;
395
- height: 2rem;
396
- min-width: 80px;
397
- }
398
-
399
- .reset-btn:hover {
400
- transform: translateY(-1px);
401
- box-shadow: 0 2px 10px rgba(162, 155, 254, 0.4);
402
- }
403
-
404
- .process-btn {
405
- background: linear-gradient(45deg, #00b894, #00cec9);
406
- border: none;
407
- border-radius: 50px;
408
- padding: 1rem 2.5rem;
409
- color: white;
410
- font-weight: 600;
411
- font-size: 1.2rem;
412
- cursor: pointer;
413
- transition: all 0.3s ease;
414
- box-shadow: 0 4px 15px rgba(0, 184, 148, 0.4);
415
- margin: 1rem 0;
416
- }
417
-
418
- .process-btn:hover {
419
- transform: translateY(-2px);
420
- box-shadow: 0 6px 20px rgba(0, 184, 148, 0.6);
421
- }
422
-
423
- /* Status indicator */
424
- .status-indicator {
425
- background: rgba(255, 255, 255, 0.95);
426
- border: 2px solid #74b9ff;
427
- color: #2d3436;
428
- padding: 2rem;
429
- border-radius: 15px;
430
- font-weight: 500;
431
- margin: 1rem 0;
432
- box-shadow: 0 4px 15px rgba(116, 185, 255, 0.2);
433
- }
434
-
435
- /* Input styling */
436
- .audio-input {
437
- border: 2px dashed #ddd;
438
- border-radius: 15px;
439
- padding: 2rem;
440
- text-align: center;
441
- background: rgba(255,255,255,0.5);
442
- transition: all 0.3s ease;
443
- }
444
-
445
- .audio-input:hover {
446
- border-color: #74b9ff;
447
- background: rgba(116, 185, 255, 0.1);
448
- }
449
-
450
- /* Ensure proper text alignment in outputs */
451
- .output-section textarea {
452
- text-align: left;
453
- vertical-align: top;
454
- resize: vertical;
455
- }
456
-
457
- /* Responsive design */
458
- @media (max-width: 768px) {
459
- .main-header h1 {
460
- font-size: 2rem;
461
- }
462
-
463
- .input-card, .output-card, .record-audio-section {
464
- padding: 2rem;
465
- }
466
-
467
- .record-btn, .process-btn {
468
- width: 100%;
469
- margin: 0.5rem 0;
470
- }
471
-
472
- .reset-btn {
473
- min-width: 70px;
474
- font-size: 0.75rem;
475
- }
476
- }
477
-
478
- /* Animation untuk elemen yang muncul */
479
- @keyframes fadeInUp {
480
- from {
481
- opacity: 0;
482
- transform: translateY(30px);
483
- }
484
- to {
485
- opacity: 1;
486
- transform: translateY(0);
487
- }
488
- }
489
-
490
- .input-card, .output-card, .record-audio-section {
491
- animation: fadeInUp 0.6s ease-out;
492
- }
493
-
494
- /* Microphone icon animation */
495
- @keyframes pulse {
496
- 0% {
497
- transform: scale(1);
498
- }
499
- 50% {
500
- transform: scale(1.05);
501
- }
502
- 100% {
503
- transform: scale(1);
504
- }
505
- }
506
-
507
- .recording-active {
508
- animation: pulse 1s infinite;
509
- }
510
-
511
- /* Border glow animation for recording states */
512
- @keyframes redGlow {
513
- 0% {
514
- box-shadow: 0 8px 32px rgba(255, 71, 87, 0.3), 0 0 20px rgba(255, 71, 87, 0.2);
515
- }
516
- 50% {
517
- box-shadow: 0 8px 32px rgba(255, 71, 87, 0.5), 0 0 30px rgba(255, 71, 87, 0.4);
518
- }
519
- 100% {
520
- box-shadow: 0 8px 32px rgba(255, 71, 87, 0.3), 0 0 20px rgba(255, 71, 87, 0.2);
521
- }
522
- }
523
-
524
- @keyframes blueGlow {
525
- 0% {
526
- box-shadow: 0 8px 32px rgba(55, 66, 250, 0.3), 0 0 20px rgba(55, 66, 250, 0.2);
527
- }
528
- 50% {
529
- box-shadow: 0 8px 32px rgba(55, 66, 250, 0.5), 0 0 30px rgba(55, 66, 250, 0.4);
530
- }
531
- 100% {
532
- box-shadow: 0 8px 32px rgba(55, 66, 250, 0.3), 0 0 20px rgba(55, 66, 250, 0.2);
533
- }
534
- }
535
-
536
- .record-audio-section.recording-active {
537
- animation: redGlow 2s infinite ease-in-out;
538
- }
539
-
540
- .record-audio-section.recording-completed {
541
- animation: blueGlow 2s infinite ease-in-out;
542
- }
543
- </style>
544
- """
545
-
546
- # Buat interface dengan theme modern
547
- with gr.Blocks(
548
- title="🩺 SOAP AI - Modern Interface",
549
- css=modern_css,
550
- theme=gr.themes.Soft(
551
- primary_hue="blue",
552
- secondary_hue="cyan",
553
- neutral_hue="slate",
554
- font=gr.themes.GoogleFont("Inter")
555
- )
556
- ) as app:
557
 
558
  # Header
559
- gr.HTML("""
560
- <div class="main-header">
561
- <h1>πŸŽ™οΈ Realtime Recording</h1>
562
- <p>High Quality Audio Recording with Smart Visual Feedback</p>
563
- </div>
564
- """)
565
 
566
  with gr.Row():
567
  with gr.Column(scale=8):
568
  input_choice = gr.Dropdown(
569
  choices=["Upload Audio", "Realtime Recording", "Input Teks"],
570
  value="Realtime Recording",
571
- label="🎯 Pilih Metode Input",
572
- container=True,
573
- elem_classes=["input-dropdown"]
574
  )
575
  with gr.Column(scale=2):
576
- clear_button = gr.Button(
577
- "πŸ—‘οΈ Clear",
578
- variant="secondary",
579
- size="sm",
580
- elem_classes=["reset-btn"]
581
- )
582
 
583
  # Input Section - Upload Audio
584
- with gr.Group(elem_classes=["input-card"], visible=False) as upload_audio_group:
585
- gr.HTML("<h3>πŸ“ Upload Audio File</h3>")
586
-
587
  audio_upload = gr.Audio(
588
  sources=["upload"],
589
  label="πŸ“ Upload File Audio",
590
- type="filepath",
591
- show_download_button=False,
592
- show_share_button=False,
593
- interactive=True,
594
- elem_classes=["audio-input"]
595
  )
596
 
597
- # Input Section - Record Audio with proper padding and dynamic border
598
- record_audio_group = gr.Group(elem_classes=["record-audio-section"], visible=True)
599
- with record_audio_group:
600
- gr.HTML("<h3>🎡 Record Your Audio</h3>")
601
-
 
 
 
 
602
  audio_record = gr.Audio(
603
  sources=["microphone"],
604
  label="πŸŽ™οΈ Realtime Recording",
605
- type="filepath",
606
- show_download_button=True,
607
- show_share_button=False,
608
- interactive=True,
609
- streaming=False,
610
- elem_classes=["audio-input"]
611
  )
612
 
613
- # Input Section - Text Input (without record audio section)
614
- with gr.Group(elem_classes=["input-card"], visible=False) as text_input_group:
615
- gr.HTML("<h3>πŸ“ Input Teks</h3>")
616
-
617
  text_input = gr.Textbox(
618
  label="πŸ“ Masukkan Percakapan Dokter-Pasien",
619
  lines=6,
620
- placeholder="Ketik percakapan antara dokter dan pasien di sini...",
621
- elem_classes=["text-input"]
622
- )
623
-
624
- # Status Section - hanya untuk Realtime Recording
625
- recording_status_group = gr.Group(elem_classes=["status-indicator"], visible=True)
626
- with recording_status_group:
627
- gr.HTML("<h4>πŸ“Š Status Recording</h4>")
628
- recording_status = gr.Textbox(
629
- value="Siap untuk merekam",
630
- interactive=False,
631
- show_label=False,
632
- lines=1,
633
- elem_classes=["status-display"]
634
  )
635
 
636
  # Validation Section
@@ -638,79 +268,54 @@ with gr.Blocks(
638
  label="⚠️ Validasi Upload Audio",
639
  lines=1,
640
  interactive=False,
641
- visible=False,
642
- elem_classes=["validation-msg"]
643
  )
644
  validation_realtime = gr.Textbox(
645
  label="⚠️ Validasi Realtime Recording",
646
  lines=1,
647
  interactive=False,
648
- visible=True,
649
- elem_classes=["validation-msg"]
650
  )
651
  validation_text = gr.Textbox(
652
  label="⚠️ Validasi Input Teks",
653
  lines=1,
654
  interactive=False,
655
- visible=False,
656
- elem_classes=["validation-msg"]
657
  )
658
 
659
  # Process Button
660
- process_button = gr.Button(
661
- "πŸš€ Proses ke SOAP",
662
- variant="primary",
663
- size="lg",
664
- elem_classes=["process-btn"]
665
- )
666
 
667
- # Output Section with proper alignment - Fixed Layout
668
- with gr.Group(elem_classes=["output-card"]):
669
- # Header aligned properly
670
- with gr.Row():
671
- with gr.Column():
672
- gr.HTML('<div class="output-header"><h3>πŸ“‹ Hasil Analisis</h3></div>')
673
-
674
- # All outputs in aligned container
675
- with gr.Column(elem_classes=["output-container"]):
676
- transcript_output = gr.Textbox(
677
- label="πŸ“ Hasil Transkripsi",
678
- lines=4,
679
- elem_classes=["output-section"]
680
- )
681
-
682
- soap_output = gr.Textbox(
683
- label="πŸ“‹ Ringkasan SOAP",
684
- lines=8,
685
- elem_classes=["output-section"]
686
- )
687
-
688
- tags_output = gr.Textbox(
689
- label="🏷️ Medical Tags",
690
- lines=6,
691
- elem_classes=["output-section"]
692
- )
693
-
694
- # Footer
695
- gr.HTML("""
696
- <div style="text-align: center; padding: 2rem; color: rgba(255,255,255,0.7);">
697
- <p>Use via API πŸ”₯ β€’ Built with Gradio πŸš€</p>
698
- </div>
699
- """)
700
 
701
  # Event handlers untuk toggle inputs
702
  input_choice.change(
703
  fn=lambda choice: (
704
- gr.update(visible=(choice == "Upload Audio")), # upload_audio_group
705
- gr.update(visible=(choice == "Realtime Recording"), elem_classes=["record-audio-section"]), # record_audio_group with reset border
706
- gr.update(visible=(choice == "Input Teks")), # text_input_group
707
- gr.update(visible=(choice == "Upload Audio")), # validation_upload
708
- gr.update(visible=(choice == "Realtime Recording")), # validation_realtime
709
- gr.update(visible=(choice == "Input Teks")), # validation_text
710
- gr.update(visible=(choice == "Realtime Recording")), # recording_status_group
711
- gr.update(value=""), # transcript
712
- gr.update(value=""), # soap
713
- gr.update(value=""), # tags
714
  ),
715
  inputs=input_choice,
716
  outputs=[
@@ -720,23 +325,22 @@ with gr.Blocks(
720
  validation_upload,
721
  validation_realtime,
722
  validation_text,
723
- recording_status_group,
724
  transcript_output,
725
  soap_output,
726
- tags_output,
727
- ],
728
  )
729
 
730
- # Event handlers untuk recording dengan border dynamics
731
  audio_record.start_recording(
732
  fn=start_recording,
733
- outputs=[recording_status, record_audio_group]
734
  )
735
 
736
  audio_record.stop_recording(
737
  fn=stop_recording,
738
  inputs=audio_record,
739
- outputs=[recording_status, record_audio_group]
740
  )
741
 
742
  clear_button.click(
@@ -751,9 +355,8 @@ with gr.Blocks(
751
  recording_status,
752
  transcript_output,
753
  soap_output,
754
- tags_output,
755
- record_audio_group, # Reset border when clearing
756
- ],
757
  )
758
 
759
  process_button.click(
@@ -765,14 +368,14 @@ with gr.Blocks(
765
  validation_text,
766
  transcript_output,
767
  soap_output,
768
- tags_output,
769
  ],
770
- show_progress="minimal",
771
  )
772
 
773
  # Startup information
774
  if __name__ == "__main__":
775
- print("πŸš€ Starting Enhanced SOAP AI Application...")
776
  print("πŸ“‹ Setup Instructions:")
777
  print("1. Install dependencies: pip install gradio pydub nltk requests python-dotenv")
778
  print("2. Make sure wordlist.lst file is available")
@@ -781,7 +384,6 @@ if __name__ == "__main__":
781
 
782
  print("\n🌐 Application will start at: http://localhost:7860")
783
  print("πŸŽ™οΈ Make sure to allow microphone access when using Realtime Recording!")
784
- print("πŸ“Š Visual feedback provided through dynamic border colors during recording")
785
  print()
786
 
787
  app.launch()
 
65
  def start_recording():
66
  """Function yang dipanggil ketika tombol record ditekan"""
67
  print("πŸŽ™οΈ Recording started...")
68
+ return "πŸ”΄ Recording..."
 
 
 
69
 
70
  def stop_recording(audio):
71
  """Function yang dipanggil ketika recording selesai"""
72
  if audio is not None:
73
  print("βœ… Recording completed!")
74
+ return "βœ… Ready to process"
 
 
 
75
  else:
76
  print("❌ No audio recorded")
77
+ return "βšͺ Ready to record"
 
 
 
78
 
79
  def test_microphone():
80
  """Function untuk test microphone"""
 
83
 
84
  def reset_recording_status():
85
  """Function untuk reset status recording"""
86
+ return "βšͺ Ready to record"
 
 
 
87
 
88
  def handle_audio(audio_file):
89
  """Handle audio processing - returns (validation_message, transcript, soap, tags)"""
 
148
  gr.update(visible=(choice == "Upload Audio")), # validasi upload
149
  gr.update(visible=(choice == "Realtime Recording")), # validasi realtime
150
  gr.update(visible=(choice == "Input Teks")), # validasi teks
 
 
151
  gr.update(value=""), # transcript
152
  gr.update(value=""), # soap
153
  gr.update(value=""), # tags
 
161
  gr.update(value=""), # validation_upload
162
  gr.update(value=""), # validation_realtime
163
  gr.update(value=""), # validation_text
164
+ gr.update(value="βšͺ Ready to record"), # recording_status
165
  gr.update(value=""), # transcript_output
166
  gr.update(value=""), # soap_output
167
  gr.update(value=""), # tags_output
 
168
  )
169
 
170
  def process_data(choice, audio_upload, audio_record, text_input):
 
213
  # Default case - clear all
214
  return ("", "", "", "", "", "")
215
 
216
+ # Buat interface dengan tampilan default Gradio
217
+ with gr.Blocks(title="🩺 SOAP AI") as app:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
 
219
  # Header
220
+ gr.Markdown("# πŸŽ™οΈ SOAP AI - Medical Transcription & Analysis")
221
+ gr.Markdown("Aplikasi untuk mengkonversi percakapan dokter-pasien menjadi format SOAP")
 
 
 
 
222
 
223
  with gr.Row():
224
  with gr.Column(scale=8):
225
  input_choice = gr.Dropdown(
226
  choices=["Upload Audio", "Realtime Recording", "Input Teks"],
227
  value="Realtime Recording",
228
+ label="🎯 Pilih Metode Input"
 
 
229
  )
230
  with gr.Column(scale=2):
231
+ clear_button = gr.Button("πŸ—‘οΈ Clear", variant="secondary")
 
 
 
 
 
232
 
233
  # Input Section - Upload Audio
234
+ with gr.Group(visible=False) as upload_audio_group:
235
+ gr.Markdown("### πŸ“ Upload Audio File")
 
236
  audio_upload = gr.Audio(
237
  sources=["upload"],
238
  label="πŸ“ Upload File Audio",
239
+ type="filepath"
 
 
 
 
240
  )
241
 
242
+ # Input Section - Record Audio
243
+ with gr.Group(visible=True) as record_audio_group:
244
+ gr.Markdown("### 🎡 Record Your Audio")
245
+ recording_status = gr.Textbox(
246
+ value="βšͺ Ready to record",
247
+ interactive=False,
248
+ show_label=False,
249
+ lines=1
250
+ )
251
  audio_record = gr.Audio(
252
  sources=["microphone"],
253
  label="πŸŽ™οΈ Realtime Recording",
254
+ type="filepath"
 
 
 
 
 
255
  )
256
 
257
+ # Input Section - Text Input
258
+ with gr.Group(visible=False) as text_input_group:
259
+ gr.Markdown("### πŸ“ Input Teks")
 
260
  text_input = gr.Textbox(
261
  label="πŸ“ Masukkan Percakapan Dokter-Pasien",
262
  lines=6,
263
+ placeholder="Ketik percakapan antara dokter dan pasien di sini..."
 
 
 
 
 
 
 
 
 
 
 
 
 
264
  )
265
 
266
  # Validation Section
 
268
  label="⚠️ Validasi Upload Audio",
269
  lines=1,
270
  interactive=False,
271
+ visible=False
 
272
  )
273
  validation_realtime = gr.Textbox(
274
  label="⚠️ Validasi Realtime Recording",
275
  lines=1,
276
  interactive=False,
277
+ visible=True
 
278
  )
279
  validation_text = gr.Textbox(
280
  label="⚠️ Validasi Input Teks",
281
  lines=1,
282
  interactive=False,
283
+ visible=False
 
284
  )
285
 
286
  # Process Button
287
+ process_button = gr.Button("πŸš€ Proses ke SOAP", variant="primary", size="lg")
 
 
 
 
 
288
 
289
+ # Output Section
290
+ gr.Markdown("## πŸ“‹ Hasil Analisis")
291
+
292
+ transcript_output = gr.Textbox(
293
+ label="πŸ“ Hasil Transkripsi",
294
+ lines=4
295
+ )
296
+
297
+ soap_output = gr.Textbox(
298
+ label="πŸ“‹ Ringkasan SOAP",
299
+ lines=8
300
+ )
301
+
302
+ tags_output = gr.Textbox(
303
+ label="🏷️ Medical Tags",
304
+ lines=6
305
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
306
 
307
  # Event handlers untuk toggle inputs
308
  input_choice.change(
309
  fn=lambda choice: (
310
+ gr.update(visible=(choice == "Upload Audio")),
311
+ gr.update(visible=(choice == "Realtime Recording")),
312
+ gr.update(visible=(choice == "Input Teks")),
313
+ gr.update(visible=(choice == "Upload Audio")),
314
+ gr.update(visible=(choice == "Realtime Recording")),
315
+ gr.update(visible=(choice == "Input Teks")),
316
+ gr.update(value=""),
317
+ gr.update(value=""),
318
+ gr.update(value="")
 
319
  ),
320
  inputs=input_choice,
321
  outputs=[
 
325
  validation_upload,
326
  validation_realtime,
327
  validation_text,
 
328
  transcript_output,
329
  soap_output,
330
+ tags_output
331
+ ]
332
  )
333
 
334
+ # Event handlers untuk recording
335
  audio_record.start_recording(
336
  fn=start_recording,
337
+ outputs=recording_status
338
  )
339
 
340
  audio_record.stop_recording(
341
  fn=stop_recording,
342
  inputs=audio_record,
343
+ outputs=recording_status
344
  )
345
 
346
  clear_button.click(
 
355
  recording_status,
356
  transcript_output,
357
  soap_output,
358
+ tags_output
359
+ ]
 
360
  )
361
 
362
  process_button.click(
 
368
  validation_text,
369
  transcript_output,
370
  soap_output,
371
+ tags_output
372
  ],
373
+ show_progress="minimal"
374
  )
375
 
376
  # Startup information
377
  if __name__ == "__main__":
378
+ print("πŸš€ Starting SOAP AI Application...")
379
  print("πŸ“‹ Setup Instructions:")
380
  print("1. Install dependencies: pip install gradio pydub nltk requests python-dotenv")
381
  print("2. Make sure wordlist.lst file is available")
 
384
 
385
  print("\n🌐 Application will start at: http://localhost:7860")
386
  print("πŸŽ™οΈ Make sure to allow microphone access when using Realtime Recording!")
 
387
  print()
388
 
389
  app.launch()