""" JAIM - Gradio Web Interface A beautiful, interactive UI for querying the Vrikshayurveda knowledge base. """ import gradio as gr from rag_pipeline import JAIMPipeline from inference.engine import VrikshayurvedaInferenceEngine, DiagnosisResult # ─── Initialize Pipeline ───────────────────────────────────────────────────── pipeline = JAIMPipeline() # ─── Visualizer HTML (Phase 8a) ────────────────────────────────────────────── VISUALIZER_HTML = """
Facts in memory: 0
Rules fired: 0
Diagnosis:
Working memory
Proof trace
symptom derived dosha / disorder remedy
""" # ─── Query Handler ──────────────────────────────────────────────────────────── def handle_query(user_query: str, num_results: int) -> tuple[str, str]: """Process user query and return formatted response + sources.""" if not user_query.strip(): return "⚠️ Please enter a question about plant disorders.", "" result = pipeline.query(user_query, top_k=int(num_results)) diagnosis = result.get("diagnosis") # Build inference block from new chaining engine inference_block = "" if diagnosis: inference_block = ( "## 🧠 Inference Engine Analysis (Forward + Backward Chaining)\n" f"- **Primary Diagnosis:** {diagnosis.primary_diagnosis}\n" f"- **Dosha:** {diagnosis.dosha.capitalize()}\n" ) if diagnosis.forward_trace: inference_block += "- **Reasoning Chain:**\n" for step in diagnosis.forward_trace: inference_block += f" - {step}\n" remedies = [ f.replace("recommend_", "").replace("_", " ").title() for f in diagnosis.all_facts if f.startswith("recommend_") ] if remedies: inference_block += f"- **Recommended Treatments:** {', '.join(remedies)}\n" response_text = inference_block + "\n\n## JAIM Response (RAG + LLM)\n" + result["response"] # Format sources sources_text = "" for src in result["sources"]: meta = src["metadata"] score_bar = "█" * int(src["score"] * 20) + "░" * (20 - int(src["score"] * 20)) sources_text += ( f"**{src['id']}** — Score: `{src['score']}` {score_bar}\n" f"- **Dosha:** {meta.get('cause_given', 'N/A')} | " f"**Disorder:** {meta.get('disorder', 'N/A')}\n" f"- **Symptoms:** {meta.get('symptoms', 'N/A')[:120]}...\n\n" ) return response_text, sources_text # ─── Symptom Chain Explorer functions (Phase 8b) ───────────────────────────── def _wrap_in_iframe(html_content: str) -> str: """Wrap HTML in an iframe srcdoc so JavaScript executes (Gradio strips scripts).""" escaped = html_content.replace("&", "&").replace('"', """) return f'' def _render_viz_with_facts(facts: list[str], mode: str = "run") -> str: """ Injects a JS bootstrap call into the visualizer HTML so the canvas fires immediately on load. """ if not facts: return _wrap_in_iframe(VISUALIZER_HTML) facts_js = str(facts).replace("'", '"') call = ( f"runChainWithFacts({facts_js});" if mode == "run" else f"stepChainWithFacts({facts_js});" ) modified_html = VISUALIZER_HTML.replace( "initCanvas(0);\ndraw();", f"initCanvas(0);\ndraw();\nsetTimeout(function(){{{call}}},300);", ) return _wrap_in_iframe(modified_html) def explorer_run(selected_symptoms): if not selected_symptoms: return ( _wrap_in_iframe(VISUALIZER_HTML), "No symptoms selected. Check at least one symptom and try again." ) return ( _render_viz_with_facts(selected_symptoms, mode="run"), f"Auto-running chain for: {', '.join(s.replace('_',' ') for s in selected_symptoms)}" ) def explorer_step(selected_symptoms): if not selected_symptoms: return ( _wrap_in_iframe(VISUALIZER_HTML), "No symptoms selected. Check at least one symptom and try again." ) return ( _render_viz_with_facts(selected_symptoms, mode="step"), "Step mode — click '→ Step one rule at a time' repeatedly to advance." ) def explorer_reset(): return ( _wrap_in_iframe(VISUALIZER_HTML), "Reset. Select symptoms above, then choose auto-run or step through." ) # ─── Example Queries ────────────────────────────────────────────────────────── EXAMPLES = [ ["My tree trunk is bent and the fruits are hard and not juicy"], ["The fruits are bland and overripe with oozing"], ["Leaves are withering early and flowers are decaying"], ["My tree has been wounded by cutting"], ["There are ants on my plants and they smell bad"], ["I overwatered my plants and they look sick"], ["My seeds are not growing into productive trees"], ] # ─── Gradio UI ──────────────────────────────────────────────────────────────── CUSTOM_CSS = """ .gradio-container { max-width: 960px !important; margin: auto !important; } .main-title { text-align: center; background: linear-gradient(135deg, #2d5016 0%, #4a7c23 50%, #6ba33e 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-size: 2.8em !important; font-weight: 800 !important; margin-bottom: 0 !important; } .subtitle { text-align: center; color: #6b7280; font-size: 1.1em; margin-top: 0; margin-bottom: 1.5em; } footer { display: none !important; } """ with gr.Blocks( title="RAG for Vrikshayurveda", ) as app: # Header gr.HTML("""

