"""
app.py
─────────────────────────────────────────────
Streamlit web interface for the Rural Healthcare RAG Assistant.
Design: "Bio-signal interface" — dark medical HUD aesthetic.
Run with:
streamlit run src/app.py
─────────────────────────────────────────────
"""
import streamlit as st
import os
from rag import load_vectorstore, get_llm, answer_question, check_symptoms
VECTORSTORE_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "vectorstore")
def ensure_vectorstore_downloaded():
"""Download pre-built vectorstore from HF dataset repo if not present locally."""
if os.path.exists(VECTORSTORE_DIR) and os.listdir(VECTORSTORE_DIR):
return # already exists, nothing to do
from huggingface_hub import snapshot_download
snapshot_download(
repo_id="MridulSharma02/sehat-sathi-vectorstore",
repo_type="dataset",
local_dir=VECTORSTORE_DIR,
)
# ─────────────────────────────────────────────
# PAGE CONFIG
# ─────────────────────────────────────────────
st.set_page_config(
page_title="Sehat Sathi · Rural Health Assistant",
page_icon="🩺",
layout="centered",
initial_sidebar_state="expanded",
)
symptom_mode = st.sidebar.toggle("🩹 Symptom Checker Mode", value=False)
# ─────────────────────────────────────────────
# DESIGN SYSTEM — "Bio-signal interface"
# ─────────────────────────────────────────────
st.markdown("""
""", unsafe_allow_html=True)
# ─────────────────────────────────────────────
# HERO SECTION
# ─────────────────────────────────────────────
st.markdown("""
सेहत साथी · SYSTEM ONLINE
Trusted answers,
in plain language.
Ask any health question. Every answer is grounded in official government
guidelines and verified medical sources — not guesswork.
""", unsafe_allow_html=True)
# ─────────────────────────────────────────────
# STAT STRIP
# ─────────────────────────────────────────────
st.markdown("""
""", unsafe_allow_html=True)
# ─────────────────────────────────────────────
# LOAD MODELS (cached so it only loads once)
# ─────────────────────────────────────────────
@st.cache_resource(show_spinner=False)
def load_resources():
vectordb = load_vectorstore()
llm = get_llm()
return vectordb, llm
with st.spinner("🔧 Loading knowledge base..."):
ensure_vectorstore_downloaded()
try:
with st.spinner("🔧 Loading knowledge base..."):
vectordb, llm = load_resources()
except ValueError as e:
st.error(f"⚠️ {e}")
st.info("Please add your Groq API key to the `.env` file (or Space secrets).")
st.stop()
# ─────────────────────────────────────────────
# CHAT HISTORY
# ─────────────────────────────────────────────
if "question_count" not in st.session_state:
st.session_state.question_count = 0
MAX_QUESTIONS_PER_SESSION = 15
if "messages" not in st.session_state:
st.session_state.messages = [
{
"role": "assistant",
"content": "नमस्ते 👋 I'm here to help with your health questions. What's on your mind today?",
"sources": [],
"is_verified": None
}
]
# ─────────────────────────────────────────────
# SUGGESTED QUESTION CHIPS (only show before first real question)
# ─────────────────────────────────────────────
SUGGESTIONS = [
"What are the symptoms of dengue?",
"How is diabetes managed?",
"What vaccines do newborns need?",
"Signs of dehydration in children",
]
clicked_suggestion = None
if len(st.session_state.messages) == 1:
st.markdown('⌁ Try asking
', unsafe_allow_html=True)
chip_cols = st.columns(2)
for i, q in enumerate(SUGGESTIONS):
with chip_cols[i % 2]:
if st.button(q, key=f"chip_{i}", use_container_width=True):
clicked_suggestion = q
# Display chat history
for msg in st.session_state.messages:
with st.chat_message(msg["role"], avatar="🩺" if msg["role"] == "assistant" else "🙋"):
if msg.get("is_verified") is True:
st.markdown('✓ Verified source', unsafe_allow_html=True)
elif msg.get("is_verified") is False:
st.markdown('⌁ General knowledge', unsafe_allow_html=True)
st.markdown(msg["content"])
if msg.get("sources"):
tags_html = "".join([f'⌁ {s}' for s in msg["sources"]])
st.markdown(tags_html, unsafe_allow_html=True)
# ─────────────────────────────────────────────
# CHAT INPUT
# ─────────────────────────────────────────────
user_query = st.chat_input("Type your health question here...")
if clicked_suggestion:
user_query = clicked_suggestion
if user_query:
if st.session_state.question_count >= MAX_QUESTIONS_PER_SESSION:
st.warning("⚠️ You've reached the session limit of 15 questions. Please refresh the page to start a new session.")
st.stop()
st.session_state.question_count += 1
st.session_state.messages.append({"role": "user", "content": user_query, "sources": [], "is_verified": None})
with st.chat_message("user", avatar="🙋"):
st.markdown(user_query)
with st.chat_message("assistant", avatar="🩺"):
with st.spinner("Analyzing..." if symptom_mode else "Scanning verified sources..."):
try:
if symptom_mode:
answer = check_symptoms(user_query, llm)
sources, is_verified = [], None
else:
answer, sources, is_verified = answer_question(user_query, vectordb, llm, chat_history=st.session_state.messages)
except Exception as e:
answer = f"⚠️ Something went wrong: {e}"
sources = []
is_verified = None
if is_verified is True:
st.markdown('✓ Verified source', unsafe_allow_html=True)
elif is_verified is False:
st.markdown('⌁ General knowledge', unsafe_allow_html=True)
st.markdown(answer)
if sources:
tags_html = "".join([f'⌁ {s}' for s in sources])
st.markdown(tags_html, unsafe_allow_html=True)
st.session_state.messages.append({
"role": "assistant",
"content": answer,
"sources": sources,
"is_verified": is_verified
})
st.rerun()
# ─────────────────────────────────────────────
# DISCLAIMER
# ─────────────────────────────────────────────
st.markdown("""
⚠️ Important: This assistant provides general health information based on official guidelines.
It is not a substitute for professional medical advice. For emergencies or serious symptoms,
please visit your nearest health center or call emergency services immediately.
""", unsafe_allow_html=True)
# ─────────────────────────────────────────────
# SIDEBAR
# ─────────────────────────────────────────────
with st.sidebar:
st.markdown("""
### 🩺 Sehat Sathi
*Your health companion, grounded in truth.*
---
**How this works**
This assistant uses **RAG (Retrieval Augmented Generation)** — it searches verified documents first, then crafts an answer only from what it finds there.
**Knowledge sources:**
- 🏛️ National Health Mission guidelines
- 🌍 WHO India fact sheets
- 📋 Ayushman Bharat documentation
- 📊 Verified medical Q&A datasets
---
""")
if st.button("🗑️ Clear conversation", use_container_width=True):
st.session_state.messages = [
{
"role": "assistant",
"content": "नमस्ते 👋 I'm here to help with your health questions. What's on your mind today?",
"sources": []
}
]
st.rerun()