"""One-command LIVE demo launcher with preflight checks. This is the friendly front door for the *local* live demo. It: 1. checks your .env has a working key setup (GROQ is the only hard requirement), 2. builds the warehouse DB if it's missing, 3. makes sure at least one demo item is actually low-stock (resets if needed), 4. launches the Streamlit dashboard and opens your browser, 5. prints exactly what to click. You then drive the whole thing from the dashboard's 🎮 Live demo sidebar — no second terminal, no run_id juggling. Run it with the project's Python, from the project root: python -m scripts.live_demo or just double-click run_live_demo.bat (Windows). """ from __future__ import annotations import sqlite3 import subprocess import sys import time import webbrowser from pathlib import Path # Windows consoles default to cp1252 and crash on emoji/arrows in our banners. # Force UTF-8 so the launcher never dies on a print() (this bit us before). for _stream in (sys.stdout, sys.stderr): try: _stream.reconfigure(encoding="utf-8", errors="replace") # py3.7+ except (AttributeError, ValueError): pass sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) from core.config import PROJECT_ROOT, api_key, db_path, settings # noqa: E402 PORT = settings()["ports"]["ui"] BAR = "=" * 66 def _c(msg: str, ok: bool | None = True) -> None: mark = {True: " [OK] ", False: " [FAIL] ", None: " [WARN] "}[ok] print(mark + msg) def preflight() -> bool: """Return True if we're clear to launch, False if a hard requirement failed.""" print(BAR) print(" AutoSource — LIVE demo preflight") print(BAR) ok = True # --- 1. Python + package check --- _c(f"Python {sys.version.split()[0]} at {sys.executable}") try: import streamlit # noqa: F401 import groq # noqa: F401 _c("Core packages importable (streamlit, groq, mcp, a2a-sdk)") except ImportError as e: _c(f"Missing package: {e.name}. Run: pip install -r requirements.txt", False) return False # --- 2. .env / keys --- env_file = PROJECT_ROOT / ".env" if not env_file.exists(): _c(".env not found. Copy .env.example to .env and add your GROQ_API_KEY.", False) return False if api_key("GROQ_API_KEY"): _c("GROQ_API_KEY present (the negotiation workhorse)") else: _c("GROQ_API_KEY missing in .env — the live demo cannot negotiate.", False) ok = False for opt in ("GEMINI_API_KEY", "OPENROUTER_API_KEY", "HF_TOKEN"): present = bool(api_key(opt)) _c(f"{opt} {'present' if present else 'not set (optional)'}", True if present else None) if not ok: return False # --- 3. warehouse DB --- db = db_path() if not db.exists(): _c("Warehouse DB missing — building it now…", None) _build_db() else: _c(f"Warehouse DB present ({db.name})") # --- 4. is the headline demo item actually low-stock? --- demo_sku = settings()["app"]["demo_sku"] low = _low_stock_items() if demo_sku not in low: _c(f"Headline item {demo_sku} isn't low-stock (probably on-order from a " f"previous run). Resetting warehouse to a clean demo state…", None) _build_db() low = _low_stock_items() _c(f"Low-stock items ready to procure: {', '.join(low) or '(none!)'}", demo_sku in low) print(BAR) return demo_sku in low def _build_db() -> None: subprocess.run([sys.executable, "-m", "scripts.init_db"], cwd=str(PROJECT_ROOT), check=False) def _low_stock_items() -> list[str]: db = db_path() if not db.exists(): return [] with sqlite3.connect(f"file:{db}?mode=ro", uri=True) as c: rows = c.execute("SELECT sku FROM inventory WHERE status='low'").fetchall() return [r[0] for r in rows] def launch_dashboard() -> None: url = f"http://localhost:{PORT}/?mode=live" print() print(" Launching the dashboard… (leave this window open)") print() print(" WHEN THE BROWSER OPENS:") print(" 1. Look at the LEFT sidebar → '🎮 Live demo'") print(" 2. Click 🚀 Trigger stock check & negotiate") print(" 3. Watch the agents negotiate (~2-4 min on free tiers)") print(" 4. When the AP2 mandate panel turns yellow → click ✅ Approve") print(" 5. Between demos, click 🔄 Reset warehouse to make it low-stock again") print() print(f" If the browser doesn't open, go to: {url}") print(" To STOP: press Ctrl+C here.") print(BAR) # open the browser a moment after streamlit starts binding the port def _open_later(): time.sleep(3.5) try: webbrowser.open(url) except Exception: # noqa: BLE001 pass import threading threading.Thread(target=_open_later, daemon=True).start() subprocess.run( [sys.executable, "-m", "streamlit", "run", "ui/app.py", "--server.port", str(PORT), "--server.headless", "true"], cwd=str(PROJECT_ROOT), check=False) def main() -> None: if not preflight(): print() print(" Preflight failed — fix the [FAIL] item above and re-run.") print(" Most common fix: add GROQ_API_KEY to your .env file.") sys.exit(1) launch_dashboard() if __name__ == "__main__": main()