Spaces:
Sleeping
Sleeping
| # app/ui_proxy.py | |
| from __future__ import annotations | |
| import json, os, time | |
| from typing import Tuple, Generator | |
| import gradio as gr | |
| from gradio_client import Client | |
| def _pretty(x) -> str: | |
| try: | |
| return json.dumps(x, indent=2, ensure_ascii=False) | |
| except Exception: | |
| return str(x) | |
| def _normalize_space_id(raw: str) -> str: | |
| """Accept 'owner/repo' or a full URL; return 'owner/repo' only.""" | |
| s = (raw or "").strip() | |
| for pref in ("https://huggingface.co/spaces/", "http://huggingface.co/spaces/"): | |
| if s.startswith(pref): | |
| s = s[len(pref):].strip("/ ") | |
| return s | |
| def _client() -> Client: | |
| space_id = _normalize_space_id(os.getenv("PROXY_BACKEND_SPACE")) | |
| if not space_id or "/" not in space_id: | |
| raise RuntimeError("Backend is not configured.") | |
| token = (os.getenv("HF_API_TOKEN") or os.getenv("HF_TOKEN") or "").strip() | |
| if not token: | |
| raise RuntimeError("Access to backend is not available.") | |
| return Client(space_id, hf_token=token) | |
| def _pick_api_name(cli: Client) -> str: | |
| manual = (os.getenv("PROXY_API_NAME") or "").strip() | |
| if manual: | |
| return manual if manual.startswith("/") else f"/{manual}" | |
| try: | |
| info = cli.view_api() | |
| if not info: | |
| return "/predict" | |
| eps = info.get("endpoints") or [] | |
| names = [e.get("name") for e in eps if e and e.get("name")] | |
| if "/predict" in names: | |
| return "/predict" | |
| if names: | |
| return names[0] | |
| except Exception: | |
| pass | |
| return "/predict" | |
| def handle_query_proxy(q: str) -> Generator[Tuple[str, str, str, str, str], None, None]: | |
| """Yields: routed_json, plan_json, answer_json, human_md, perf_json""" | |
| loading = "### ⏳ Fetching…\nContacting the analysis backend." | |
| try: | |
| # Minimal, generic status | |
| yield "{}", "{}", "{}", loading, _pretty({"status": "connecting"}) | |
| cli = _client() | |
| api_name = _pick_api_name(cli) | |
| yield "{}", "{}", "{}", loading, _pretty({"status": "running"}) | |
| job = cli.submit(q, api_name=api_name) | |
| # Tiny delay for nicer UX | |
| time.sleep(0.3) | |
| if not job.done(): | |
| yield "{}", "{}", "{}", loading, _pretty({"status": "running"}) | |
| routed_json, plan_json, answer_json, human_text, perf_json = job.result() | |
| yield routed_json, plan_json, answer_json, human_text, perf_json | |
| except Exception: | |
| friendly = ( | |
| "### ❌ Something went wrong\n" | |
| "Please try again in a moment." | |
| ) | |
| # No exception details, no env, no tokens. | |
| yield "{}", "{}", "{}", friendly, _pretty({"status": "error"}) | |
| def build_proxy() -> gr.Blocks: | |
| with gr.Blocks(title="Crypto Copilot (Public)") as demo: | |
| gr.Markdown("## Crypto Copilot — Public UI") | |
| with gr.Row(): | |
| query = gr.Textbox( | |
| label="Your question", | |
| placeholder="Examples: 'What is BTC price now?', 'Compare BTC vs ETH 30d drawdown'", | |
| lines=2, | |
| ) | |
| run_btn = gr.Button("Run", variant="primary") | |
| # Summary first (shows loading message immediately) | |
| with gr.Tab("Summary"): | |
| human_out = gr.Markdown() | |
| with gr.Tab("How it was decided"): | |
| routed_out = gr.Code(language="json", label="Router output (intent/assets/windows)") | |
| with gr.Tab("Plan"): | |
| plan_out = gr.Code(language="json", label="Planner output") | |
| with gr.Tab("Answer JSON"): | |
| answer_out = gr.Code(language="json", label="Structured answer (schema)") | |
| with gr.Tab("Perf & Cost"): | |
| perf_out = gr.Code(language="json", label="Latency, backend, cache stats") | |
| run_btn.click( | |
| fn=handle_query_proxy, | |
| inputs=[query], | |
| outputs=[routed_out, plan_out, answer_out, human_out, perf_out], | |
| show_progress=True, | |
| ) | |
| gr.Examples( | |
| examples=[ | |
| "What is BTC price now?", | |
| "Compare BTC vs ETH YTD and 30d drawdown", | |
| "Show 7d return and volatility for SOL", | |
| "Portfolio: BTC 60% ETH 40%", | |
| "What moved ETH today?", | |
| ], | |
| inputs=[query], | |
| outputs=[routed_out, plan_out, answer_out, human_out, perf_out], | |
| fn=handle_query_proxy, | |
| cache_examples=False, | |
| label="Try these example questions", | |
| run_on_click=True, | |
| ) | |
| return demo |