import os import base64 import gradio as gr # Import our custom modules from src.audio import speech_to_text, text_to_speech from src.rag import init_vector_store, retrieve_context_multi from src.llm import generate_hindi_response, correct_hindi_query # Initialize the RAG vector store on startup print("Initializing application...") init_vector_store("data") print("Application ready.") def process_voice_query(audio_filepath, history=None): """ End-to-end pipeline: Audio In -> Audio Out + step-by-step text outputs. """ if audio_filepath is None: return "đī¸ Please record your question first.", "", None # Step 1: Speech-to-Text hindi_transcript = speech_to_text(audio_filepath) if not hindi_transcript: return "Error: No speech detected. Please try again.", "", None if hindi_transcript.startswith("Error:"): return hindi_transcript, "", None # Step 2: Retrieve relevant FAQ context directly using the Hindi transcript # If the user says a short affirmation like "Haa" (Yes), use the previous bot topic for the RAG search search_query = hindi_transcript if history and len(hindi_transcript.split()) <= 3: last_user, last_bot, _ = history[-1] if last_bot and "ā¤āĨā¤¯ā¤ž ā¤ā¤Ē ā¤¯ā¤š ā¤āĨ ā¤ā¤žā¤¨ā¤¨ā¤ž ā¤ā¤žā¤šāĨā¤ā¤āĨ:" in last_bot: topic = last_bot.split("ā¤āĨā¤¯ā¤ž ā¤ā¤Ē ā¤¯ā¤š ā¤āĨ ā¤ā¤žā¤¨ā¤¨ā¤ž ā¤ā¤žā¤šāĨā¤ā¤āĨ:")[-1].strip().strip("?") if topic: search_query = topic print(f"[RAG] Short query detected. Using previous topic: {search_query}") # Auto-correct phonetic STT typos (e.g. 'laan' -> 'loan') before RAG search corrected_query = correct_hindi_query(search_query) print(f"[LLM] Corrected Query for RAG: {corrected_query}") faq_context = retrieve_context_multi("", corrected_query) # Step 3: Generate Hindi answer, using history for conversational context hindi_answer = generate_hindi_response(hindi_transcript, faq_context, history) # Step 4: Convert answer to spoken audio audio_output_path = text_to_speech(hindi_answer) return hindi_transcript, hindi_answer, audio_output_path # ââ Gradio UI (Mobile App Style) ââââââââââââââââââââââââââââââââââââââââââââââ custom_css = """ /* Restrict main container to mobile width and center it */ .gradio-container { max-width: 450px !important; margin: auto !important; background-color: #f8fafc !important; } /* Card styling for elements */ .app-card { background: white; border-radius: 16px; padding: 16px; box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); margin-bottom: 16px; border: 1px solid #e2e8f0; } /* Header styling */ .app-header { text-align: center; padding: 20px 0 10px 0; color: #0f172a; } .app-header h1 { font-size: 1.5rem; font-weight: 700; margin: 0; } .app-header p { color: #64748b; font-size: 0.9rem; margin-top: 4px; } /* Chat History Styling */ .chat-history { display: flex; flex-direction: column; gap: 16px; max-height: 400px; overflow-y: auto; padding: 4px; } .chat-turn { display: flex; flex-direction: column; gap: 6px; } .user-bubble { align-self: flex-end; background-color: #dcf8c6; color: #0f172a; padding: 10px 14px; border-radius: 16px 16px 0px 16px; max-width: 85%; box-shadow: 0 1px 2px rgb(0 0 0 / 0.1); font-size: 0.95rem; } .bot-row { display: flex; align-items: flex-start; gap: 8px; align-self: flex-start; max-width: 95%; } .bot-bubble { background-color: #f1f5f9; color: #0f172a; padding: 10px 14px; border-radius: 16px 16px 16px 0px; box-shadow: 0 1px 2px rgb(0 0 0 / 0.1); font-size: 0.95rem; flex: 1; } .play-btn { background: #059669; border: none; border-radius: 50%; width: 32px; height: 32px; cursor: pointer; display: flex; align-items: center; justify-content: center; flex-shrink: 0; margin-top: 4px; box-shadow: 0 1px 3px rgb(0 0 0 / 0.2); } .play-btn:hover { background: #047857; } .play-btn:active { transform: scale(0.95); } .chat-label { font-size: 0.75rem; color: #64748b; margin-bottom: 2px; } /* Hide footer */ footer { display: none !important; } """ def _audio_to_base64(audio_path): """Convert an audio file to a base64 data URI for inline playback.""" if not audio_path or not os.path.exists(audio_path): return None try: with open(audio_path, "rb") as f: data = base64.b64encode(f.read()).decode("utf-8") return f"data:audio/mpeg;base64,{data}" except Exception: return None def render_chat_history(history): """Render the full chat history as HTML with inline audio players.""" if not history: return "
Your simple banking helper