"""Launches a Gradio app that runs an AI planning agent to find smart online deals. Uses Python's built-in logging system for consistent logs. Includes demo mode restrictions: MAX_DEMO_RUNS_PER_DAY runs per day. """ import os from typing import Tuple import gradio as gr from src.agents.pipeline import run_and_stream_logs from src.config.constants import ( IS_DEMO_VERSION, MAX_CATEGORY_SELECTION, MAX_DEMO_RUNS_PER_DAY, PROJECT_NAME, VERSION, ) from src.config.feeds import CATEGORY_FEEDS from src.ui.formatting import format_deals_table from src.utils.logger import console from src.utils.state_manager import can_run_app PROJECT_NAME_CAP = PROJECT_NAME.capitalize() REPO_URL = f"https://github.com/lisekarimi/{PROJECT_NAME}" DOC_URL = f"https://lisekarimi.github.io/{PROJECT_NAME}" def build_ui() -> gr.Blocks: """Constructs and returns the Gradio UI interface, with error handling.""" try: with open( os.path.join(os.path.dirname(__file__), "assets", "styles.css"), "r" ) as f: css = f.read() except Exception as e: css = "" console.print(f"[bold yellow]⚠️ Failed to load CSS:[/] {e}") # Set initial UI state here disable_btn = False initial_status = "Loading demo status..." # Building the UI try: with gr.Blocks(css=css, title=f"🏷️{PROJECT_NAME_CAP}") as ui: with gr.Column(elem_id="app-container"): # πŸ” Top content gr.Markdown(f"

🏷️ {PROJECT_NAME_CAP}

") gr.Markdown( "

Autonomous AI Agents Snapping the Best " "Deals Online

" ) gr.HTML( f"""

🏷️ Snapr, an Agentic AI System, discovers the best online deals for youβ€”smart, simple, and automatic. Let AI do the work, so you can save money without any effort.

πŸ€– How It Works:

1️⃣ Choose up to {MAX_CATEGORY_SELECTION} categories to search.

2️⃣ Click "Find Smart Deals" β€” AI scans, estimates prices, and filters top discounts.

3️⃣ See the best deals in a table with prices, discounts, and direct links.

""" ) if IS_DEMO_VERSION: gr.Markdown( f"""

⚠️ This is a demo version β€” limited to {MAX_DEMO_RUNS_PER_DAY} global runs per day for all users.

""" ) gr.Markdown( f""" """ ) with gr.Column(elem_id="left-col"): category_selector = gr.Dropdown( choices=list(CATEGORY_FEEDS.keys()), value="Electronics", multiselect=True, label=( f"🧭 Select up to {MAX_CATEGORY_SELECTION} Deal Categories" ), elem_id="category-selector", elem_classes="custom-dropdown", ) run_btn = gr.Button( "πŸ” Find Smart Deals", elem_id="run-btn", variant="primary", elem_classes="run-button", interactive=not disable_btn, ) status_msg = gr.HTML(value=initial_status, elem_id="status-message") # Logs + deals logs_output = gr.HTML( value="""
πŸ“œ Live Agent Logs
πŸ•΅οΈβ€β™€οΈ Click "πŸ” Find Smart Deals" to wake the agents and stream logs here!
""" ) deals_output = gr.HTML( value=format_deals_table([]), elem_id="deal-table" ) # Connect button run_btn.click( fn=run_and_stream_logs, inputs=[category_selector], outputs=[logs_output, deals_output, run_btn, status_msg], ) # Status update on load @ui.load(outputs=[status_msg, run_btn]) def update_status_on_load() -> Tuple[str, gr.update]: """Sets demo status and button state on UI load.""" can_run, status = can_run_app() btn_state = gr.update( interactive=can_run, elem_classes=( ["run-button", "btn-disabled"] if not can_run else ["run-button"] ), ) return status, btn_state # Bottom: version info gr.Markdown( f"""

πŸ”– Version {VERSION}

""" ) return ui except Exception as e: console.print(f"[bold red]❌ Failed to build UI:[/] {e}") raise