šļø Realtime Recording
High Quality Audio Recording with Smart Visual Feedback
import gradio as gr import threading import os import requests import string import time from pydub import AudioSegment from nltk.tokenize import word_tokenize import nltk from nltk.corpus import words, stopwords from dotenv import load_dotenv # Download resource NLTK (hanya sekali) nltk.download('punkt') nltk.download('words') nltk.download('stopwords') load_dotenv() API_TRANSCRIBE = os.getenv("API_TRANSCRIBE") API_TEXT = os.getenv("API_TEXT") english_words = set(words.words()) indonesian_stopwords = set(stopwords.words('indonesian')) def load_indonesian_wordlist(filepath='wordlist.lst'): try: with open(filepath, encoding='utf-8') as f: return set(line.strip().lower() for line in f if line.strip()) except UnicodeDecodeError: try: with open(filepath, encoding='latin-1') as f: return set(line.strip().lower() for line in f if line.strip()) except Exception: return set() except Exception: return set() indonesian_words = load_indonesian_wordlist() valid_words = english_words.union(indonesian_words) def contains_medical_terms_auto_threshold(text, medical_words): tokens = word_tokenize(text.lower()) tokens = [w.strip(string.punctuation) for w in tokens if w.isalpha()] if not tokens: return False medical_count = sum(1 for w in tokens if w in medical_words) ratio = medical_count / len(tokens) threshold = 0.4 if len(tokens) <= 5 else 0.1 return ratio >= threshold medical_words = load_indonesian_wordlist('wordlist.lst') MAX_DURATION_SECONDS = 600 def validate_audio_duration(audio_file): try: audio = AudioSegment.from_file(audio_file) duration_sec = len(audio) / 1000.0 if duration_sec > MAX_DURATION_SECONDS: return False, duration_sec return True, duration_sec except Exception as e: return False, -1 def start_recording(): """Function yang dipanggil ketika tombol record ditekan""" print("šļø Recording started...") return ( "šļø Sedang merekam... Klik stop untuk menyelesaikan", gr.update(elem_classes=["record-audio-section", "recording-active"]) # Add red border ) def stop_recording(audio): """Function yang dipanggil ketika recording selesai""" if audio is not None: print("ā Recording completed!") return ( "ā Recording selesai! Audio siap diproses", gr.update(elem_classes=["record-audio-section", "recording-completed"]) # Add blue border ) else: print("ā No audio recorded") return ( "ā Tidak ada audio yang direkam", gr.update(elem_classes=["record-audio-section"]) # Reset to default ) def test_microphone(): """Function untuk test microphone""" print("š§ Testing microphone...") return "š§ Testing microphone... Silakan coba record lagi" def reset_recording_status(): """Function untuk reset status recording""" return ( "š± Siap untuk merekam - Klik tombol record", gr.update(elem_classes=["record-audio-section"]) # Reset to default ) def handle_audio(audio_file): """Handle audio processing - returns (validation_message, transcript, soap, tags)""" if audio_file is None: return "ā Tidak ada file audio", "", "", "" valid, duration = validate_audio_duration(audio_file) if not valid: if duration == -1: msg = "ā ļø Gagal memproses file audio." else: msg = f"ā ļø Durasi rekaman terlalu panjang ({duration:.1f}s). Maksimal {MAX_DURATION_SECONDS}s." return msg, "", "", "" try: with open(audio_file, "rb") as f: files = {"audio": f} response = requests.post(API_TRANSCRIBE, files=files) result = response.json() transcription = result.get("transcription", "") soap_content = result.get("soap_content", "") tags_content = result.get("tags_content", "") if not transcription and not soap_content and not tags_content: return "ā ļø Tidak ada hasil dari proses audio", "", "", "" return "", transcription, soap_content, tags_content except Exception as e: return f"ā Error processing audio: {str(e)}", "", "", "" def handle_text(dialogue): """Handle text processing - returns (validation_message, transcript, soap, tags)""" if not dialogue.strip(): return "ā ļø Teks tidak boleh kosong", "", "", "" if not contains_medical_terms_auto_threshold(dialogue, medical_words): return "ā ļø Teks tidak mengandung istilah medis yang cukup untuk diproses.", "", "", "" try: response = requests.post(API_TEXT, json={"dialogue": dialogue}) result = response.json() soap_content = result.get("soap_content", "") tags_content = result.get("tags_content", "") if not soap_content and not tags_content: return "ā ļø Tidak ada hasil dari proses teks", "", "", "" return "", dialogue, soap_content, tags_content except Exception as e: return f"ā Error processing text: {str(e)}", "", "", "" def toggle_inputs_with_refresh(choice): # Tampilkan input dan validasi yang sesuai, sembunyikan lainnya return ( gr.update(visible=(choice == "Upload Audio"), value=None), # audio upload gr.update(visible=(choice == "Realtime Recording"), value=None), # audio record gr.update(visible=(choice == "Input Teks"), value=""), # text input gr.update(visible=(choice == "Upload Audio")), # validasi upload gr.update(visible=(choice == "Realtime Recording")), # validasi realtime gr.update(visible=(choice == "Input Teks")), # validasi teks gr.update(visible=(choice == "Realtime Recording")), # recording status group gr.update(visible=(choice == "Realtime Recording"), elem_classes=["record-audio-section"]), # record audio group with reset border gr.update(value=""), # transcript gr.update(value=""), # soap gr.update(value=""), # tags ) def clear_all_data(): return ( gr.update(value=None), # audio_upload gr.update(value=None), # audio_record gr.update(value=""), # text_input gr.update(value=""), # validation_upload gr.update(value=""), # validation_realtime gr.update(value=""), # validation_text gr.update(value="š± Siap untuk merekam"), # recording_status gr.update(value=""), # transcript_output gr.update(value=""), # soap_output gr.update(value=""), # tags_output gr.update(elem_classes=["record-audio-section"]), # reset record audio group border ) def process_data(choice, audio_upload, audio_record, text_input): """ Process data based on choice and return results in correct order: Returns: (validation_upload, validation_realtime, validation_text, transcript, soap, tags) """ if choice == "Upload Audio": # Process upload audio validation_msg, transcript, soap, tags = handle_audio(audio_upload) return ( validation_msg, # validation_upload "", # validation_realtime (empty) "", # validation_text (empty) transcript, # transcript_output soap, # soap_output tags # tags_output ) elif choice == "Realtime Recording": # Process realtime recording validation_msg, transcript, soap, tags = handle_audio(audio_record) return ( "", # validation_upload (empty) validation_msg, # validation_realtime "", # validation_text (empty) transcript, # transcript_output soap, # soap_output tags # tags_output ) elif choice == "Input Teks": # Process text input validation_msg, transcript, soap, tags = handle_text(text_input) return ( "", # validation_upload (empty) "", # validation_realtime (empty) validation_msg, # validation_text transcript, # transcript_output (will be same as input for text) soap, # soap_output tags # tags_output ) else: # Default case - clear all return ("", "", "", "", "", "") # Custom CSS untuk tampilan modern dengan alignment yang diperbaiki dan border dinamis modern_css = """ """ # Buat interface dengan theme modern with gr.Blocks( title="𩺠SOAP AI - Modern Interface", css=modern_css, theme=gr.themes.Soft( primary_hue="blue", secondary_hue="cyan", neutral_hue="slate", font=gr.themes.GoogleFont("Inter") ) ) as app: # Header gr.HTML("""
High Quality Audio Recording with Smart Visual Feedback
Use via API š„ ⢠Built with Gradio š