🌿 RAG for Vrikshayurveda

Retrieval-Augmented Generation • Surapala's Science of Plant Life (वृक्षायुर्वेद)

""") with gr.Tab("🩺 Diagnose"): with gr.Row(): with gr.Column(scale=3): query_input = gr.Textbox( label="🔍 Describe your plant's symptoms", placeholder="e.g., My tree trunk is bent, fruits are hard and not juicy, leaves are yellowing...", lines=3, max_lines=5, ) with gr.Column(scale=1): num_results = gr.Slider( minimum=1, maximum=7, value=3, step=1, label="📊 Results to retrieve", ) query_btn = gr.Button( "🌱 Diagnose & Treat", variant="primary", size="lg", ) # Example queries gr.Examples( examples=EXAMPLES, inputs=query_input, label="💡 Try these examples", ) # Response section with gr.Accordion("🩺 Diagnosis & Treatment", open=True): response_output = gr.Markdown( value="*Enter your plant's symptoms above and click **Diagnose & Treat** to get Ayurvedic guidance.*" ) with gr.Accordion("📚 Retrieved Sources (from Pinecone)", open=False): sources_output = gr.Markdown( value="*Sources will appear here after a query.*" ) # Event handlers query_btn.click( fn=handle_query, inputs=[query_input, num_results], outputs=[response_output, sources_output], ) query_input.submit( fn=handle_query, inputs=[query_input, num_results], outputs=[response_output, sources_output], ) # ─── Symptom Chain Explorer tab (Phase 8c) ──────────────────────────────── with gr.Tab("🔗 Symptom Chain Explorer"): gr.Markdown("### Select symptoms and watch the inference engine reason step by step.") symptom_selector = gr.CheckboxGroup( choices=[ # Vata symptoms ("Trunk bent / crooked", "trunk_bent"), ("Knots on trunk or leaves", "knots_on_trunk"), ("Hard / dry fruits", "hard_fruits"), ("Slow defoliation", "slow_defoliation"), ("Flower / fruit loss", "flower_fruit_loss"), ("General yellowing", "general_yellowing"), # Kapha symptoms ("Delayed fruiting", "delayed_fruiting"), ("Bland overripe fruits", "bland_overripe_fruits"), ("Oozing without injury", "oozing_without_injury"), # Pitta symptoms ("Early leaf withering", "early_leaf_withering"), ("Early fruit / flower decay", "early_fruit_flower_decay"), # External / shared symptoms ("Vata-like symptoms (external)", "vata_like_symptoms"), ("Tree drying up", "tree_drying"), ("Lightning strike", "lightning_strike"), ("Tree uprooting", "tree_uprooting"), ("Branch breaking", "branch_breaking"), ("Tree twisting", "tree_twisting"), ("Mechanical wounds (axe etc.)", "tree_wounds"), ("Tree unproductive", "tree_unproductive"), ("Foul smell", "foul_smell"), ("Fragrance loss", "fragrance_loss"), ("Reduced leaf size", "reduced_leaf_size"), ("Stunted seedlings", "stunted_seedlings"), ("Tree indigestion / waterlogged","tree_indigestion"), ("Tree destruction from water", "tree_destruction"), # Seasonal context ("Winter / spring season", "winter_spring_season"), ("End of summer season", "end_of_summer"), ], label="Observed symptoms", ) with gr.Row(): run_btn = gr.Button("▶ Auto-run chain", variant="primary") step_btn = gr.Button("→ Step one rule at a time") reset_btn = gr.Button("↺ Reset") status_box = gr.Textbox( value="Select symptoms above, then choose auto-run or step through.", interactive=False, max_lines=1, label="", show_label=False, ) viz_html = gr.HTML(value=_wrap_in_iframe(VISUALIZER_HTML), label="Chain visualizer") run_btn.click( fn=explorer_run, inputs=[symptom_selector], outputs=[viz_html, status_box], ) step_btn.click( fn=explorer_step, inputs=[symptom_selector], outputs=[viz_html, status_box], ) reset_btn.click( fn=explorer_reset, inputs=[], outputs=[viz_html, status_box], ) # Footer gr.HTML("""
This app uses RAG (Retrieval-Augmented Generation) combining Pinecone vector search with AI
Embedding Model: BAAI/bge-large-en-v1.5 • LLM: Llama 3.3 70B • Inference: Forward + Backward Chaining • Knowledge Base: Vrikshayurveda by Surapala
""") # ─── Launch ─────────────────────────────────────────────────────────────────── if __name__ == "__main__": app.launch( server_name="127.0.0.1", server_port=7860, share=False, show_error=True, css=CUSTOM_CSS, theme=gr.themes.Soft( primary_hue="green", secondary_hue="emerald", neutral_hue="slate", font=gr.themes.GoogleFont("Inter"), ) )