"""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([]) # full model conversation (incl. tool calls) 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())