"""Gradio web UI for the personal finance manager.""" import os import threading import gradio as gr import bot from ledger import get_ledger from agent import stream_response, execute logging_format = "%(asctime)s %(levelname)s %(name)s: %(message)s" import logging logging.basicConfig(level=logging.INFO, format=logging_format) ledger = get_ledger() threading.Thread(target=bot.start, args=(ledger,), daemon=True).start() # ── chat handler ────────────────────────────────────────────────────────────── def respond(message: str, history: list[dict], hf_token: gr.OAuthToken): token = hf_token.token if hf_token else os.getenv("HF_TOKEN", "") if not token: yield "Please log in with HuggingFace to use the assistant." return final_reply, final_action = "", None for partial, action in stream_response(message, history, ledger, token): final_reply, final_action = partial, action yield partial if final_action: confirmation = execute(final_action, ledger, message) if confirmation: yield final_reply + "\n\n" + confirmation # ── ledger tab helpers ──────────────────────────────────────────────────────── def refresh_ledger(): return ledger.recent(50), f"### 💰 Total: ${ledger.total():.2f}" # ── layout ──────────────────────────────────────────────────────────────────── with gr.Blocks(theme=gr.themes.Soft(), title="💸 Finance Manager") as demo: with gr.Sidebar(): gr.LoginButton() gr.Markdown(f"**Storage:** {ledger.status}") with gr.Tabs(): with gr.Tab("💬 Chat"): gr.ChatInterface( respond, type="messages", placeholder="e.g. 'Spent $12 on lunch' or 'How much did I spend on food?'", ) with gr.Tab("📊 Ledger"): refresh_btn = gr.Button("🔄 Refresh", variant="secondary") table = gr.Dataframe(value=ledger.recent(50), interactive=False) total_md = gr.Markdown(f"### 💰 Total: ${ledger.total():.2f}") refresh_btn.click(fn=refresh_ledger, outputs=[table, total_md]) if __name__ == "__main__": demo.launch()