| """MiniFam — a local AI family assistant. Gradio entry point (Hugging Face Space). |
| |
| Run locally: source .venv/bin/activate && python app.py |
| Then open the printed http://127.0.0.1:7860 URL. |
| """ |
|
|
| import gradio as gr |
|
|
| from minifam import agent, config |
|
|
|
|
| def respond(user_msg, display_history, raw_messages, member): |
| """Handle one chat submission.""" |
| user_msg = (user_msg or "").strip() |
| if not user_msg: |
| return display_history, raw_messages, "" |
|
|
| raw_messages = raw_messages + [{"role": "user", "content": user_msg}] |
| try: |
| reply, raw_messages = agent.run_agent(raw_messages, member) |
| except Exception as e: |
| reply = ( |
| f"⚠️ Could not reach the model ({e}).\n\n" |
| "Is Ollama running and is the model pulled? Try: `ollama run qwen3:30b`" |
| ) |
|
|
| display_history = display_history + [ |
| {"role": "user", "content": user_msg}, |
| {"role": "assistant", "content": reply}, |
| ] |
| return display_history, raw_messages, "" |
|
|
|
|
| def switch_member(_member): |
| """Start a fresh conversation when the active member changes.""" |
| return [], [] |
|
|
|
|
| with gr.Blocks(title="MiniFam") as demo: |
| gr.Markdown( |
| "# 🏡 MiniFam\n" |
| "Your family's assistant — runs entirely on your own computer." |
| ) |
|
|
| _names = config.member_names() |
| member = gr.Dropdown( |
| choices=_names, |
| value=_names[0] if _names else None, |
| label="Who's talking?", |
| ) |
|
|
| chatbot = gr.Chatbot(height=460, label="MiniFam") |
| raw_state = gr.State([]) |
|
|
| msg = gr.Textbox( |
| placeholder="e.g. Remind me to buy milk tomorrow · What are my notes?", |
| label="Message", |
| autofocus=True, |
| ) |
|
|
| msg.submit( |
| respond, |
| inputs=[msg, chatbot, raw_state, member], |
| outputs=[chatbot, raw_state, msg], |
| ) |
| member.change(switch_member, inputs=member, outputs=[chatbot, raw_state]) |
|
|
|
|
| if __name__ == "__main__": |
| demo.launch(theme=gr.themes.Soft()) |
|
|