Spaces:
Sleeping
Sleeping
last commit
Browse files
app.py
CHANGED
|
@@ -65,16 +65,25 @@ 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 |
|
| 70 |
def stop_recording(audio):
|
| 71 |
"""Function yang dipanggil ketika recording selesai"""
|
| 72 |
if audio is not None:
|
| 73 |
print("β
Recording completed!")
|
| 74 |
-
return
|
|
|
|
|
|
|
|
|
|
| 75 |
else:
|
| 76 |
print("β No audio recorded")
|
| 77 |
-
return
|
|
|
|
|
|
|
|
|
|
| 78 |
|
| 79 |
def test_microphone():
|
| 80 |
"""Function untuk test microphone"""
|
|
@@ -83,7 +92,10 @@ def test_microphone():
|
|
| 83 |
|
| 84 |
def reset_recording_status():
|
| 85 |
"""Function untuk reset status recording"""
|
| 86 |
-
return
|
|
|
|
|
|
|
|
|
|
| 87 |
|
| 88 |
def handle_audio(audio_file):
|
| 89 |
"""Handle audio processing - returns (validation_message, transcript, soap, tags)"""
|
|
@@ -149,7 +161,7 @@ def toggle_inputs_with_refresh(choice):
|
|
| 149 |
gr.update(visible=(choice == "Realtime Recording")), # validasi realtime
|
| 150 |
gr.update(visible=(choice == "Input Teks")), # validasi teks
|
| 151 |
gr.update(visible=(choice == "Realtime Recording")), # recording status group
|
| 152 |
-
gr.update(visible=(choice == "Realtime Recording")), # record audio group
|
| 153 |
gr.update(value=""), # transcript
|
| 154 |
gr.update(value=""), # soap
|
| 155 |
gr.update(value=""), # tags
|
|
@@ -167,6 +179,7 @@ def clear_all_data():
|
|
| 167 |
gr.update(value=""), # transcript_output
|
| 168 |
gr.update(value=""), # soap_output
|
| 169 |
gr.update(value=""), # tags_output
|
|
|
|
| 170 |
)
|
| 171 |
|
| 172 |
def process_data(choice, audio_upload, audio_record, text_input):
|
|
@@ -215,7 +228,7 @@ def process_data(choice, audio_upload, audio_record, text_input):
|
|
| 215 |
# Default case - clear all
|
| 216 |
return ("", "", "", "", "", "")
|
| 217 |
|
| 218 |
-
# Custom CSS untuk tampilan modern dengan alignment yang diperbaiki
|
| 219 |
modern_css = """
|
| 220 |
<style>
|
| 221 |
/* Background gradient yang modern */
|
|
@@ -266,7 +279,7 @@ modern_css = """
|
|
| 266 |
border: 1px solid rgba(255,255,255,0.2);
|
| 267 |
}
|
| 268 |
|
| 269 |
-
/* Record audio section with padding */
|
| 270 |
.record-audio-section {
|
| 271 |
background: rgba(255, 255, 255, 0.95);
|
| 272 |
border-radius: 20px;
|
|
@@ -275,6 +288,21 @@ modern_css = """
|
|
| 275 |
box-shadow: 0 8px 32px rgba(0,0,0,0.1);
|
| 276 |
backdrop-filter: blur(10px);
|
| 277 |
border: 1px solid rgba(255,255,255,0.2);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 278 |
}
|
| 279 |
|
| 280 |
/* Output header styling - aligned properly */
|
|
@@ -479,6 +507,39 @@ modern_css = """
|
|
| 479 |
.recording-active {
|
| 480 |
animation: pulse 1s infinite;
|
| 481 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 482 |
</style>
|
| 483 |
"""
|
| 484 |
|
|
@@ -498,7 +559,7 @@ with gr.Blocks(
|
|
| 498 |
gr.HTML("""
|
| 499 |
<div class="main-header">
|
| 500 |
<h1>ποΈ Realtime Recording</h1>
|
| 501 |
-
<p>High Quality Audio Recording</p>
|
| 502 |
</div>
|
| 503 |
""")
|
| 504 |
|
|
@@ -533,8 +594,9 @@ with gr.Blocks(
|
|
| 533 |
elem_classes=["audio-input"]
|
| 534 |
)
|
| 535 |
|
| 536 |
-
# Input Section - Record Audio with proper padding
|
| 537 |
-
|
|
|
|
| 538 |
gr.HTML("<h3>π΅ Record Your Audio</h3>")
|
| 539 |
|
| 540 |
audio_record = gr.Audio(
|
|
@@ -640,7 +702,7 @@ with gr.Blocks(
|
|
| 640 |
input_choice.change(
|
| 641 |
fn=lambda choice: (
|
| 642 |
gr.update(visible=(choice == "Upload Audio")), # upload_audio_group
|
| 643 |
-
gr.update(visible=(choice == "Realtime Recording")), # record_audio_group
|
| 644 |
gr.update(visible=(choice == "Input Teks")), # text_input_group
|
| 645 |
gr.update(visible=(choice == "Upload Audio")), # validation_upload
|
| 646 |
gr.update(visible=(choice == "Realtime Recording")), # validation_realtime
|
|
@@ -665,16 +727,16 @@ with gr.Blocks(
|
|
| 665 |
],
|
| 666 |
)
|
| 667 |
|
| 668 |
-
# Event handlers untuk recording
|
| 669 |
audio_record.start_recording(
|
| 670 |
fn=start_recording,
|
| 671 |
-
outputs=recording_status
|
| 672 |
)
|
| 673 |
|
| 674 |
audio_record.stop_recording(
|
| 675 |
fn=stop_recording,
|
| 676 |
inputs=audio_record,
|
| 677 |
-
outputs=recording_status
|
| 678 |
)
|
| 679 |
|
| 680 |
clear_button.click(
|
|
@@ -690,6 +752,7 @@ with gr.Blocks(
|
|
| 690 |
transcript_output,
|
| 691 |
soap_output,
|
| 692 |
tags_output,
|
|
|
|
| 693 |
],
|
| 694 |
)
|
| 695 |
|
|
@@ -709,7 +772,7 @@ with gr.Blocks(
|
|
| 709 |
|
| 710 |
# Startup information
|
| 711 |
if __name__ == "__main__":
|
| 712 |
-
print("π Starting Enhanced SOAP AI Application
|
| 713 |
print("π Setup Instructions:")
|
| 714 |
print("1. Install dependencies: pip install gradio pydub nltk requests python-dotenv")
|
| 715 |
print("2. Make sure wordlist.lst file is available")
|
|
@@ -718,7 +781,7 @@ if __name__ == "__main__":
|
|
| 718 |
|
| 719 |
print("\nπ Application will start at: http://localhost:7860")
|
| 720 |
print("ποΈ Make sure to allow microphone access when using Realtime Recording!")
|
| 721 |
-
print("
|
| 722 |
print()
|
| 723 |
|
| 724 |
app.launch()
|
|
|
|
| 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 |
|
| 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)"""
|
|
|
|
| 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
|
|
|
|
| 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 |
# 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 */
|
|
|
|
| 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;
|
|
|
|
| 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 */
|
|
|
|
| 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 |
|
|
|
|
| 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 |
|
|
|
|
| 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(
|
|
|
|
| 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
|
|
|
|
| 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(
|
|
|
|
| 752 |
transcript_output,
|
| 753 |
soap_output,
|
| 754 |
tags_output,
|
| 755 |
+
record_audio_group, # Reset border when clearing
|
| 756 |
],
|
| 757 |
)
|
| 758 |
|
|
|
|
| 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 |
|
| 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()
|