Spaces:
Sleeping
Sleeping
Download fa_page.py from TheFinAI/FinLLaVA: direct link, hf CLI and curl.
- Browser
- Download file 6.64 kB
-
https://huggingface.co/spaces/TheFinAI/FinLLaVA/resolve/main/fa_page.py
- Command line
-
hf download hf://spaces/TheFinAI/FinLLaVA/fa_page.py
-
curl -L -o fa_page.py https://huggingface.co/spaces/TheFinAI/FinLLaVA/resolve/main/fa_page.py
6.64 kB
| """Custom The Fin AI page for Gradio-backed demo Spaces. | |
| Gradio only serves the page and the `/chat` API (gr.api); the whole UI is our own HTML/CSS/JS (page/), which talks to | |
| the API with @gradio/client. Works with Gradio 5 (head/css on Blocks) and Gradio 6 (head/css on launch). | |
| page = fa_page.Page(cfg) # cfg: see build_body() | |
| with gr.Blocks(**page.blocks_kwargs()) as demo: | |
| page.render() | |
| gr.api(chat, api_name="chat") | |
| demo.queue().launch(**page.launch_kwargs()) | |
| """ | |
| import html | |
| import json | |
| import os | |
| import gradio as gr | |
| HERE = os.path.dirname(os.path.abspath(__file__)) | |
| PAGE = os.path.join(HERE, "page") | |
| ASSETS = os.path.join(HERE, "assets") | |
| gr.set_static_paths(paths=[ASSETS]) | |
| GRADIO6 = int(gr.__version__.split(".")[0]) >= 6 | |
| CLIENT = "2.7.1" if GRADIO6 else "1.19.1" # @gradio/client matching the Gradio major version | |
| e = lambda s: html.escape(str(s), quote=True) | |
| def asset(path): | |
| return f"/gradio_api/file={os.path.join(ASSETS, path)}" | |
| def _read(name): | |
| with open(os.path.join(PAGE, name), encoding="utf-8") as f: | |
| return f.read() | |
| ICON_SEND = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg>' | |
| ICON_STOP = '<svg viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="6" width="12" height="12" rx="2"/></svg>' | |
| ICON_IMG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="3"/><circle cx="9" cy="10" r="2"/><path d="m21 16-5-5-9 9"/></svg>' | |
| class Page: | |
| def __init__(self, cfg): | |
| self.cfg = cfg | |
| def head(self): | |
| c = self.cfg | |
| chat = {"client": CLIENT, "endpoint": "/chat", "image": c.get("image", False), "avatar": asset(c["avatar"]), | |
| "greeting": c["greeting"], "params": c["params"], "readyText": c.get("ready_text", "Ready"), | |
| "examples": [{**x, "image": asset(x["image"]) if x.get("image") else None} for x in c["examples"]]} | |
| fonts = ('<link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>' | |
| '<link href="https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,400;0,6..72,500;1,6..72,400' | |
| '&family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@500&display=swap" rel="stylesheet">') | |
| return (fonts + f'<link rel="icon" href="{asset("finai-logo.png")}"><style>{_read("style.css")}\n{_read("chat.css")}</style>' | |
| f'<script>window.FA_CHAT={json.dumps(chat)};</script><script type="module">{_read("chat.js")}</script>') | |
| def body(self): | |
| c = self.cfg | |
| nav = "".join(f'<a href="{e(u)}" target="_blank" rel="noreferrer">{e(l)}</a>' for l, u in c["nav"]) | |
| stats = "".join(f'<div><b data-count="{e(v)}"{f" data-dec={d}" if d else ""}>0</b><span>{e(k)}</span></div>' for v, k, d in c["stats"]) | |
| pills = "".join(f'<a class="pill" href="{e(u)}" target="_blank" rel="noreferrer">{e(l)}</a>' for l, u in c["links"]) | |
| orgs = "".join(f'<a class="org" href="{e(u)}" target="_blank" rel="noreferrer" style="--d:{i * 40}ms" title="{e(n)}">' | |
| f'<img src="{asset("orgs/" + f)}" alt="" class="{e(k)}" loading="lazy"><span>{e(n)}</span></a>' for i, (n, f, u, k) in enumerate(c["orgs"])) | |
| attach = (f'<label class="icon-btn attach" title="Add an image">{ICON_IMG}<input id="fa-image" type="file" accept="image/*"></label>' | |
| '<div id="fa-preview" hidden><img alt=""><button type="button" aria-label="Remove image">×</button></div>') if c.get("image") else "" | |
| return f'''<div id="fa-app"> | |
| <div class="progress" aria-hidden="true"></div> | |
| <header class="header scrolled"><div class="wrap nav"> | |
| <a class="brand" href="https://thefin.ai" target="_blank" rel="noreferrer"><img src="{asset("finai-logo.png")}" alt="">The Fin AI</a> | |
| <nav class="links">{nav}<a href="https://thefin.ai" target="_blank" rel="noreferrer">thefin.ai ↗</a></nav> | |
| </div></header> | |
| <main class="wrap demo"> | |
| <section class="intro"> | |
| <span class="kicker">{e(c["kicker"])}</span> | |
| <h1>{c["title_html"]}</h1> | |
| <p class="lead">{c["lead_html"]}</p> | |
| <div class="fb-stats">{stats}</div> | |
| <div class="links-row">{pills}</div> | |
| <h3 class="side-h">Try an example</h3> | |
| <div id="fa-examples"></div> | |
| <details class="params"><summary>Generation settings</summary><div id="fa-params"></div></details> | |
| </section> | |
| <section class="panel" aria-label="Chat"> | |
| <div class="panel-top"><span id="fa-status" data-state="connecting"><i></i><span>Connecting…</span></span><button type="button" class="ghost" id="fa-clear">New chat</button></div> | |
| <div id="fa-log" aria-live="polite"></div> | |
| <div class="composer"> | |
| {attach} | |
| <textarea id="fa-input" rows="1" placeholder="{e(c["placeholder"])}"></textarea> | |
| <button type="button" class="icon-btn" id="fa-send" aria-label="Send">{ICON_SEND}</button> | |
| <button type="button" class="icon-btn" id="fa-stop" aria-label="Stop" hidden>{ICON_STOP}</button> | |
| <div id="fa-note" role="status"></div> | |
| </div> | |
| <p class="hint">{c["hint_html"]}</p> | |
| </section> | |
| </main> | |
| <section class="wrap credits-sec reveal"> | |
| <span class="kicker">People & partners</span> | |
| <h2>Built together</h2> | |
| <p class="sub">{c["orgs_sub_html"]}</p> | |
| <div class="orgs">{orgs}</div> | |
| <p class="disclaimer">{c["disclaimer"]}</p> | |
| </section> | |
| <footer class="footer wrap"> | |
| <span class="brand"><img src="{asset("finai-logo.png")}" alt="">The Fin AI</span> | |
| <nav><a href="https://github.com/The-FinAI" target="_blank" rel="noreferrer">GitHub</a><a href="https://huggingface.co/TheFinAI" target="_blank" rel="noreferrer">Hugging Face</a><a href="https://huggingface.co/collections/TheFinAI/the-fin-ai-leaderboards-6ac7154319e5aa2b52037515" target="_blank" rel="noreferrer">Leaderboards</a><a href="https://discord.gg/Wpt347rusk" target="_blank" rel="noreferrer">Discord</a></nav> | |
| <span class="copy">© 2026 The Fin AI · AI Readiness in Finance</span> | |
| </footer> | |
| </div>''' | |
| def render(self): | |
| return gr.HTML(self.body()) | |
| def blocks_kwargs(self): | |
| kw = dict(title=self.cfg["page_title"], fill_width=True) | |
| if not GRADIO6: | |
| kw["head"] = self.head() | |
| return kw | |
| def launch_kwargs(self): | |
| kw = {} if not GRADIO6 else dict(footer_links=[]) | |
| if GRADIO6: | |
| kw["head"] = self.head() | |
| kw["ssr_mode"] = False | |
| return kw | |