lab-assistant / app.py
prarabdhmisra's picture
Deploy lab assistant
e5ed667 verified
Raw
History Blame Contribute Delete
5.95 kB
"""Gradio UI for the Lab Assistant.
Run locally: py -3.12 app.py
On Hugging Face: this file is the Space entry point (sdk: gradio).
"""
from __future__ import annotations
import gradio as gr
import config
# Build the knowledge base on first boot if the artifacts are missing, so a fresh
# clone or a freshly-pushed Space works without a manual ingest step.
if not (config.CHUNKS_FILE.exists() and config.EMBEDDINGS_FILE.exists()):
print("[app] knowledge base not found — running ingest at startup ...")
try:
import ingest
ingest.main()
except Exception as exc: # pragma: no cover
print(f"[app] startup ingest failed: {exc}")
import agent # noqa: E402 (import after potential ingest)
import leads # noqa: E402
EXAMPLES = [
"What is Spatial-RAG and what problem does it solve?",
"Summarize Prof. Zhao's work on graph retrieval-augmented generation.",
"Is Prof. Zhao taking new PhD students, and what does he look for?",
"What has the lab done on GNN explainability?",
"How does the lab reduce LLM API costs?",
]
HEADER = f"""
# 🤖 {config.LAB_NAME} — Research Assistant
**{config.PROFESSOR_NAME}** · {config.PROFESSOR_TITLE}
Ask about the lab's research, publications, and opportunities. Answers are
**grounded in the lab's publications with inline citations** — and the assistant
will tell you when something is outside its knowledge rather than guess.
[Homepage]({config.HOMEPAGE_URL}) · [Google Scholar]({config.SCHOLAR_URL})
"""
ABOUT = """
**Prof. Liang Zhao** is an award-winning AI researcher at Emory University (Winship
Distinguished Research Professor of Computer Science, with a joint appointment at the
Winship Cancer Institute). He builds **scalable and trustworthy machine learning for
structured, spatial, and scientific problems** — graph neural networks,
spatio-temporal/geospatial reasoning, retrieval-augmented and agentic LLMs, AI for
science, and efficient/trustworthy AI.
His work spans a decade-long arc: from the deployed **EMBERS** civil-unrest forecasting
system, through foundational **graph neural network** and **deep graph generation**
research, to today's frontier of **graph & spatial RAG**, **agentic systems**, and
**"world models" for science** (epidemiology, molecules, power grids). He is among
**Stanford's "Top 2%" most-cited scientists** — **~12,200 citations, h-index 52** —
with funding from **NSF (CAREER), NIH, Amazon, Meta, and NVIDIA**.
_Ask below for a cited summary of any topic, e.g. graph RAG, Spatial-RAG, GNN
explainability, LLM cost reduction, or his work on AI for science._
"""
DISCLAIMER = (
"_This is an AI assistant prototype. Responses are generated automatically from "
"the lab's public research and may be incomplete; they are not official "
"statements from Prof. Zhao or Emory University. Verify deadlines, admissions, "
"and funding through official channels._"
)
def respond(message: str, chat_history: list):
"""Stream the assistant's reply into the chat history."""
message = (message or "").strip()
if not message:
yield "", chat_history
return
chat_history = (chat_history or []) + [{"role": "user", "content": message}]
chat_history.append({"role": "assistant", "content": ""})
prior = chat_history[:-2] # history excluding the in-flight turn
for partial in agent.stream_answer(message, prior):
chat_history[-1]["content"] = partial
yield "", chat_history
# If they look like a prospective student/collaborator, nudge the lead form.
if agent.wants_to_connect(message):
chat_history[-1]["content"] += (
"\n\n👉 *Want the lab to reach out? Open **“📬 Connect with the lab”** "
"below and leave your details.*"
)
yield "", chat_history
def submit_lead(name, email, role, interest):
ok, msg = leads.save_lead(name, email, role, interest)
prefix = "✅ " if ok else "⚠️ "
return prefix + msg
with gr.Blocks(title=f"{config.LAB_NAME} — Assistant") as demo:
gr.Markdown(HEADER)
with gr.Accordion("ℹ️ About Prof. Zhao", open=False):
gr.Markdown(ABOUT)
chatbot = gr.Chatbot(height=460, label="Lab Assistant", avatar_images=(None, None))
with gr.Row():
msg = gr.Textbox(placeholder="Ask about the lab's research or opportunities…",
scale=8, show_label=False, autofocus=True)
send = gr.Button("Send", variant="primary", scale=1)
clear = gr.Button("Clear", scale=1)
gr.Examples(examples=[[e] for e in EXAMPLES], inputs=[msg], label="Try asking")
with gr.Accordion("📬 Connect with the lab (prospective students & collaborators)", open=False):
gr.Markdown(
"Leave your details and a note about your interest; they'll be passed to the lab."
)
with gr.Row():
lead_name = gr.Textbox(label="Name", scale=1)
lead_email = gr.Textbox(label="Email", scale=1)
lead_role = gr.Dropdown(
["Prospective PhD student", "Prospective MS/undergrad", "Collaborator (academia)",
"Collaborator (industry)", "Other"],
label="I am a…", scale=1,
)
lead_interest = gr.Textbox(label="Your interest / message", lines=2)
lead_submit = gr.Button("Send to the lab", variant="primary")
lead_status = gr.Markdown()
footer = config.BUILT_BY and f"Prototype built by **{config.BUILT_BY}**. "
gr.Markdown((footer or "") + DISCLAIMER)
# wiring
msg.submit(respond, [msg, chatbot], [msg, chatbot])
send.click(respond, [msg, chatbot], [msg, chatbot])
clear.click(lambda: [], None, chatbot, queue=False)
lead_submit.click(
submit_lead, [lead_name, lead_email, lead_role, lead_interest], [lead_status]
)
if __name__ == "__main__":
demo.queue().launch(theme=gr.themes.Soft())