Spaces:
Runtime error
Runtime error
| import gradio as gr | |
| import whisper | |
| import subprocess | |
| import os | |
| import uuid | |
| import wave | |
| import contextlib | |
| from validation import validate_transcription | |
| from transformers import pipeline | |
| # Load model NLP emosi | |
| emotion_model = pipeline("text-classification", model="cardiffnlp/twitter-roberta-base-emotion", top_k=1) | |
| # Cek ffmpeg | |
| def ffmpeg_available(): | |
| try: | |
| subprocess.run(["ffmpeg", "-version"], capture_output=True) | |
| return True | |
| except FileNotFoundError: | |
| return False | |
| # Load Whisper | |
| model = whisper.load_model("base") | |
| # Analisis emosi sederhana | |
| def detect_emotion(text): | |
| emotions = { | |
| "sedih": "sedih", | |
| "lelah": "lelah", | |
| "bingung": "bingung", | |
| "tidak semangat": "putus asa", | |
| "baik-baik saja": "positif" | |
| } | |
| for keyword, label in emotions.items(): | |
| if keyword in text.lower(): | |
| return label | |
| return "netral" | |
| # Respons chatbot berdasarkan emosi | |
| def generate_response(text, emotion): | |
| responses = { | |
| "sedih": "Terima kasih sudah berbagi. Apa yang membuatmu merasa sedih?", | |
| "lelah": "Kamu merasa lelah ya... Mau cerita lebih lanjut?", | |
| "bingung": "Wajar kok merasa bingung. Aku di sini untuk mendengarkan.", | |
| "putus asa": "Aku paham. Kadang kita butuh waktu untuk memulihkan diri.", | |
| "positif": "Senang mendengarnya. Kalau ada yang ingin dibicarakan, aku siap mendengarkan.", | |
| "netral": "Terima kasih sudah berbagi. Aku di sini kalau kamu ingin cerita lebih banyak." | |
| } | |
| return responses.get(emotion, responses["netral"]) | |
| # Durasi audio | |
| def get_audio_duration(audio_path): | |
| try: | |
| with contextlib.closing(wave.open(audio_path, 'r')) as f: | |
| frames = f.getnframes() | |
| rate = f.getframerate() | |
| duration = frames / float(rate) | |
| return round(duration, 2) | |
| except Exception: | |
| return None | |
| # Fungsi utama | |
| def transcribe_audio(audio_file): | |
| ffmpeg_ok = ffmpeg_available() | |
| file_ext = os.path.splitext(audio_file)[1].lower() | |
| safe_formats = [".wav", ".flac"] | |
| if not ffmpeg_ok and file_ext not in safe_formats: | |
| return ( | |
| f"β οΈ Format {file_ext} tidak didukung tanpa ffmpeg.", | |
| None, | |
| None, | |
| None, | |
| None | |
| ) | |
| duration = get_audio_duration(audio_file) | |
| if duration is None: | |
| return "β Gagal membaca durasi audio.", None, None, None, None | |
| if duration < 1.5: | |
| return f"β οΈ Audio terlalu pendek ({duration} detik).", None, None, None, None | |
| try: | |
| result = model.transcribe(audio_file) | |
| raw_text = result["text"] | |
| language = result["language"] | |
| # Validasi transkripsi | |
| is_valid, validated_text_or_msg = validate_transcription(raw_text) | |
| if not is_valid: | |
| return ( | |
| f"β οΈ Transkripsi tidak valid: {validated_text_or_msg}", | |
| raw_text, | |
| None, | |
| validated_text_or_msg, | |
| "tidak terdeteksi" | |
| ) | |
| # Simpan ke file | |
| file_id = str(uuid.uuid4())[:8] | |
| output_path = f"/tmp/transcript_{file_id}.txt" | |
| with open(output_path, "w", encoding="utf-8") as f: | |
| f.write(validated_text_or_msg) | |
| # Analisis emosi | |
| emotion = detect_emotion(validated_text_or_msg) | |
| # Respons chatbot | |
| response = generate_response(validated_text_or_msg, emotion) | |
| return ( | |
| f"β Transkripsi selesai. Bahasa: **{language}**, Durasi: **{duration} detik**", | |
| validated_text_or_msg, | |
| output_path, | |
| response, | |
| f"π§ Emosi terdeteksi: **{emotion}**" | |
| ) | |
| except Exception as e: | |
| return f"β Gagal transkripsi: {str(e)}", None, None, None, None | |
| # UI dengan tema khas Indonesia | |
| with gr.Blocks(theme=gr.themes.Soft()) as demo: | |
| gr.Markdown("## π£οΈ Chatbot Suara Empatik untuk Skrining Awal Depresi") | |
| gr.Markdown( | |
| """ | |
| Rekam suara langsung dari mikrofon. Chatbot akan mengenali isi percakapan, | |
| menganalisis emosi, dan memberikan respons empatik. | |
| Cocok untuk skrining awal kondisi psikologis secara anonim. | |
| """ | |
| ) | |
| gr.Markdown( | |
| "β οΈ *Percakapan ini bersifat anonim dan hanya untuk keperluan skrining awal. " | |
| "Tidak menggantikan diagnosis profesional.*" | |
| ) | |
| with gr.Row(): | |
| audio_input = gr.Audio(source="microphone", type="filepath", label="ποΈ Rekam Suara") | |
| file_output = gr.File(label="π Unduh Transkripsi") | |
| with gr.Row(): | |
| transcript_output = gr.Textbox(label="π Hasil Transkripsi", lines=4) | |
| emotion_output = gr.Markdown(label="π Analisis Emosi") | |
| response_output = gr.Textbox(label="π¬ Respons Chatbot", lines=3) | |
| status_output = gr.Markdown(label="π Status") | |
| def chatbot_ui(audio): | |
| return transcribe_audio(audio) | |
| audio_input.change(fn=chatbot_ui, inputs=audio_input, outputs=[ | |
| status_output, | |
| transcript_output, | |
| file_output, | |
| response_output, | |
| emotion_output | |
| ]) | |
| demo.launch() |