Spaces:
Sleeping
Sleeping
| """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() | |