Spaces:
Runtime error
Runtime error
| """ | |
| Gradio Blocks UI for the multilingual RAG chatbot. | |
| Run: python3 app.py | |
| """ | |
| import subprocess | |
| import pathlib | |
| import gradio as gr | |
| from rag_pipeline import RAGPipeline | |
| if not pathlib.Path("faiss_index").exists(): | |
| print("FAISS index not found β running ingest.py...") | |
| subprocess.run(["python3", "ingest.py"], check=True) | |
| pipeline = RAGPipeline() | |
| DESCRIPTION = """ | |
| # π Multilingual RAG Chatbot | |
| Ask questions in **English**, **Ψ§ΩΨΉΨ±Ψ¨ΩΨ© (Arabic)**, or **Bahasa Melayu (Malay)**. | |
| Answers are grounded in the knowledge base. Retrieved source passages appear below each answer. | |
| """ | |
| EXAMPLES = [ | |
| ["What is retrieval-augmented generation?"], | |
| ["How does machine learning differ from deep learning?"], | |
| ["What are vector databases used for?"], | |
| ["Ω Ψ§ ΩΩ Ψ§ΩΨ°ΩΨ§Ψ‘ Ψ§ΩΨ§Ψ΅Ψ·ΩΨ§ΨΉΩΨ"], | |
| ["ΩΩΩ ΩΨΉΩ Ω Ψ§ΩΨͺΨΉΩΩ Ψ§ΩΨ’ΩΩΨ"], | |
| ["Ω Ψ§ ΩΩ ΩΩΨ§ΨΉΨ― Ψ§ΩΨ¨ΩΨ§ΩΨ§Ψͺ Ψ§ΩΩ ΨͺΨ¬ΩΩΨ©Ψ"], | |
| ["Apakah itu kecerdasan buatan?"], | |
| ["Bagaimana pembelajaran mesin berfungsi?"], | |
| ["Apakah RAG dan kegunaannya?"], | |
| ] | |
| RTL_CSS = """ | |
| .message-bubble p, .message-bubble span, .prose p { | |
| unicode-bidi: plaintext; | |
| text-align: start; | |
| } | |
| [lang="ar"], .rtl-text { | |
| direction: rtl; | |
| text-align: right; | |
| font-family: 'Segoe UI', Tahoma, Arial, sans-serif; | |
| } | |
| .source-box { | |
| border-left: 3px solid #6366f1; | |
| padding-left: 0.75rem; | |
| margin: 0.5rem 0; | |
| font-size: 0.875rem; | |
| } | |
| .example-btn { font-size: 0.82rem !important; } | |
| """ | |
| JS_RTL = """ | |
| function applyRTL() { | |
| document.querySelectorAll('.message-bubble p, .prose p').forEach(el => { | |
| if (/[Ψ-ΫΏ]/.test(el.innerText || '')) { | |
| el.setAttribute('dir', 'rtl'); | |
| el.style.textAlign = 'right'; | |
| } | |
| }); | |
| } | |
| const observer = new MutationObserver(applyRTL); | |
| observer.observe(document.body, { childList: true, subtree: true }); | |
| applyRTL(); | |
| """ | |
| def format_sources(sources: list[dict]) -> str: | |
| if not sources: | |
| return "_No sources retrieved._" | |
| lines = [] | |
| for i, s in enumerate(sources, 1): | |
| snippet = s["content"].replace("\n", " ").strip() | |
| if len(snippet) > 300: | |
| snippet = snippet[:300] + "β¦" | |
| file_name = s["source"].split("/")[-1] | |
| lines.append(f"**[{i}] `{file_name}`**\n> {snippet}") | |
| return "\n\n".join(lines) | |
| def respond(message: str, history: list): | |
| if not message.strip(): | |
| yield history, "_Please enter a question._" | |
| return | |
| result = pipeline.ask(message) | |
| answer = result["answer"] | |
| sources_md = format_sources(result["sources"]) | |
| history = history + [ | |
| {"role": "user", "content": message}, | |
| {"role": "assistant", "content": answer}, | |
| ] | |
| yield history, sources_md | |
| def clear_all(): | |
| pipeline.chain.memory.clear() | |
| return [], "_Sources will appear here after your first question._" | |
| with gr.Blocks(title="Multilingual RAG Chatbot") as demo: | |
| gr.Markdown(DESCRIPTION) | |
| with gr.Row(): | |
| with gr.Column(scale=3): | |
| chatbot = gr.Chatbot( | |
| elem_id="chatbot", | |
| label="Chat", | |
| height=480, | |
| ) | |
| with gr.Row(): | |
| msg_box = gr.Textbox( | |
| placeholder="Type your question in English, Ψ§ΩΨΉΨ±Ψ¨ΩΨ©, or Bahasa Melayuβ¦", | |
| show_label=False, | |
| scale=8, | |
| autofocus=True, | |
| ) | |
| send_btn = gr.Button("Send β€", variant="primary", scale=1) | |
| with gr.Row(): | |
| clear_btn = gr.Button("π Clear Chat", variant="secondary", size="sm") | |
| with gr.Column(scale=2): | |
| gr.Markdown("### π Retrieved Sources") | |
| sources_box = gr.Markdown( | |
| value="_Sources will appear here after your first question._", | |
| ) | |
| with gr.Accordion("π‘ Example Questions", open=True): | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.Markdown("**π¬π§ English**") | |
| for ex in EXAMPLES[:3]: | |
| gr.Button(ex[0], elem_classes="example-btn").click( | |
| fn=lambda q=ex[0]: q, | |
| outputs=msg_box, | |
| ) | |
| with gr.Column(): | |
| gr.Markdown("**πΈπ¦ Ψ§ΩΨΉΨ±Ψ¨ΩΨ©**") | |
| for ex in EXAMPLES[3:6]: | |
| gr.Button(ex[0], elem_classes="example-btn").click( | |
| fn=lambda q=ex[0]: q, | |
| outputs=msg_box, | |
| ) | |
| with gr.Column(): | |
| gr.Markdown("**π²πΎ Bahasa Melayu**") | |
| for ex in EXAMPLES[6:]: | |
| gr.Button(ex[0], elem_classes="example-btn").click( | |
| fn=lambda q=ex[0]: q, | |
| outputs=msg_box, | |
| ) | |
| submit_inputs = [msg_box, chatbot] | |
| submit_outputs = [chatbot, sources_box] | |
| msg_box.submit(respond, submit_inputs, submit_outputs).then( | |
| fn=lambda: "", outputs=msg_box | |
| ) | |
| send_btn.click(respond, submit_inputs, submit_outputs).then( | |
| fn=lambda: "", outputs=msg_box | |
| ) | |
| clear_btn.click(clear_all, outputs=[chatbot, sources_box]) | |
| if __name__ == "__main__": | |
| demo.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| show_error=True, | |
| css=RTL_CSS, | |
| js=JS_RTL, | |
| ) | |