Rishi-Jain-27 commited on
Commit
1433b16
·
1 Parent(s): 42bbd85

Updated README, added tracing capabilities, changed size of flowchart, vendored the animation assets so this meets off the grid.

Browse files
.gitignore CHANGED
@@ -5,3 +5,5 @@ venv
5
  __pycache__
6
  .DS_Store
7
  Screenshot 2026-06-07 at 10.46.25 AM.png
 
 
 
5
  __pycache__
6
  .DS_Store
7
  Screenshot 2026-06-07 at 10.46.25 AM.png
8
+ build/node_modules/
9
+ agent_traces.jsonl
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Rishi Jain
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README.md CHANGED
@@ -4,20 +4,196 @@ emoji: 📊
4
  colorFrom: indigo
5
  colorTo: blue
6
  sdk: gradio
7
- sdk_version: 6.16.0
8
  python_version: '3.13'
 
9
  app_file: app.py
10
- pinned: false
11
  license: mit
12
- short_description: Turn code into a readable Mermaid.js flowchart 📊
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  ---
14
 
15
- Add tags for the tracks and badges you want to be considered for to the yaml block at the top of your README, plus a short write-up of the idea and tech.
16
- Post it
17
- Create one social-media post showcasing your app, and link to it from your Space README.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
- Record a demo
20
- Submit a demo video showing your app working — so judges can evaluate it even if GPU or API limits stop a live run.
 
 
 
 
21
 
 
22
 
23
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
4
  colorFrom: indigo
5
  colorTo: blue
6
  sdk: gradio
 
7
  python_version: '3.13'
8
+ sdk_version: 6.16.0
9
  app_file: app.py
10
+ pinned: true
11
  license: mit
12
+ short_description: Turn code into a readable Mermaid.js flowchart 📊!
13
+ tags:
14
+ - build-small-hackathon
15
+ - backyard-ai
16
+ - llama-cpp
17
+ - field-notes
18
+ - sharing-is-caring
19
+ - off-brand
20
+ - off-the-grid
21
+ - code
22
+ - mermaid.js
23
+ - flowchart
24
+ - small-models
25
+ - seq2seq
26
+ - gradio
27
+ - agentic
28
+ ---
29
+
30
+ # 📊 CodeFlow
31
+
32
+ **Paste code → read its logic as a flowchart.** A 30B coder model runs entirely on **CPU via llama.cpp** to translate source code into a clean, animated [Mermaid.js](https://mermaid.js.org/) control-flow diagram — with each node wired back to the exact lines it came from.
33
+
34
+ ### 🔗 Links
35
+
36
+ [🚀 **Live Space**][space] · [▶️ **Demo Video**][video] · [🐦 **Social Post**][social] · [📓 **Field Notes (blog)**][blog] · [🔍 **Agent Traces**][traces]
37
+
38
+ <!-- ╔═══════════════════════════════════════════════════════════════╗
39
+ ║ FILL THESE IN — replace each REPLACE_ME with your real URL. ║
40
+ ╚═══════════════════════════════════════════════════════════════╝ -->
41
+ [space]: REPLACE_ME "Hugging Face Space"
42
+ [video]: REPLACE_ME "Demo video"
43
+ [social]: REPLACE_ME "Social post"
44
+ [blog]: REPLACE_ME "Field notes / blog post"
45
+ [traces]: REPLACE_ME "Agent traces (or https://<your-space>.hf.space/traces)"
46
+
47
  ---
48
 
49
+ ## The Problem
50
+
51
+ Reading unfamiliar code means simulating its control flow in your head — chasing branches, loops, and early returns line by line. That's slow, error-prone, and gets worse the deeper the nesting. Existing "code → diagram" tools are usually rigid AST parsers (brittle, language-locked) or cloud LLM APIs (your code leaves the building).
52
+
53
+ **CodeFlow** turns any snippet into a scannable flowchart you can audit at a glance — generated by a real language model that runs **100% locally**, so nothing is sent to an external API.
54
+
55
+ ## ⚙️ How It Works
56
+
57
+ ```
58
+ Paste code ──▶ Generate ──▶ POST /generate_flowchart (Gradio API)
59
+
60
+ number the source lines + structured system prompt
61
+
62
+ Qwen3-Coder-30B-A3B (llama.cpp · CPU)
63
+
64
+ <thinking> …reasoning… </thinking>
65
+ graph TD … nodes & edges …
66
+ <linemap> A:1 B:2 C:3-4 </linemap>
67
+
68
+ strip reasoning · parse + validate the line-map · sanitize labels
69
+
70
+ { mermaid, linemap } ──▶ append agent_traces.jsonl
71
+
72
+ Mermaid render + "trace-the-path" reveal + node ↔ code linking
73
+ ```
74
+
75
+ 1. You paste code (or pick a pre-rendered example) into the **CodeMirror** editor and hit **Generate**.
76
+ 2. The backend numbers the source lines and sends them with a strict system prompt to **Qwen3-Coder** running on **llama.cpp**.
77
+ 3. The model returns hidden `<thinking>`, the Mermaid `graph`, and a `<linemap>` mapping every node to its source line(s).
78
+ 4. The server strips the reasoning, **validates** the line-map against the source, sanitizes labels for Mermaid, and returns `{ mermaid, linemap }`.
79
+ 5. The frontend renders the diagram with a **trace-the-path reveal** that flows out of a persistent Start node while the canvas scrolls along in real time.
80
+ 6. **Node ↔ code linking:** hover a node to highlight its source lines, click a node to jump-and-edit them, or move your cursor over a line to light up the matching node.
81
+ 7. Every generation is captured as a structured **agent trace** (`/traces`).
82
+
83
+ ## 🧰 Tech Stack
84
+
85
+ | Layer | What it is | Used for |
86
+ |---|---|---|
87
+ | **Model** | [Qwen3-Coder-30B-A3B-Instruct](https://huggingface.co/Qwen) (Mixture-of-Experts) | Code → Mermaid + line-map generation |
88
+ | **Quantization** | [Unsloth](https://huggingface.co/unsloth) Dynamic **UD-Q3_K_XL** GGUF (~3-bit) | Shrinks the 30B model to run on CPU |
89
+ | **Inference** | [`llama-cpp-python`](https://github.com/abetlen/llama-cpp-python) (llama.cpp) | Local CPU inference (`n_ctx=4096`) |
90
+ | **Model fetch** | `huggingface_hub` | Downloads the GGUF on first run |
91
+ | **Server** | [Gradio](https://www.gradio.app/) `gr.Server` + FastAPI | `/generate_flowchart` API, `/` UI, `/traces` |
92
+ | **Frontend** | A single self-contained `frontend.html` (vanilla JS + CSS custom properties) | Editor, diagram, animation, theming |
93
+ | **Editor** | [CodeMirror 6](https://codemirror.net/) — **vendored** bundle (`static/cm.bundle.js`) | Syntax-highlighted code input |
94
+ | **Diagrams** | [Mermaid.js 10](https://mermaid.js.org/) — **vendored** UMD (`static/mermaid.min.js`) | Flowchart rendering |
95
+ | **Animation** | Web Animations API | Trace-the-path reveal + theme crossfade |
96
+ | **Type** | Fraunces · Hanken Grotesk · JetBrains Mono — **vendored** woff2 (`static/fonts/`) | Custom, non-default look |
97
+ | **Assets** | All JS/CSS/fonts bundled into `static/` (no CDN at runtime) | True offline operation |
98
+ | **Observability** | Hand-rolled JSONL agent traces | One trace per generation, served at `/traces` |
99
+ | **Tests** | `smoke-test.sh` (headless Chrome) | 13 build/render checks |
100
+ | **Deploy** | Hugging Face Spaces | Hosting |
101
+
102
+ ## 🔢 Total Parameters
103
+
104
+ CodeFlow is driven by **Qwen3-Coder-30B-A3B-Instruct** — a **Mixture-of-Experts** model with:
105
+
106
+ - **≈ 30.5 billion total parameters**
107
+ - **≈ 3.3 billion active parameters per token** (128 experts, 8 activated)
108
+
109
+ It's served as an **Unsloth Dynamic ~3-bit (UD-Q3_K_XL) GGUF**, which compresses those 30B weights to a CPU-runnable footprint (~13 GB on disk) — letting a 30B-class model generate diagrams **off the grid**, with no GPU and no external API.
110
+
111
+ ## 🏅 Badges (5 / 6)
112
+
113
+ These map to the Space tags above.
114
+
115
+ | Badge | How CodeFlow earns it |
116
+ |---|---|
117
+ | 🔌 **Off the Grid** | **No external API or CDN at runtime — period.** The model runs fully locally (Qwen3-Coder GGUF on CPU via llama.cpp), and *every* frontend asset (Mermaid, CodeMirror, the Gradio client, all fonts) is vendored into `static/`. The Gradio share tunnel is off (`share=False`). The **only** network call in the whole project is the one-time model download at startup. The UI even runs fully offline from `file://`. |
118
+ | 🎨 **Off-Brand** | **Zero default-Gradio look.** A bespoke single-file UI: custom "Pine & Sage" palette (one-word rust fallback), Fraunces + Hanken Grotesk type, a hand-drawn decision-node logo, restyled Mermaid nodes, and a trace-the-path reveal animation — deliberately designed *not* to look templated. |
119
+ | 📓 **Field Notes** | See the [blog post][blog]. |
120
+ | 🤝 **Sharing is Caring** | Open-source under **MIT**, a public Space, plus a [social post][social] sharing the process and learnings. |
121
+ | 🤖 **Agentic** | Every model generation is captured as a structured agent trace (input code, the model's reasoning, output, token usage, latency), downloadable at [`/traces`][traces]. |
122
+
123
+ ## 🎥 Demo
124
+
125
+ [![Watch the demo](REPLACE_ME_thumbnail.png)][video]
126
+
127
+ > ▶️ Click above, or use the [Demo Video][video] link at the top.
128
+
129
+ ## 💻 Run It Locally
130
+
131
+ > First launch downloads the **~13 GB GGUF** from Hugging Face. CPU inference is slow (cold generations can take minutes) — the built-in **examples render instantly** because their diagrams are pre-computed.
132
+
133
+ ```bash
134
+ # 1. Clone
135
+ git clone REPLACE_ME_repo_url CodeFlow
136
+ cd CodeFlow
137
+
138
+ # 2. Create a virtual env
139
+ python -m venv .venv
140
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
141
+
142
+ # 3. Install deps (uses a prebuilt CPU wheel for llama-cpp-python)
143
+ pip install -r requirements.txt
144
+
145
+ # 4. Run — opens a local Gradio URL
146
+ python app.py
147
+ ```
148
+
149
+ Then open the printed URL. **Preview the UI without the model** by opening `frontend.html` directly in a browser (`file://`) — fully offline, since all assets are vendored in `static/`; the example presets render their diagrams instantly.
150
+
151
+ > **Rebuilding the vendored bundles** (optional): the CodeMirror + Gradio-client bundles in `static/` are produced by `build/build.sh` (needs Node). Mermaid and the fonts are downloaded into `static/` as well. You never need this to *run* the app — only to regenerate the bundles.
152
+
153
+ **Endpoints:** `/` (UI) · `/generate_flowchart` (API) · `/traces` (download all agent traces as JSONL).
154
+
155
+ ## 🗂️ Repository Structure
156
+
157
+ ```
158
+ CodeFlow/
159
+ ├── app.py # Gradio + FastAPI server: loads the model and exposes
160
+ │ # /generate_flowchart (API), / (UI), /static, /traces
161
+ ├── frontend.html # Self-contained UI — CodeMirror editor, Mermaid render,
162
+ │ # trace-the-path animation, node↔code linking, theming
163
+ ├── static/ # Vendored frontend assets — NO CDN at runtime
164
+ │ ├── mermaid.min.js # Mermaid (UMD, ~3.2 MB)
165
+ │ ├── cm.bundle.js # CodeMirror 6 (single IIFE bundle)
166
+ │ ├── gradio-client.js # @gradio/client (IIFE bundle)
167
+ │ ├── fonts.css # @font-face → local woff2
168
+ │ └── fonts/ # Fraunces · Hanken Grotesk · JetBrains Mono (woff2)
169
+ ├── build/ # Reproducible bundle build (Node) — build.sh + entry files
170
+ ├── requirements.txt # Python deps (CPU llama-cpp-python wheel, gradio, hub)
171
+ ├── smoke-test.sh # Headless-Chrome smoke test (13 checks)
172
+ ├── notes-for-blog.md # Field Notes — the full build log
173
+ ├── README.md # You are here
174
+ ├── LICENSE # MIT
175
+ └── agent_traces.jsonl # (created at runtime) one JSON line per generation
176
+ ```
177
+
178
+ ## ⚠️ Limitations
179
+
180
+ - **CPU inference is slow.** A 30B model on CPU means cold generations can take minutes; the demo leans on pre-rendered examples for instant feedback.
181
+ - **3-bit quantization** trades some fidelity for the ability to run a 30B model at all — occasional imperfect diagrams.
182
+ - **4096-token context** — very large files won't fit; works best on functions/snippets.
183
+ - **Line-map depends on the model.** The `<linemap>` is LLM-generated; the server validates and drops bad entries, so node↔code links can be partial on tricky code.
184
+ - **Paraphrased labels.** Nodes describe logic in plain words (no raw code), so they read cleanly but aren't verbatim.
185
+ - **Mermaid parse failures** on unusual syntax are possible (the raw output is shown so nothing is lost).
186
+ - **Ephemeral traces on Spaces.** `agent_traces.jsonl` lives on the runtime filesystem and resets on restart/rebuild — download it before then.
187
+
188
+ ## 🙏 Credits
189
 
190
+ - **Model:** [Qwen3-Coder](https://huggingface.co/Qwen) (Qwen Team, Alibaba) — GGUF quant by [Unsloth](https://huggingface.co/unsloth).
191
+ - **Inference:** [llama.cpp](https://github.com/ggml-org/llama.cpp) via [`llama-cpp-python`](https://github.com/abetlen/llama-cpp-python) (Andrei Betlen).
192
+ - **App framework:** [Gradio](https://www.gradio.app/) (Hugging Face).
193
+ - **Diagrams:** [Mermaid.js](https://mermaid.js.org/) · **Editor:** [CodeMirror](https://codemirror.net/).
194
+ - **Type:** Fraunces, Hanken Grotesk, JetBrains Mono ([Google Fonts](https://fonts.google.com/), SIL OFL).
195
+ - **Built for** the Build Small Hackathon.
196
 
197
+ ## 📄 License
198
 
199
+ Released under the **MIT License** see [`LICENSE`](LICENSE). © 2026 Rishi Jain.
app.py CHANGED
@@ -3,11 +3,14 @@ from huggingface_hub import hf_hub_download
3
  from llama_cpp import Llama
4
  import gradio as gr
5
  from gradio import Server
6
- from fastapi.responses import HTMLResponse # serve the custom frontend from a route
 
7
  from typing import Any, cast # to resolve PyLance freaking out over llama-cpp-python in the generate_flowchart function
8
  from textwrap import dedent
9
  from pathlib import Path # load the custom frontend from disk
10
  import re # remove thinking tag from response
 
 
11
 
12
  # ----- Get Model ----- #
13
  # Download Q4_K_M GGUF file from the repo
@@ -26,6 +29,20 @@ llm = Llama(
26
  # ----- Init App ----- #
27
  app = gr.Server(title="Code-to-Flowchart Generator")
28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  # ----- Functions ----- #
30
 
31
  # This is a cleaning function to resolve common syntax errors.
@@ -138,6 +155,7 @@ def generate_flowchart(src_code: str) -> dict:
138
  llm.reset()
139
 
140
  # Casting else PyLance gets mad
 
141
  response = cast(Any, llm.create_chat_completion(
142
  messages=[
143
  {"role": "system", "content": system_prompt},
@@ -147,11 +165,15 @@ def generate_flowchart(src_code: str) -> dict:
147
  max_tokens=1024,
148
  stream=False
149
  ))
 
150
 
151
- content = response["choices"][0]["message"]["content"]
 
152
 
153
- # remove the thinking tags from the response
154
- content = re.sub(r'<thinking>.*?</thinking>', '', content, flags=re.DOTALL)
 
 
155
 
156
  # Extract + strip the node→line map, then validate it against the source length
157
  linemap: dict = {}
@@ -163,6 +185,25 @@ def generate_flowchart(src_code: str) -> dict:
163
  # Quote-wrap each node label and escape any leaked code characters
164
  mermaid = quote_labels(content).strip() # and remove excess whitespace
165
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  return {"mermaid": mermaid, "linemap": linemap}
167
 
168
  # ----- Custom Frontend ----- #
@@ -176,4 +217,27 @@ index_html = (Path(__file__).parent / "frontend.html").read_text(encoding="utf-8
176
  def index():
177
  return HTMLResponse(index_html)
178
 
179
- app.launch(share=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  from llama_cpp import Llama
4
  import gradio as gr
5
  from gradio import Server
6
+ from fastapi.responses import HTMLResponse, PlainTextResponse, FileResponse # frontend + traces + vendored static assets
7
+ import mimetypes
8
  from typing import Any, cast # to resolve PyLance freaking out over llama-cpp-python in the generate_flowchart function
9
  from textwrap import dedent
10
  from pathlib import Path # load the custom frontend from disk
11
  import re # remove thinking tag from response
12
+ import json, time, uuid # agent-trace logging
13
+ from datetime import datetime, timezone
14
 
15
  # ----- Get Model ----- #
16
  # Download Q4_K_M GGUF file from the repo
 
29
  # ----- Init App ----- #
30
  app = gr.Server(title="Code-to-Flowchart Generator")
31
 
32
+ # ----- Agent traces ----- #
33
+ # Each generation appends one JSON line capturing the full LLM call (input code,
34
+ # the model's reasoning, output Mermaid + linemap, token usage, latency).
35
+ # Download the whole log from the running app at /traces .
36
+ MODEL_NAME = "unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF:UD-Q3_K_XL"
37
+ TRACE_PATH = Path(__file__).parent / "agent_traces.jsonl"
38
+
39
+ def write_trace(record: dict) -> None:
40
+ try:
41
+ with open(TRACE_PATH, "a", encoding="utf-8") as f:
42
+ f.write(json.dumps(record, ensure_ascii=False) + "\n")
43
+ except Exception:
44
+ pass # tracing must never break generation
45
+
46
  # ----- Functions ----- #
47
 
48
  # This is a cleaning function to resolve common syntax errors.
 
155
  llm.reset()
156
 
157
  # Casting else PyLance gets mad
158
+ t0 = time.perf_counter()
159
  response = cast(Any, llm.create_chat_completion(
160
  messages=[
161
  {"role": "system", "content": system_prompt},
 
165
  max_tokens=1024,
166
  stream=False
167
  ))
168
+ latency_ms = round((time.perf_counter() - t0) * 1000)
169
 
170
+ raw = response["choices"][0]["message"]["content"]
171
+ usage = response.get("usage", {}) or {}
172
 
173
+ # Capture the model's hidden reasoning for the trace, then strip the tags
174
+ think = re.search(r'<thinking>(.*?)</thinking>', raw, flags=re.DOTALL)
175
+ reasoning = think.group(1).strip() if think else ""
176
+ content = re.sub(r'<thinking>.*?</thinking>', '', raw, flags=re.DOTALL)
177
 
178
  # Extract + strip the node→line map, then validate it against the source length
179
  linemap: dict = {}
 
185
  # Quote-wrap each node label and escape any leaked code characters
186
  mermaid = quote_labels(content).strip() # and remove excess whitespace
187
 
188
+ # ----- Agent trace (append-only JSONL; downloadable at /traces) -----
189
+ write_trace({
190
+ "id": uuid.uuid4().hex,
191
+ "ts": datetime.now(timezone.utc).isoformat(),
192
+ "event": "generate_flowchart",
193
+ "model": MODEL_NAME,
194
+ "params": {"temperature": 0.1, "max_tokens": 1024, "n_ctx": 4096},
195
+ "input": {"src_code": src_code, "num_lines": num_lines},
196
+ "reasoning": reasoning,
197
+ "output": {"raw": raw, "mermaid": mermaid, "linemap": linemap},
198
+ "usage": {
199
+ "prompt_tokens": usage.get("prompt_tokens"),
200
+ "completion_tokens": usage.get("completion_tokens"),
201
+ "total_tokens": usage.get("total_tokens"),
202
+ },
203
+ "latency_ms": latency_ms,
204
+ "status": "ok",
205
+ })
206
+
207
  return {"mermaid": mermaid, "linemap": linemap}
208
 
209
  # ----- Custom Frontend ----- #
 
217
  def index():
218
  return HTMLResponse(index_html)
219
 
220
+ # Serve the vendored frontend assets (Mermaid, CodeMirror bundle, Gradio client,
221
+ # fonts) locally so the app needs NO external CDN/API at runtime.
222
+ STATIC_DIR = (Path(__file__).parent / "static").resolve()
223
+ mimetypes.add_type("text/javascript", ".js")
224
+ mimetypes.add_type("font/woff2", ".woff2")
225
+
226
+ @app.get("/static/{fname:path}")
227
+ def static_files(fname: str):
228
+ fp = (STATIC_DIR / fname).resolve()
229
+ # contain to STATIC_DIR (no path traversal) and require a real file
230
+ if not str(fp).startswith(str(STATIC_DIR) + "/") or not fp.is_file():
231
+ return PlainTextResponse("not found", status_code=404)
232
+ mt, _ = mimetypes.guess_type(str(fp))
233
+ return FileResponse(fp, media_type=mt or "application/octet-stream")
234
+
235
+ # Download every agent trace collected this run (one JSON object per line).
236
+ # curl https://<your-space>/traces > agent_traces.jsonl
237
+ @app.get("/traces")
238
+ def traces():
239
+ text = TRACE_PATH.read_text(encoding="utf-8") if TRACE_PATH.exists() else ""
240
+ return PlainTextResponse(text, media_type="application/x-ndjson",
241
+ headers={"Content-Disposition": 'attachment; filename="agent_traces.jsonl"'})
242
+
243
+ app.launch(share=False) # no external gradio.live tunnel — fully self-hosted
build/build.sh ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ # Rebuild the vendored frontend bundles in ../static/ from scratch.
3
+ # Requires Node. Run from this build/ directory: ./build.sh
4
+ set -euo pipefail
5
+ cd "$(dirname "$0")"
6
+ npm install --no-fund --no-audit \
7
+ @codemirror/state@6 @codemirror/view@6 @codemirror/commands@6 @codemirror/language@6 \
8
+ @codemirror/lang-python@6 @codemirror/lang-javascript@6 @codemirror/lang-java@6 @codemirror/lang-cpp@6 \
9
+ @lezer/highlight@1 @gradio/client@1 esbuild
10
+ EB=./node_modules/.bin/esbuild
11
+ "$EB" cm-entry.mjs --bundle --format=iife --global-name=CM6 --minify --outfile=../static/cm.bundle.js
12
+ "$EB" gradio-entry.mjs --bundle --format=iife --global-name=GradioClient --minify --platform=browser \
13
+ --external:fs/promises --external:path --external:fs --external:url --external:stream \
14
+ --external:crypto --external:http --external:https --external:os --external:child_process \
15
+ --outfile=../static/gradio-client.js
16
+ curl -sL "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js" -o ../static/mermaid.min.js
17
+ echo "Rebuilt static/{cm.bundle.js, gradio-client.js, mermaid.min.js}. (Fonts are vendored separately.)"
build/cm-entry.mjs ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ export { EditorState, Compartment, StateField, StateEffect } from "@codemirror/state";
2
+ export { EditorView, keymap, placeholder, lineNumbers, highlightActiveLine,
3
+ highlightActiveLineGutter, drawSelection, dropCursor, Decoration } from "@codemirror/view";
4
+ export { history, defaultKeymap, historyKeymap, indentWithTab } from "@codemirror/commands";
5
+ export { indentOnInput, bracketMatching, syntaxHighlighting, HighlightStyle } from "@codemirror/language";
6
+ export { tags } from "@lezer/highlight";
7
+ export { python } from "@codemirror/lang-python";
8
+ export { javascript } from "@codemirror/lang-javascript";
9
+ export { java } from "@codemirror/lang-java";
10
+ export { cpp } from "@codemirror/lang-cpp";
build/gradio-entry.mjs ADDED
@@ -0,0 +1 @@
 
 
1
+ export { Client } from "@gradio/client";
build/package.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"name":"cf-vendor-build","private":true,"type":"module","dependencies":{"@codemirror/commands":"^6.10.3","@codemirror/lang-cpp":"^6.0.3","@codemirror/lang-java":"^6.0.2","@codemirror/lang-javascript":"^6.2.5","@codemirror/lang-python":"^6.2.1","@codemirror/language":"^6.12.3","@codemirror/state":"^6.6.0","@codemirror/view":"^6.43.1","@gradio/client":"^1.19.1","@lezer/highlight":"^1.2.3","esbuild":"^0.28.0"}}
frontend.html CHANGED
@@ -4,9 +4,8 @@
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>CodeFlow — Code to Flowchart</title>
7
- <link rel="preconnect" href="https://fonts.googleapis.com">
8
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
- <link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,500;9..144,600;9..144,700&family=Hanken+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
10
  <style>
11
  /* ============================================================
12
  PINE & SAGE — the CodeFlow theme (green + light).
@@ -500,13 +499,14 @@
500
  textarea::-webkit-scrollbar-thumb:hover { background: var(--scroll-hi); }
501
  #flowchart-target::-webkit-scrollbar-corner,
502
  textarea::-webkit-scrollbar-corner { background: var(--bg-inset); }
503
- /* Render the SVG at full panel width and let long charts grow + scroll
504
- instead of being shrunk to fit (which made them hard to read). */
 
505
  #flowchart-target svg {
506
- width: calc(100% * var(--zoom, 1)) !important; /* zoom scales width; height follows */
507
  max-width: none !important; /* override Mermaid's inline max-width so zoom can grow it */
508
  height: auto !important;
509
- min-height: 360px;
510
  flex: 0 0 auto;
511
  }
512
  /* Empty state: the lone Start anchor renders small + centred — not stretched
@@ -711,10 +711,17 @@
711
  </div>
712
  </div>
713
 
 
 
 
 
 
 
 
714
  <script type="module">
715
- import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
716
- // CodeMirror is imported *dynamically* inside initEditor() (not at the top
717
- // level) so that any CM/CDN failure is contained to the editor and can't
718
  // take down the rest of the page (examples, Generate). See initEditor().
719
 
720
  // Per-palette, per-theme Mermaid palettes. Keyed [PALETTE][theme] so the
@@ -851,27 +858,18 @@ print(total)`,
851
  a working textarea instead of a broken page. getCode()/setCode() below
852
  hide which input is live, so the preset + submit logic never branches. */
853
 
854
- // Layered ?deps= chain so every package shares ONE @codemirror/state +
855
- // @codemirror/view + @lezer/highlight instance otherwise CM's facets
856
- // don't match across packages and it throws, and token tags from the
857
- // grammars don't match our HighlightStyle so colors never apply. We pin
858
- // the @6 / @1 majors (not micro-versions) so esm.sh resolves one mutually
859
- // compatible current set. (Verified in a headless Chrome harness.)
860
- const D = {
861
- state: "@codemirror/state@6",
862
- view: "@codemirror/state@6,@codemirror/view@6",
863
- lang: "@codemirror/state@6,@codemirror/view@6,@codemirror/language@6,@lezer/highlight@1",
864
- };
865
-
866
- // Lazy grammar loaders — only the picked language's parser is fetched.
867
  const LANG_LOADERS = {
868
- python: () => import("https://esm.sh/@codemirror/lang-python@6?deps=" + D.lang).then(m => m.python()),
869
- javascript: () => import("https://esm.sh/@codemirror/lang-javascript@6?deps=" + D.lang).then(m => m.javascript()),
870
- java: () => import("https://esm.sh/@codemirror/lang-java@6?deps=" + D.lang).then(m => m.java()),
871
- cpp: () => import("https://esm.sh/@codemirror/lang-cpp@6?deps=" + D.lang).then(m => m.cpp()),
872
  };
873
  async function makeLangExt(name) {
874
- try { return await LANG_LOADERS[name](); } catch { return []; }
875
  }
876
 
877
  let cmView = null;
@@ -911,24 +909,17 @@ print(total)`,
911
 
912
  async function initEditor() {
913
  try {
914
- // Dynamic imports: contained here so a CM/CDN failure can't kill
915
- // the rest of the page (mermaid, examples, Generate all still run).
916
- // We assemble our own editor setup from the individual packages
917
- // rather than the `codemirror` meta-package, which only exposes a
918
- // `default` export under ?deps= (so basicSetup comes back undefined).
919
- const [stateMod, viewMod, commandsMod, languageMod, lezerMod] = await Promise.all([
920
- import("https://esm.sh/@codemirror/state@6"),
921
- import("https://esm.sh/@codemirror/view@6?deps=" + D.state),
922
- import("https://esm.sh/@codemirror/commands@6?deps=" + D.view),
923
- import("https://esm.sh/@codemirror/language@6?deps=" + D.lang),
924
- import("https://esm.sh/@lezer/highlight@1"),
925
- ]);
926
- const { EditorState, Compartment, StateField, StateEffect } = stateMod;
927
  const { EditorView, keymap, placeholder, lineNumbers, highlightActiveLine,
928
- highlightActiveLineGutter, drawSelection, dropCursor, Decoration } = viewMod;
929
- const { history, defaultKeymap, historyKeymap, indentWithTab } = commandsMod;
930
- const { indentOnInput, bracketMatching, syntaxHighlighting, HighlightStyle } = languageMod;
931
- const tg = lezerMod.tags;
932
 
933
  // Lean "basic setup" — line numbers, active line, history/undo,
934
  // indent-on-input, bracket matching. (No autocomplete/search/lint;
@@ -1424,13 +1415,13 @@ print(total)`,
1424
  }
1425
 
1426
  /* ----- Live generation (server only) -----
1427
- The Gradio client is imported lazily on first click so this page
1428
- still loads and the presets still work when opened directly as a
1429
- file:// preview with no backend running. */
1430
  let clientPromise = null;
1431
  async function getClient() {
1432
  if (!clientPromise) {
1433
- const { Client } = await import("https://cdn.jsdelivr.net/npm/@gradio/client@1/dist/index.min.js");
1434
  clientPromise = Client.connect(window.location.origin);
1435
  }
1436
  return clientPromise;
 
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>CodeFlow — Code to Flowchart</title>
7
+ <!-- All assets are vendored locally (see static/) — no external CDN/API at runtime. -->
8
+ <link rel="stylesheet" href="static/fonts.css">
 
9
  <style>
10
  /* ============================================================
11
  PINE & SAGE — the CodeFlow theme (green + light).
 
499
  textarea::-webkit-scrollbar-thumb:hover { background: var(--scroll-hi); }
500
  #flowchart-target::-webkit-scrollbar-corner,
501
  textarea::-webkit-scrollbar-corner { background: var(--bg-inset); }
502
+ /* Render the SVG a bit under full panel width (centred) so it reads at a
503
+ comfortable size; long charts still grow + scroll instead of shrinking.
504
+ --fit is the default "fit" scale; the zoom control multiplies it. */
505
  #flowchart-target svg {
506
+ width: calc(72% * var(--zoom, 1)) !important; /* fit-to-width, slightly inset; zoom scales it */
507
  max-width: none !important; /* override Mermaid's inline max-width so zoom can grow it */
508
  height: auto !important;
509
+ min-height: 320px;
510
  flex: 0 0 auto;
511
  }
512
  /* Empty state: the lone Start anchor renders small + centred — not stretched
 
711
  </div>
712
  </div>
713
 
714
+ <!-- Vendored libraries (classic scripts → globals): Mermaid (window.mermaid),
715
+ CodeMirror bundle (window.CM6), Gradio client (window.GradioClient).
716
+ Loaded before the module below so the module can use the globals. -->
717
+ <script src="static/mermaid.min.js"></script>
718
+ <script src="static/cm.bundle.js"></script>
719
+ <script src="static/gradio-client.js"></script>
720
+
721
  <script type="module">
722
+ // `mermaid` is the global from static/mermaid.min.js (vendored, no CDN).
723
+ // CodeMirror is read from the window.CM6 global inside initEditor() kept in
724
+ // a try/catch so any editor failure is contained and falls back to a textarea.
725
  // take down the rest of the page (examples, Generate). See initEditor().
726
 
727
  // Per-palette, per-theme Mermaid palettes. Keyed [PALETTE][theme] so the
 
858
  a working textarea instead of a broken page. getCode()/setCode() below
859
  hide which input is live, so the preset + submit logic never branches. */
860
 
861
+ // CodeMirror is vendored as a single IIFE bundle (static/cm.bundle.js → the
862
+ // CM6 global), so every package shares ONE @codemirror/state/view/@lezer
863
+ // instance by construction no ?deps= juggling, no CDN. Grammars come from
864
+ // the same bundle (CM6.python / .javascript / .java / .cpp).
 
 
 
 
 
 
 
 
 
865
  const LANG_LOADERS = {
866
+ python: () => CM6.python(),
867
+ javascript: () => CM6.javascript(),
868
+ java: () => CM6.java(),
869
+ cpp: () => CM6.cpp(),
870
  };
871
  async function makeLangExt(name) {
872
+ try { return (LANG_LOADERS[name] || LANG_LOADERS.python)(); } catch { return []; }
873
  }
874
 
875
  let cmView = null;
 
909
 
910
  async function initEditor() {
911
  try {
912
+ // Everything comes from the vendored CM6 global (static/cm.bundle.js).
913
+ // Wrapped in try/catch so any editor failure is contained to the
914
+ // editor and falls back to the plain textarea — the rest of the page
915
+ // (mermaid, examples, Generate) keeps working.
916
+ if (!window.CM6) throw new Error('CodeMirror bundle not loaded');
917
+ const { EditorState, Compartment, StateField, StateEffect } = CM6;
 
 
 
 
 
 
 
918
  const { EditorView, keymap, placeholder, lineNumbers, highlightActiveLine,
919
+ highlightActiveLineGutter, drawSelection, dropCursor, Decoration } = CM6;
920
+ const { history, defaultKeymap, historyKeymap, indentWithTab } = CM6;
921
+ const { indentOnInput, bracketMatching, syntaxHighlighting, HighlightStyle } = CM6;
922
+ const tg = CM6.tags;
923
 
924
  // Lean "basic setup" — line numbers, active line, history/undo,
925
  // indent-on-input, bracket matching. (No autocomplete/search/lint;
 
1415
  }
1416
 
1417
  /* ----- Live generation (server only) -----
1418
+ Uses the vendored Gradio client (static/gradio-client.js the
1419
+ GradioClient global). Connected lazily on first Generate; presets still
1420
+ render with no backend. */
1421
  let clientPromise = null;
1422
  async function getClient() {
1423
  if (!clientPromise) {
1424
+ const { Client } = window.GradioClient;
1425
  clientPromise = Client.connect(window.location.origin);
1426
  }
1427
  return clientPromise;
static/cm.bundle.js ADDED
The diff for this file is too large to render. See raw diff
 
static/fonts.css ADDED
@@ -0,0 +1,333 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* vietnamese */
2
+ @font-face {
3
+ font-family: 'Fraunces';
4
+ font-style: normal;
5
+ font-weight: 500;
6
+ font-display: swap;
7
+ src: url(fonts/6NU78FyLNQOQZAnv9bYEvDiIdE9Ea92uemAk_WBq8U_9v0c2Wa0KxCBTeP2Xz5fU8w.woff2) format('woff2');
8
+ unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
9
+ }
10
+ /* latin-ext */
11
+ @font-face {
12
+ font-family: 'Fraunces';
13
+ font-style: normal;
14
+ font-weight: 500;
15
+ font-display: swap;
16
+ src: url(fonts/6NU78FyLNQOQZAnv9bYEvDiIdE9Ea92uemAk_WBq8U_9v0c2Wa0KxCFTeP2Xz5fU8w.woff2) format('woff2');
17
+ unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
18
+ }
19
+ /* latin */
20
+ @font-face {
21
+ font-family: 'Fraunces';
22
+ font-style: normal;
23
+ font-weight: 500;
24
+ font-display: swap;
25
+ src: url(fonts/6NU78FyLNQOQZAnv9bYEvDiIdE9Ea92uemAk_WBq8U_9v0c2Wa0KxC9TeP2Xz5c.woff2) format('woff2');
26
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
27
+ }
28
+ /* vietnamese */
29
+ @font-face {
30
+ font-family: 'Fraunces';
31
+ font-style: normal;
32
+ font-weight: 600;
33
+ font-display: swap;
34
+ src: url(fonts/6NU78FyLNQOQZAnv9bYEvDiIdE9Ea92uemAk_WBq8U_9v0c2Wa0KxCBTeP2Xz5fU8w.woff2) format('woff2');
35
+ unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
36
+ }
37
+ /* latin-ext */
38
+ @font-face {
39
+ font-family: 'Fraunces';
40
+ font-style: normal;
41
+ font-weight: 600;
42
+ font-display: swap;
43
+ src: url(fonts/6NU78FyLNQOQZAnv9bYEvDiIdE9Ea92uemAk_WBq8U_9v0c2Wa0KxCFTeP2Xz5fU8w.woff2) format('woff2');
44
+ unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
45
+ }
46
+ /* latin */
47
+ @font-face {
48
+ font-family: 'Fraunces';
49
+ font-style: normal;
50
+ font-weight: 600;
51
+ font-display: swap;
52
+ src: url(fonts/6NU78FyLNQOQZAnv9bYEvDiIdE9Ea92uemAk_WBq8U_9v0c2Wa0KxC9TeP2Xz5c.woff2) format('woff2');
53
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
54
+ }
55
+ /* vietnamese */
56
+ @font-face {
57
+ font-family: 'Fraunces';
58
+ font-style: normal;
59
+ font-weight: 700;
60
+ font-display: swap;
61
+ src: url(fonts/6NU78FyLNQOQZAnv9bYEvDiIdE9Ea92uemAk_WBq8U_9v0c2Wa0KxCBTeP2Xz5fU8w.woff2) format('woff2');
62
+ unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
63
+ }
64
+ /* latin-ext */
65
+ @font-face {
66
+ font-family: 'Fraunces';
67
+ font-style: normal;
68
+ font-weight: 700;
69
+ font-display: swap;
70
+ src: url(fonts/6NU78FyLNQOQZAnv9bYEvDiIdE9Ea92uemAk_WBq8U_9v0c2Wa0KxCFTeP2Xz5fU8w.woff2) format('woff2');
71
+ unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
72
+ }
73
+ /* latin */
74
+ @font-face {
75
+ font-family: 'Fraunces';
76
+ font-style: normal;
77
+ font-weight: 700;
78
+ font-display: swap;
79
+ src: url(fonts/6NU78FyLNQOQZAnv9bYEvDiIdE9Ea92uemAk_WBq8U_9v0c2Wa0KxC9TeP2Xz5c.woff2) format('woff2');
80
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
81
+ }
82
+ /* cyrillic-ext */
83
+ @font-face {
84
+ font-family: 'Hanken Grotesk';
85
+ font-style: normal;
86
+ font-weight: 400;
87
+ font-display: swap;
88
+ src: url(fonts/ieVn2YZDLWuGJpnzaiwFXS9tYtpQ59CxCis4UvI.woff2) format('woff2');
89
+ unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
90
+ }
91
+ /* vietnamese */
92
+ @font-face {
93
+ font-family: 'Hanken Grotesk';
94
+ font-style: normal;
95
+ font-weight: 400;
96
+ font-display: swap;
97
+ src: url(fonts/ieVn2YZDLWuGJpnzaiwFXS9tYtpS59CxCis4UvI.woff2) format('woff2');
98
+ unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
99
+ }
100
+ /* latin-ext */
101
+ @font-face {
102
+ font-family: 'Hanken Grotesk';
103
+ font-style: normal;
104
+ font-weight: 400;
105
+ font-display: swap;
106
+ src: url(fonts/ieVn2YZDLWuGJpnzaiwFXS9tYtpT59CxCis4UvI.woff2) format('woff2');
107
+ unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
108
+ }
109
+ /* latin */
110
+ @font-face {
111
+ font-family: 'Hanken Grotesk';
112
+ font-style: normal;
113
+ font-weight: 400;
114
+ font-display: swap;
115
+ src: url(fonts/ieVn2YZDLWuGJpnzaiwFXS9tYtpd59CxCis4.woff2) format('woff2');
116
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
117
+ }
118
+ /* cyrillic-ext */
119
+ @font-face {
120
+ font-family: 'Hanken Grotesk';
121
+ font-style: normal;
122
+ font-weight: 500;
123
+ font-display: swap;
124
+ src: url(fonts/ieVn2YZDLWuGJpnzaiwFXS9tYtpQ59CxCis4UvI.woff2) format('woff2');
125
+ unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
126
+ }
127
+ /* vietnamese */
128
+ @font-face {
129
+ font-family: 'Hanken Grotesk';
130
+ font-style: normal;
131
+ font-weight: 500;
132
+ font-display: swap;
133
+ src: url(fonts/ieVn2YZDLWuGJpnzaiwFXS9tYtpS59CxCis4UvI.woff2) format('woff2');
134
+ unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
135
+ }
136
+ /* latin-ext */
137
+ @font-face {
138
+ font-family: 'Hanken Grotesk';
139
+ font-style: normal;
140
+ font-weight: 500;
141
+ font-display: swap;
142
+ src: url(fonts/ieVn2YZDLWuGJpnzaiwFXS9tYtpT59CxCis4UvI.woff2) format('woff2');
143
+ unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
144
+ }
145
+ /* latin */
146
+ @font-face {
147
+ font-family: 'Hanken Grotesk';
148
+ font-style: normal;
149
+ font-weight: 500;
150
+ font-display: swap;
151
+ src: url(fonts/ieVn2YZDLWuGJpnzaiwFXS9tYtpd59CxCis4.woff2) format('woff2');
152
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
153
+ }
154
+ /* cyrillic-ext */
155
+ @font-face {
156
+ font-family: 'Hanken Grotesk';
157
+ font-style: normal;
158
+ font-weight: 600;
159
+ font-display: swap;
160
+ src: url(fonts/ieVn2YZDLWuGJpnzaiwFXS9tYtpQ59CxCis4UvI.woff2) format('woff2');
161
+ unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
162
+ }
163
+ /* vietnamese */
164
+ @font-face {
165
+ font-family: 'Hanken Grotesk';
166
+ font-style: normal;
167
+ font-weight: 600;
168
+ font-display: swap;
169
+ src: url(fonts/ieVn2YZDLWuGJpnzaiwFXS9tYtpS59CxCis4UvI.woff2) format('woff2');
170
+ unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
171
+ }
172
+ /* latin-ext */
173
+ @font-face {
174
+ font-family: 'Hanken Grotesk';
175
+ font-style: normal;
176
+ font-weight: 600;
177
+ font-display: swap;
178
+ src: url(fonts/ieVn2YZDLWuGJpnzaiwFXS9tYtpT59CxCis4UvI.woff2) format('woff2');
179
+ unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
180
+ }
181
+ /* latin */
182
+ @font-face {
183
+ font-family: 'Hanken Grotesk';
184
+ font-style: normal;
185
+ font-weight: 600;
186
+ font-display: swap;
187
+ src: url(fonts/ieVn2YZDLWuGJpnzaiwFXS9tYtpd59CxCis4.woff2) format('woff2');
188
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
189
+ }
190
+ /* cyrillic-ext */
191
+ @font-face {
192
+ font-family: 'Hanken Grotesk';
193
+ font-style: normal;
194
+ font-weight: 700;
195
+ font-display: swap;
196
+ src: url(fonts/ieVn2YZDLWuGJpnzaiwFXS9tYtpQ59CxCis4UvI.woff2) format('woff2');
197
+ unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
198
+ }
199
+ /* vietnamese */
200
+ @font-face {
201
+ font-family: 'Hanken Grotesk';
202
+ font-style: normal;
203
+ font-weight: 700;
204
+ font-display: swap;
205
+ src: url(fonts/ieVn2YZDLWuGJpnzaiwFXS9tYtpS59CxCis4UvI.woff2) format('woff2');
206
+ unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
207
+ }
208
+ /* latin-ext */
209
+ @font-face {
210
+ font-family: 'Hanken Grotesk';
211
+ font-style: normal;
212
+ font-weight: 700;
213
+ font-display: swap;
214
+ src: url(fonts/ieVn2YZDLWuGJpnzaiwFXS9tYtpT59CxCis4UvI.woff2) format('woff2');
215
+ unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
216
+ }
217
+ /* latin */
218
+ @font-face {
219
+ font-family: 'Hanken Grotesk';
220
+ font-style: normal;
221
+ font-weight: 700;
222
+ font-display: swap;
223
+ src: url(fonts/ieVn2YZDLWuGJpnzaiwFXS9tYtpd59CxCis4.woff2) format('woff2');
224
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
225
+ }
226
+ /* cyrillic-ext */
227
+ @font-face {
228
+ font-family: 'JetBrains Mono';
229
+ font-style: normal;
230
+ font-weight: 400;
231
+ font-display: swap;
232
+ src: url(fonts/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPx3cwgknk-6nFg.woff2) format('woff2');
233
+ unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
234
+ }
235
+ /* cyrillic */
236
+ @font-face {
237
+ font-family: 'JetBrains Mono';
238
+ font-style: normal;
239
+ font-weight: 400;
240
+ font-display: swap;
241
+ src: url(fonts/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPxTcwgknk-6nFg.woff2) format('woff2');
242
+ unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
243
+ }
244
+ /* greek */
245
+ @font-face {
246
+ font-family: 'JetBrains Mono';
247
+ font-style: normal;
248
+ font-weight: 400;
249
+ font-display: swap;
250
+ src: url(fonts/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPxPcwgknk-6nFg.woff2) format('woff2');
251
+ unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
252
+ }
253
+ /* vietnamese */
254
+ @font-face {
255
+ font-family: 'JetBrains Mono';
256
+ font-style: normal;
257
+ font-weight: 400;
258
+ font-display: swap;
259
+ src: url(fonts/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPx_cwgknk-6nFg.woff2) format('woff2');
260
+ unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
261
+ }
262
+ /* latin-ext */
263
+ @font-face {
264
+ font-family: 'JetBrains Mono';
265
+ font-style: normal;
266
+ font-weight: 400;
267
+ font-display: swap;
268
+ src: url(fonts/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPx7cwgknk-6nFg.woff2) format('woff2');
269
+ unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
270
+ }
271
+ /* latin */
272
+ @font-face {
273
+ font-family: 'JetBrains Mono';
274
+ font-style: normal;
275
+ font-weight: 400;
276
+ font-display: swap;
277
+ src: url(fonts/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPxDcwgknk-4.woff2) format('woff2');
278
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
279
+ }
280
+ /* cyrillic-ext */
281
+ @font-face {
282
+ font-family: 'JetBrains Mono';
283
+ font-style: normal;
284
+ font-weight: 500;
285
+ font-display: swap;
286
+ src: url(fonts/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPx3cwgknk-6nFg.woff2) format('woff2');
287
+ unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
288
+ }
289
+ /* cyrillic */
290
+ @font-face {
291
+ font-family: 'JetBrains Mono';
292
+ font-style: normal;
293
+ font-weight: 500;
294
+ font-display: swap;
295
+ src: url(fonts/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPxTcwgknk-6nFg.woff2) format('woff2');
296
+ unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
297
+ }
298
+ /* greek */
299
+ @font-face {
300
+ font-family: 'JetBrains Mono';
301
+ font-style: normal;
302
+ font-weight: 500;
303
+ font-display: swap;
304
+ src: url(fonts/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPxPcwgknk-6nFg.woff2) format('woff2');
305
+ unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
306
+ }
307
+ /* vietnamese */
308
+ @font-face {
309
+ font-family: 'JetBrains Mono';
310
+ font-style: normal;
311
+ font-weight: 500;
312
+ font-display: swap;
313
+ src: url(fonts/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPx_cwgknk-6nFg.woff2) format('woff2');
314
+ unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
315
+ }
316
+ /* latin-ext */
317
+ @font-face {
318
+ font-family: 'JetBrains Mono';
319
+ font-style: normal;
320
+ font-weight: 500;
321
+ font-display: swap;
322
+ src: url(fonts/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPx7cwgknk-6nFg.woff2) format('woff2');
323
+ unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
324
+ }
325
+ /* latin */
326
+ @font-face {
327
+ font-family: 'JetBrains Mono';
328
+ font-style: normal;
329
+ font-weight: 500;
330
+ font-display: swap;
331
+ src: url(fonts/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPxDcwgknk-4.woff2) format('woff2');
332
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
333
+ }
static/fonts/6NU78FyLNQOQZAnv9bYEvDiIdE9Ea92uemAk_WBq8U_9v0c2Wa0KxC9TeP2Xz5c.woff2 ADDED
Binary file (67.4 kB). View file
 
static/fonts/6NU78FyLNQOQZAnv9bYEvDiIdE9Ea92uemAk_WBq8U_9v0c2Wa0KxCBTeP2Xz5fU8w.woff2 ADDED
Binary file (19.7 kB). View file
 
static/fonts/6NU78FyLNQOQZAnv9bYEvDiIdE9Ea92uemAk_WBq8U_9v0c2Wa0KxCFTeP2Xz5fU8w.woff2 ADDED
Binary file (59.5 kB). View file
 
static/fonts/ieVn2YZDLWuGJpnzaiwFXS9tYtpQ59CxCis4UvI.woff2 ADDED
Binary file (1.64 kB). View file
 
static/fonts/ieVn2YZDLWuGJpnzaiwFXS9tYtpS59CxCis4UvI.woff2 ADDED
Binary file (9.36 kB). View file
 
static/fonts/ieVn2YZDLWuGJpnzaiwFXS9tYtpT59CxCis4UvI.woff2 ADDED
Binary file (19.6 kB). View file
 
static/fonts/ieVn2YZDLWuGJpnzaiwFXS9tYtpd59CxCis4.woff2 ADDED
Binary file (34.7 kB). View file
 
static/fonts/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPx3cwgknk-6nFg.woff2 ADDED
Binary file (1.66 kB). View file
 
static/fonts/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPx7cwgknk-6nFg.woff2 ADDED
Binary file (11.6 kB). View file
 
static/fonts/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPxDcwgknk-4.woff2 ADDED
Binary file (31.3 kB). View file
 
static/fonts/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPxPcwgknk-6nFg.woff2 ADDED
Binary file (6.8 kB). View file
 
static/fonts/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPxTcwgknk-6nFg.woff2 ADDED
Binary file (8.89 kB). View file
 
static/fonts/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPx_cwgknk-6nFg.woff2 ADDED
Binary file (5.87 kB). View file
 
static/gradio-client.js ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ var GradioClient=(()=>{var ce=Object.defineProperty;var et=Object.getOwnPropertyDescriptor;var tt=Object.getOwnPropertyNames;var nt=Object.prototype.hasOwnProperty;var st=(e,t)=>()=>(e&&(t=e(e=0)),t);var Se=(e,t)=>{for(var n in t)ce(e,n,{get:t[n],enumerable:!0})},it=(e,t,n,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of tt(t))!nt.call(e,i)&&i!==n&&ce(e,i,{get:()=>t[i],enumerable:!(s=et(t,i))||s.enumerable});return e};var ot=e=>it(ce({},"__esModule",{value:!0}),e);var le={};Se(le,{default:()=>at});var at,ue=st(()=>{at={}});var hn={};Se(hn,{Client:()=>G});var rt=Object.defineProperty,Ne=e=>{throw TypeError(e)},ct=(e,t,n)=>t in e?rt(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,u=(e,t,n)=>ct(e,typeof t!="symbol"?t+"":t,n),Pe=(e,t,n)=>t.has(e)||Ne("Cannot "+n),Z=(e,t,n)=>(Pe(e,t,"read from private field"),n?n.call(e):t.get(e)),lt=(e,t,n)=>t.has(e)?Ne("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,n),ut=(e,t,n,s)=>(Pe(e,t,"write to private field"),s?s.call(e,n):t.set(e,n),n),pe=new Intl.Collator(0,{numeric:1}).compare;function ze(e,t,n){return e=e.split("."),t=t.split("."),pe(e[0],t[0])||pe(e[1],t[1])||(t[2]=t.slice(2).join("."),n=/[.-]/.test(e[2]=e.slice(2).join(".")),n==/[.-]/.test(t[2])?pe(e[2],t[2]):n?-1:1)}var pt="host",Ae="queue/data",dt="queue/join",xe="upload",ht="login",X="config",ft="info",_t="runtime",gt="sleeptime",mt="heartbeat",wt="component_server",yt="reset",vt="cancel",bt="app_id",$t="https://gradio-space-api-fetcher-v2.hf.space/api",Be="This application is currently busy. Please try again. ",W="Connection errored out. ",L="Could not resolve app config. ",kt="Could not get space status. ",Et="Could not get API info. ",we="Space metadata could not be loaded. ",St="Invalid URL. A full URL path is required.",xt="Not authorized to access this space. ",Le="Invalid credentials. Could not login. ",jt="Login credentials are required to access this space.",Ct="File system access is only available in Node.js environments",Ue="Root URL not found in client config",qt="Error uploading file";function Dt(e,t,n){return t.startsWith("http://")||t.startsWith("https://")?n?e:t:e+t}async function je(e,t,n){try{return(await(await fetch(`https://huggingface.co/api/spaces/${e}/jwt`,{headers:{Authorization:`Bearer ${t}`,...n?{Cookie:n}:{}}})).json()).token||!1}catch{return!1}}function Ot(e){let t={};return e.forEach(({api_name:n,id:s})=>{n&&(t[n]=s)}),t}async function Tt(e){let t=this.options.hf_token?{Authorization:`Bearer ${this.options.hf_token}`}:{};if(t["Content-Type"]="application/json",typeof window<"u"&&window.gradio_config&&location.origin!=="http://localhost:9876"){if(window.gradio_config.current_page&&(e=e.substring(0,e.lastIndexOf("/"))),window.gradio_config.dev_mode){let n=fe(e,this.deep_link?X+"?deep_link="+this.deep_link:X),s=await this.fetch(n,{headers:t,credentials:"include"}),i=await Ce(s,e,!!this.options.auth);window.gradio_config={...i,current_page:window.gradio_config.current_page}}return window.gradio_config.root=e,{...window.gradio_config}}else if(e){let n=fe(e,this.deep_link?X+"?deep_link="+this.deep_link:X),s=await this.fetch(n,{headers:t,credentials:"include"});return Ce(s,e,!!this.options.auth)}throw new Error(L)}async function Ce(e,t,n){var s,i;if(e?.status===401&&!n){let a=await e.json(),o=(s=a?.detail)==null?void 0:s.auth_message;throw new Error(o||jt)}else if(e?.status===401&&n)throw new Error(Le);if(e?.status===200){let a=await e.json();return a.root=t,(i=a.dependencies)==null||i.forEach((o,r)=>{o.id===void 0&&(o.id=r)}),a}else if(e?.status===401)throw new Error(xt);throw new Error(L)}async function Nt(){let{http_protocol:e,host:t}=await V(this.app_reference,this.options.hf_token);try{if(this.options.auth){let n=await Ie(e,t,this.options.auth,this.fetch,this.options.hf_token);n&&this.set_cookies(n)}}catch(n){throw Error(n.message)}}async function Ie(e,t,n,s,i){let a=new FormData;a.append("username",n?.[0]),a.append("password",n?.[1]);let o={};i&&(o.Authorization=`Bearer ${i}`);let r=await s(`${e}//${t}/${ht}`,{headers:o,method:"POST",body:a,credentials:"include"});if(r.status===200)return r.headers.get("set-cookie");throw r.status===401?new Error(Le):new Error(we)}function de(e){if(e.startsWith("http")){let{protocol:t,host:n,pathname:s}=new URL(e);return{ws_protocol:t==="https:"?"wss":"ws",http_protocol:t,host:n+(s!=="/"?s:"")}}return{ws_protocol:"wss",http_protocol:"https:",host:new URL(e).host}}var Re=e=>{let t=[];return e.split(/,(?=\s*[^\s=;]+=[^\s=;]+)/).forEach(n=>{let[s,i]=n.split(";")[0].split("=");s&&i&&t.push(`${s.trim()}=${i.trim()}`)}),t},ye=/^[a-zA-Z0-9_\-\.]+\/[a-zA-Z0-9_\-\.]+$/,Pt=/.*hf\.space\/{0,1}.*$/;async function V(e,t){let n={};t&&(n.Authorization=`Bearer ${t}`);let s=e.trim().replace(/\/$/,"");if(ye.test(s))try{let i=(await(await fetch(`https://huggingface.co/api/spaces/${s}/${pt}`,{headers:n})).json()).host;return{space_id:e,...de(i)}}catch{throw new Error(we)}if(Pt.test(s)){let{ws_protocol:i,http_protocol:a,host:o}=de(s);return{space_id:o.split("/")[0].replace(".hf.space",""),ws_protocol:i,http_protocol:a,host:o}}return{space_id:!1,...de(s)}}var fe=(...e)=>{try{return e.reduce((t,n)=>(t=t.replace(/\/+$/,""),n=n.replace(/^\/+/,""),new URL(n,t+"/").toString()))}catch{throw new Error(St)}};function zt(e,t,n){let s={named_endpoints:{},unnamed_endpoints:{}};return Object.keys(e).forEach(i=>{(i==="named_endpoints"||i==="unnamed_endpoints")&&(s[i]={},Object.entries(e[i]).forEach(([a,{parameters:o,returns:r}])=>{var l,_,m,p;let g=((l=t.dependencies.find(c=>c.api_name===a||c.api_name===a.replace("/","")))==null?void 0:l.id)||n[a.replace("/","")]||-1,C=g!==-1?(_=t.dependencies.find(c=>c.id==g))==null?void 0:_.types:{generator:!1,cancel:!1};if(g!==-1&&((p=(m=t.dependencies.find(c=>c.id==g))==null?void 0:m.inputs)==null?void 0:p.length)!==o.length){let c=t.dependencies.find(f=>f.id==g).inputs.map(f=>{var D;return(D=t.components.find(P=>P.id===f))==null?void 0:D.type});try{c.forEach((f,D)=>{if(f==="state"){let P={component:"state",example:null,parameter_default:null,parameter_has_default:!0,parameter_name:null,hidden:!0};o.splice(D,0,P)}})}catch(f){console.error(f)}}let U=(c,f,D,P)=>({...c,description:Bt(c?.type,D),type:At(c?.type,f,D,P)||""});s[i][a]={parameters:o.map(c=>U(c,c?.component,c?.serializer,"parameter")),returns:r.map(c=>U(c,c?.component,c?.serializer,"return")),type:C}}))}),s}function At(e,t,n,s){if(t==="Api")return e.type;switch(e?.type){case"string":return"string";case"boolean":return"boolean";case"number":return"number"}if(n==="JSONSerializable"||n==="StringSerializable")return"any";if(n==="ListStringSerializable")return"string[]";if(t==="Image")return s==="parameter"?"Blob | File | Buffer":"string";if(n==="FileSerializable")return e?.type==="array"?s==="parameter"?"(Blob | File | Buffer)[]":"{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}[]":s==="parameter"?"Blob | File | Buffer":"{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}";if(n==="GallerySerializable")return s==="parameter"?"[(Blob | File | Buffer), (string | null)][]":"[{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}, (string | null))][]"}function Bt(e,t){return t==="GallerySerializable"?"array of [file, label] tuples":t==="ListStringSerializable"?"array of strings":t==="FileSerializable"?"array of files or single file":e?.description}function he(e,t){switch(e.msg){case"send_data":return{type:"data"};case"send_hash":return{type:"hash"};case"queue_full":return{type:"update",status:{queue:!0,message:Be,stage:"error",code:e.code,success:e.success}};case"heartbeat":return{type:"heartbeat"};case"unexpected_error":return{type:"unexpected_error",status:{queue:!0,message:e.message,session_not_found:e.session_not_found,stage:"error",success:!1}};case"broken_connection":return{type:"broken_connection",status:{queue:!0,message:e.message,stage:"error",success:!1}};case"estimation":return{type:"update",status:{queue:!0,stage:t||"pending",code:e.code,size:e.queue_size,position:e.rank,eta:e.rank_eta,success:e.success}};case"progress":return{type:"update",status:{queue:!0,stage:"pending",code:e.code,progress_data:e.progress_data,success:e.success}};case"log":return{type:"log",data:e};case"process_generating":return{type:"generating",status:{queue:!0,message:e.success?null:e.output.error,stage:e.success?"generating":"error",code:e.code,progress_data:e.progress_data,eta:e.average_duration,changed_state_ids:e.success?e.output.changed_state_ids:void 0},data:e.success?e.output:null};case"process_streaming":return{type:"streaming",status:{queue:!0,message:e.output.error,stage:"streaming",time_limit:e.time_limit,code:e.code,progress_data:e.progress_data,eta:e.eta},data:e.output};case"process_completed":return"error"in e.output?{type:"update",status:{queue:!0,title:e.output.title,message:e.output.error,visible:e.output.visible,duration:e.output.duration,stage:"error",code:e.code,success:e.success}}:{type:"complete",status:{queue:!0,message:e.success?void 0:e.output.error,stage:e.success?"complete":"error",code:e.code,progress_data:e.progress_data,changed_state_ids:e.success?e.output.changed_state_ids:void 0},data:e.success?e.output:null};case"process_starts":return{type:"update",status:{queue:!0,stage:"pending",code:e.code,size:e.rank,position:0,success:e.success,eta:e.eta},original_msg:"process_starts"}}return{type:"none",status:{stage:"error",queue:!0}}}var Lt=(e=[],t)=>{let n=t?t.parameters:[];if(Array.isArray(e))return t&&n.length>0&&e.length>n.length&&console.warn("Too many arguments provided for the endpoint."),e;let s=[],i=Object.keys(e);return n.forEach((a,o)=>{if(e.hasOwnProperty(a.parameter_name))s[o]=e[a.parameter_name];else if(a.parameter_has_default)s[o]=a.parameter_default;else throw new Error(`No value provided for required parameter: ${a.parameter_name}`)}),i.forEach(a=>{if(!n.some(o=>o.parameter_name===a))throw new Error(`Parameter \`${a}\` is not a valid keyword argument. Please refer to the API for usage.`)}),s.forEach((a,o)=>{if(a===void 0&&!n[o].parameter_has_default)throw new Error(`No value provided for required parameter: ${n[o].parameter_name}`)}),s};async function Ut(){if(this.api_info)return this.api_info;let{hf_token:e}=this.options,{config:t}=this,n={"Content-Type":"application/json"};if(e&&(n.Authorization=`Bearer ${e}`),!!t)try{let s,i;if(typeof window<"u"&&window.gradio_api_info)i=window.gradio_api_info;else{if(ze(t?.version||"2.0.0","3.30")<0)s=await this.fetch($t,{method:"POST",body:JSON.stringify({serialize:!1,config:JSON.stringify(t)}),headers:n,credentials:"include"});else{let a=fe(t.root,this.api_prefix,ft);s=await this.fetch(a,{headers:n,credentials:"include"})}if(!s.ok)throw new Error(W);i=await s.json()}return"api"in i&&(i=i.api),i.named_endpoints["/predict"]&&!i.unnamed_endpoints[0]&&(i.unnamed_endpoints[0]=i.named_endpoints["/predict"]),zt(i,t,this.api_map)}catch(s){throw new Error("Could not get API info. "+s.message)}}async function It(e,t,n){var s;let i={};(s=this==null?void 0:this.options)!=null&&s.hf_token&&(i.Authorization=`Bearer ${this.options.hf_token}`);let a=1e3,o=[],r;for(let l=0;l<t.length;l+=a){let _=t.slice(l,l+a),m=new FormData;_.forEach(g=>{m.append("files",g)});try{let g=n?`${e}${this.api_prefix}/${xe}?upload_id=${n}`:`${e}${this.api_prefix}/${xe}`;r=await this.fetch(g,{method:"POST",body:m,headers:i,credentials:"include"})}catch(g){throw new Error(W+g.message)}if(!r.ok){let g=await r.text();return{error:`HTTP ${r.status}: ${g}`}}let p=await r.json();p&&o.push(...p)}return{files:o}}async function Rt(e,t,n,s){let i=(Array.isArray(e)?e:[e]).map(o=>o.blob),a=i.filter(o=>o.size>(s??1/0));if(a.length)throw new Error(`File size exceeds the maximum allowed size of ${s} bytes: ${a.map(o=>o.name).join(", ")}`);return await Promise.all(await this.upload_files(t,i,n).then(async o=>{if(o.error)throw new Error(o.error);return o.files?o.files.map((r,l)=>new Q({...e[l],path:r,url:`${t}${this.api_prefix}/file=${r}`})):[]}))}var Q=class{constructor({path:t,url:n,orig_name:s,size:i,blob:a,is_stream:o,mime_type:r,alt_text:l,b64:_}){u(this,"path"),u(this,"url"),u(this,"orig_name"),u(this,"size"),u(this,"blob"),u(this,"is_stream"),u(this,"mime_type"),u(this,"alt_text"),u(this,"b64"),u(this,"meta",{_type:"gradio.FileData"}),this.path=t,this.url=n,this.orig_name=s,this.size=i,this.blob=n?void 0:a,this.is_stream=o,this.mime_type=r,this.alt_text=l,this.b64=_}},_e=class{constructor(t,n){u(this,"type"),u(this,"command"),u(this,"meta"),u(this,"fileData"),this.type="command",this.command=t,this.meta=n}},_n=typeof process<"u"&&process.versions&&process.versions.node;function qe(e,t,n){for(;n.length>1;){let i=n.shift();if(typeof i=="string"||typeof i=="number")e=e[i];else throw new Error("Invalid key type")}let s=n.shift();if(typeof s=="string"||typeof s=="number")e[s]=t;else throw new Error("Invalid key type")}async function ge(e,t=void 0,n=[],s=!1,i=void 0){if(Array.isArray(e)){let a=[];return await Promise.all(e.map(async(o,r)=>{var l;let _=n.slice();_.push(String(r));let m=await ge(e[r],s?((l=i?.parameters[r])==null?void 0:l.component)||void 0:t,_,!1,i);a=a.concat(m)})),a}else{if(globalThis.Buffer&&e instanceof globalThis.Buffer||e instanceof Blob)return[{path:n,blob:new Blob([e]),type:t}];if(typeof e=="object"&&e!==null){let a=[];for(let o of Object.keys(e)){let r=[...n,o],l=e[o];a=a.concat(await ge(l,void 0,r,!1,i))}return a}}return[]}function Ft(e,t){var n,s;let i=(s=(n=t?.dependencies)==null?void 0:n.find(a=>a.id==e))==null?void 0:s.queue;return i!=null?!i:!t.enable_queue}function Jt(e,t){return new Promise((n,s)=>{let i=new MessageChannel;i.port1.onmessage=({data:a})=>{i.port1.close(),n(a)},window.parent.postMessage(e,t,[i.port2])})}function K(e,t,n,s,i=!1){if(s==="input"&&!i)throw new Error("Invalid code path. Cannot skip state inputs for input.");if(s==="output"&&i)return e;let a=[],o=0,r=s==="input"?t.inputs:t.outputs;for(let l=0;l<r.length;l++){let _=r[l],m=n.find(p=>p.id===_);if(m?.type==="state"){if(i)if(e.length===r.length){let p=e[o];a.push(p),o++}else a.push(null);else{o++;continue}continue}else{let p=e[o];a.push(p),o++}}return a}async function Wt(e,t,n){let s=this;await Gt(s,t);let i=await ge(t,void 0,[],!0,n);return(await Promise.all(i.map(async({path:a,blob:o,type:r})=>{if(!o)return{path:a,type:r};let l=await s.upload_files(e,[o]),_=l.files&&l.files[0];return{path:a,file_url:_,type:r,name:typeof File<"u"&&o instanceof File?o?.name:void 0}}))).forEach(({path:a,file_url:o,type:r,name:l})=>{if(r==="Gallery")qe(t,o,a);else if(o){let _=new Q({path:o,orig_name:l});qe(t,_,a)}}),t}async function Gt(e,t){var n,s;if(!((n=e.config)!=null&&n.root||(s=e.config)!=null&&s.root_url))throw new Error(Ue);await Fe(e,t)}async function Fe(e,t,n=[]){for(let s in t)t[s]instanceof _e?await Mt(e,t,s):typeof t[s]=="object"&&t[s]!==null&&await Fe(e,t[s],[...n,s])}async function Mt(e,t,n){var s,i;let a=t[n],o=((s=e.config)==null?void 0:s.root)||((i=e.config)==null?void 0:i.root_url);if(!o)throw new Error(Ue);try{let r,l;if(typeof process<"u"&&process.versions&&process.versions.node){let g=await Promise.resolve().then(()=>(ue(),le));l=(await Promise.resolve().then(()=>(ue(),le))).resolve(process.cwd(),a.meta.path),r=await g.readFile(l)}else throw new Error(Ct);let _=new Blob([r],{type:"application/octet-stream"}),m=await e.upload_files(o,[_]),p=m.files&&m.files[0];if(p){let g=new Q({path:p,orig_name:a.meta.name||""});t[n]=g}}catch(r){console.error(qt,r)}}async function Ht(e,t,n){let s={"Content-Type":"application/json"};this.options.hf_token&&(s.Authorization=`Bearer ${this.options.hf_token}`);try{var i=await this.fetch(e,{method:"POST",body:JSON.stringify(t),headers:{...s,...n},credentials:"include"})}catch{return[{error:W},500]}let a,o;try{a=await i.json(),o=i.status}catch(r){a={error:`Could not parse server response: ${r}`},o=500}return[a,o]}async function Zt(e,t={}){let n=!1,s=!1;if(!this.config)throw new Error("Could not resolve app config");if(typeof e=="number")this.config.dependencies.find(i=>i.id==e);else{let i=e.replace(/^\//,"");this.config.dependencies.find(a=>a.id==this.api_map[i])}return new Promise(async(i,a)=>{let o=this.submit(e,t,null,null,!0),r;for await(let l of o)l.type==="data"&&(s&&i(r),n=!0,r=l),l.type==="status"&&(l.stage==="error"&&a(l),l.stage==="complete"&&(s=!0,n&&i(r)))})}async function Y(e,t,n){let s=t==="subdomain"?`https://huggingface.co/api/spaces/by-subdomain/${e}`:`https://huggingface.co/api/spaces/${e}`,i,a;try{if(i=await fetch(s),a=i.status,a!==200)throw new Error;i=await i.json()}catch{n({status:"error",load_status:"error",message:kt,detail:"NOT_FOUND"});return}if(!i||a!==200)return;let{runtime:{stage:o},id:r}=i;switch(o){case"STOPPED":case"SLEEPING":n({status:"sleeping",load_status:"pending",message:"Space is asleep. Waking it up...",detail:o}),setTimeout(()=>{Y(e,t,n)},1e3);break;case"PAUSED":n({status:"paused",load_status:"error",message:"This space has been paused by the author. If you would like to try this demo, consider duplicating the space.",detail:o,discussions_enabled:await De(r)});break;case"RUNNING":case"RUNNING_BUILDING":n({status:"running",load_status:"complete",message:"Space is running.",detail:o});break;case"BUILDING":n({status:"building",load_status:"pending",message:"Space is building...",detail:o}),setTimeout(()=>{Y(e,t,n)},1e3);break;case"APP_STARTING":n({status:"starting",load_status:"pending",message:"Space is starting...",detail:o}),setTimeout(()=>{Y(e,t,n)},1e3);break;default:n({status:"space_error",load_status:"error",message:"This space is experiencing an issue.",detail:o,discussions_enabled:await De(r)});break}}var Je=async(e,t)=>{let n=0,s=12,i=5e3;return new Promise(a=>{Y(e,ye.test(e)?"space_name":"subdomain",o=>{t(o),o.status==="running"||o.status==="error"||o.status==="paused"||o.status==="space_error"?a():(o.status==="sleeping"||o.status==="building")&&(n<s?(n++,setTimeout(()=>{Je(e,t).then(a)},i)):a())})})},Kt=/^(?=[^]*\b[dD]iscussions{0,1}\b)(?=[^]*\b[dD]isabled\b)[^]*$/;async function De(e){try{let t=await fetch(`https://huggingface.co/api/spaces/${e}/discussions`,{method:"HEAD"}),n=t.headers.get("x-error-message");return!(!t.ok||n&&Kt.test(n))}catch{return!1}}async function Yt(e,t){let n={};t&&(n.Authorization=`Bearer ${t}`);try{let s=await fetch(`https://huggingface.co/api/spaces/${e}/${_t}`,{headers:n});if(s.status!==200)throw new Error("Space hardware could not be obtained.");let{hardware:i}=await s.json();return i.current}catch(s){throw new Error(s.message)}}async function Qt(e,t,n){let s={};n&&(s.Authorization=`Bearer ${n}`);let i={seconds:t};try{let a=await fetch(`https://huggingface.co/api/spaces/${e}/${gt}`,{method:"POST",headers:{"Content-Type":"application/json",...s},body:JSON.stringify(i)});if(a.status!==200)throw new Error("Could not set sleep timeout on duplicated Space. Please visit *ADD HF LINK TO SETTINGS* to set a timeout manually to reduce billing charges.");return await a.json()}catch(a){throw new Error(a.message)}}var Oe=["cpu-basic","cpu-upgrade","cpu-xl","t4-small","t4-medium","a10g-small","a10g-large","a10g-largex2","a10g-largex4","a100-large","zero-a10g","h100","h100x8"];async function Xt(e,t){let{hf_token:n,private:s,hardware:i,timeout:a,auth:o}=t;if(i&&!Oe.includes(i))throw new Error(`Invalid hardware type provided. Valid types are: ${Oe.map(f=>`"${f}"`).join(",")}.`);let{http_protocol:r,host:l}=await V(e,n),_=null;if(o){let f=await Ie(r,l,o,fetch);f&&(_=Re(f))}let m={Authorization:`Bearer ${n}`,"Content-Type":"application/json",..._?{Cookie:_.join("; ")}:{}},p=(await(await fetch("https://huggingface.co/api/whoami-v2",{headers:m})).json()).name,g=e.split("/")[1],C={repository:`${p}/${g}`};s&&(C.private=!0);let U;try{i||(U=await Yt(e,n))}catch(f){throw Error(we+f.message)}let c=i||U||"cpu-basic";C.hardware=c;try{let f=await fetch(`https://huggingface.co/api/spaces/${e}/duplicate`,{method:"POST",headers:m,body:JSON.stringify(C)});if(f.status===409)try{return await G.connect(`${p}/${g}`,t)}catch(P){throw console.error("Failed to connect Client instance:",P),P}else if(f.status!==200)throw new Error(f.statusText);let D=await f.json();return await Qt(`${p}/${g}`,a||300,n),await G.connect(Vt(D.url),t)}catch(f){throw new Error(f)}}function Vt(e){let t=/https:\/\/huggingface.co\/spaces\/([^/]+\/[^/]+)/,n=e.match(t);if(n)return n[1]}var B,me=class extends TransformStream{constructor(t={allowCR:!1}){super({transform:(n,s)=>{for(n=Z(this,B)+n;;){let i=n.indexOf(`
2
+ `),a=t.allowCR?n.indexOf("\r"):-1;if(a!==-1&&a!==n.length-1&&(i===-1||i-1>a)){s.enqueue(n.slice(0,a)),n=n.slice(a+1);continue}if(i===-1)break;let o=n[i-1]==="\r"?i-1:i;s.enqueue(n.slice(0,o)),n=n.slice(i+1)}ut(this,B,n)},flush:n=>{if(Z(this,B)==="")return;let s=t.allowCR&&Z(this,B).endsWith("\r")?Z(this,B).slice(0,-1):Z(this,B);n.enqueue(s)}}),lt(this,B,"")}};B=new WeakMap;function en(e){let t=new TextDecoderStream,n=new me({allowCR:!0});return e.pipeThrough(t).pipeThrough(n)}function tn(e){let t=/[:]\s*/.exec(e),n=t&&t.index;if(n)return[e.substring(0,n),e.substring(n+t[0].length)]}function Te(e,t,n){e.get(t)||e.set(t,n)}async function*nn(e,t){if(!e.body)return;let n=en(e.body),s,i=n.getReader(),a;for(;;){if(t&&t.aborted)return i.cancel();if(s=await i.read(),s.done)return;if(!s.value){a&&(yield a),a=void 0;continue}let[o,r]=tn(s.value)||[];o&&(o==="data"?(a||(a={}),a[o]=a[o]?a[o]+`
3
+ `+r:r):o==="event"?(a||(a={}),a[o]=r):o==="id"?(a||(a={}),a[o]=+r||r):o==="retry"&&(a||(a={}),a[o]=+r||void 0))}}async function sn(e,t){let n=new Request(e,t);Te(n.headers,"Accept","text/event-stream"),Te(n.headers,"Content-Type","application/json");let s=await fetch(n);if(!s.ok)throw s;return nn(s,n.signal)}async function on(){let{event_callbacks:e,unclosed_events:t,pending_stream_messages:n,stream_status:s,config:i,jwt:a}=this,o=this;if(!i)throw new Error("Could not resolve app config");s.open=!0;let r=null,l=new URLSearchParams({session_hash:this.session_hash}).toString(),_=new URL(`${i.root}${this.api_prefix}/${Ae}?${l}`);if(a&&_.searchParams.set("__sign",a),r=this.stream(_),!r){console.warn("Cannot connect to SSE endpoint: "+_.toString());return}r.onmessage=async function(m){let p=JSON.parse(m.data);if(p.msg==="close_stream"){ve(s,o.abort_controller);return}let g=p.event_id;if(!g)await Promise.all(Object.keys(e).map(C=>e[C](p)));else if(e[g]&&i){p.msg==="process_completed"&&["sse","sse_v1","sse_v2","sse_v2.1","sse_v3"].includes(i.protocol)&&t.delete(g);let C=e[g];typeof window<"u"&&typeof document<"u"?setTimeout(C,0,p):C(p)}else n[g]||(n[g]=[]),n[g].push(p)},r.onerror=async function(m){console.error(m),await Promise.all(Object.keys(e).map(p=>e[p]({msg:"broken_connection",message:W})))}}function ve(e,t){e&&(e.open=!1,t?.abort())}function an(e,t,n){e[t]?n.data.forEach((s,i)=>{let a=rn(e[t][i],s);e[t][i]=a,n.data[i]=a}):(e[t]=[],n.data.forEach((s,i)=>{e[t][i]=s}))}function rn(e,t){return t.forEach(([n,s,i])=>{e=cn(e,s,n,i)}),e}function cn(e,t,n,s){if(t.length===0){if(n==="replace")return s;if(n==="append")return e+s;throw new Error(`Unsupported action: ${n}`)}let i=e;for(let o=0;o<t.length-1;o++)i=i[t[o]];let a=t[t.length-1];switch(n){case"replace":i[a]=s;break;case"append":i[a]+=s;break;case"add":Array.isArray(i)?i.splice(Number(a),0,s):i[a]=s;break;case"delete":Array.isArray(i)?i.splice(Number(a),1):delete i[a];break;default:throw new Error(`Unknown action: ${n}`)}return e}function ln(e,t={}){let n={close:()=>{console.warn("Method not implemented.")},onerror:null,onmessage:null,onopen:null,readyState:0,url:e.toString(),withCredentials:!1,CONNECTING:0,OPEN:1,CLOSED:2,addEventListener:()=>{throw new Error("Method not implemented.")},dispatchEvent:()=>{throw new Error("Method not implemented.")},removeEventListener:()=>{throw new Error("Method not implemented.")}};return sn(e,t).then(async s=>{n.readyState=n.OPEN;try{for await(let i of s)n.onmessage&&n.onmessage(i);n.readyState=n.CLOSED}catch(i){n.onerror&&n.onerror(i),n.readyState=n.CLOSED}}).catch(s=>{console.error(s),n.onerror&&n.onerror(s),n.readyState=n.CLOSED}),n}function un(e,t={},n,s,i){var a;try{let o=function(w){(i||Ze[w.type])&&m(w)},r=function(){for(Qe=!0;H.length>0;)H.shift()({value:void 0,done:!0})},l=function(w){H.length>0?H.shift()(w):ae.push(w)},_=function(w){l(pn(w)),r()},m=function(w){l({value:w,done:!1})},p=function(){return ae.length>0?Promise.resolve(ae.shift()):new Promise(w=>H.push(w))},{hf_token:g}=this.options,{fetch:C,app_reference:U,config:c,session_hash:f,api_info:D,api_map:P,stream_status:ee,pending_stream_messages:te,pending_diff_streams:ne,event_callbacks:se,unclosed_events:We,post_data:ie,options:R,api_prefix:F}=this,Ge=this;if(!D)throw new Error("No API found");if(!c)throw new Error("Could not resolve app config");let{fn_index:d,endpoint_info:be,dependency:J}=dn(D,e,P,c),Me=Lt(t,be),q,z,A=c.protocol??"ws",$e="",He=()=>$e,h=typeof e=="number"?"/predict":e,M,k=null,O=!1,oe={},I=typeof window<"u"&&typeof document<"u"?new URLSearchParams(window.location.search).toString():"",Ze=((a=R?.events)==null?void 0:a.reduce((w,T)=>(w[T]=!0,w),{}))||{};async function Ke(){let w={},T={};A==="ws"?(q&&q.readyState===0?q.addEventListener("open",()=>{q.close()}):q.close(),w={fn_index:d,session_hash:f}):(w={event_id:k},T={event_id:k,session_hash:f,fn_index:d});try{if(!c)throw new Error("Could not resolve app config");"event_id"in T&&await C(`${c.root}${F}/${vt}`,{headers:{"Content-Type":"application/json"},method:"POST",body:JSON.stringify(T)}),await C(`${c.root}${F}/${yt}`,{headers:{"Content-Type":"application/json"},method:"POST",body:JSON.stringify(w)})}catch{console.warn("The `/reset` endpoint could not be called. Subsequent endpoint results may be unreliable.")}}let Ye=async w=>{await this._resolve_heartbeat(w)};async function ke(w){if(!c)return;let T=w.render_id;c.components=[...c.components.filter(E=>E.props.rendered_in!==T),...w.components],c.dependencies=[...c.dependencies.filter(E=>E.rendered_in!==T),...w.dependencies];let re=c.components.some(E=>E.type==="state"),b=c.dependencies.some(E=>E.targets.some(S=>S[1]==="unload"));c.connect_heartbeat=re||b,await Ye(c),o({type:"render",data:w,endpoint:h,fn_index:d})}this.handle_blob(c.root,Me,be).then(async w=>{var T;if(M={data:K(w,J,c.components,"input",!0)||[],event_data:n,fn_index:d,trigger_id:s},Ft(d,c))o({type:"status",endpoint:h,stage:"pending",queue:!1,fn_index:d,time:new Date}),ie(`${c.root}${F}/run${h.startsWith("/")?h:`/${h}`}${I?"?"+I:""}`,{...M,session_hash:f}).then(([b,E])=>{let S=b.data;E==200?(o({type:"data",endpoint:h,fn_index:d,data:K(S,J,c.components,"output",R.with_null_state),time:new Date,event_data:n,trigger_id:s}),b.render_config&&ke(b.render_config),o({type:"status",endpoint:h,fn_index:d,stage:"complete",eta:b.average_duration,queue:!1,time:new Date})):o({type:"status",stage:"error",endpoint:h,fn_index:d,message:b.error,queue:!1,time:new Date})}).catch(b=>{o({type:"status",stage:"error",message:b.message,endpoint:h,fn_index:d,queue:!1,time:new Date})});else if(A=="ws"){let{ws_protocol:b,host:E}=await V(U,g);o({type:"status",stage:"pending",queue:!0,endpoint:h,fn_index:d,time:new Date});let S=new URL(`${b}://${Dt(E,c.root,!0)}/queue/join${I?"?"+I:""}`);this.jwt&&S.searchParams.set("__sign",this.jwt),q=new WebSocket(S),q.onclose=x=>{x.wasClean||o({type:"status",stage:"error",broken:!0,message:W,queue:!0,endpoint:h,fn_index:d,time:new Date})},q.onmessage=function(x){let j=JSON.parse(x.data),{type:$,status:v,data:y}=he(j,oe[d]);if($==="update"&&v&&!O)o({type:"status",endpoint:h,fn_index:d,time:new Date,...v}),v.stage==="error"&&q.close();else if($==="hash"){q.send(JSON.stringify({fn_index:d,session_hash:f}));return}else $==="data"?q.send(JSON.stringify({...M,session_hash:f})):$==="complete"?O=v:$==="log"?o({type:"log",title:y.title,log:y.log,level:y.level,endpoint:h,duration:y.duration,visible:y.visible,fn_index:d}):$==="generating"&&o({type:"status",time:new Date,...v,stage:v?.stage,queue:!0,endpoint:h,fn_index:d});y&&(o({type:"data",time:new Date,data:K(y.data,J,c.components,"output",R.with_null_state),endpoint:h,fn_index:d,event_data:n,trigger_id:s}),O&&(o({type:"status",time:new Date,...O,stage:v?.stage,queue:!0,endpoint:h,fn_index:d}),q.close()))},ze(c.version||"2.0.0","3.6")<0&&addEventListener("open",()=>q.send(JSON.stringify({hash:f})))}else if(A=="sse"){o({type:"status",stage:"pending",queue:!0,endpoint:h,fn_index:d,time:new Date});var re=new URLSearchParams({fn_index:d.toString(),session_hash:f}).toString();let b=new URL(`${c.root}${F}/${Ae}?${I?I+"&":""}${re}`);if(this.jwt&&b.searchParams.set("__sign",this.jwt),z=this.stream(b),!z)return Promise.reject(new Error("Cannot connect to SSE endpoint: "+b.toString()));z.onmessage=async function(E){let S=JSON.parse(E.data),{type:x,status:j,data:$}=he(S,oe[d]);if(x==="update"&&j&&!O)o({type:"status",endpoint:h,fn_index:d,time:new Date,...j}),j.stage==="error"&&(z?.close(),r());else if(x==="data"){let[v,y]=await ie(`${c.root}${F}/queue/data`,{...M,session_hash:f,event_id:k});y!==200&&(o({type:"status",stage:"error",message:W,queue:!0,endpoint:h,fn_index:d,time:new Date}),z?.close(),r())}else x==="complete"?O=j:x==="log"?o({type:"log",title:$.title,log:$.log,level:$.level,endpoint:h,duration:$.duration,visible:$.visible,fn_index:d}):(x==="generating"||x==="streaming")&&o({type:"status",time:new Date,...j,stage:j?.stage,queue:!0,endpoint:h,fn_index:d});$&&(o({type:"data",time:new Date,data:K($.data,J,c.components,"output",R.with_null_state),endpoint:h,fn_index:d,event_data:n,trigger_id:s}),O&&(o({type:"status",time:new Date,...O,stage:j?.stage,queue:!0,endpoint:h,fn_index:d}),z?.close(),r()))}}else if(A=="sse_v1"||A=="sse_v2"||A=="sse_v2.1"||A=="sse_v3"){o({type:"status",stage:"pending",queue:!0,endpoint:h,fn_index:d,time:new Date});let b="";typeof window<"u"&&typeof document<"u"&&(b=(T=window?.location)==null?void 0:T.hostname);let E=b.includes(".dev.")?`https://moon-${b.split(".")[1]}.dev.spaces.huggingface.tech`:"https://huggingface.co";(typeof window<"u"&&typeof document<"u"&&window.parent!=window&&window.supports_zerogpu_headers?Jt("zerogpu-headers",E):Promise.resolve(null)).then(S=>ie(`${c.root}${F}/${dt}?${I}`,{...M,session_hash:f},S)).then(async([S,x])=>{if(x===503)o({type:"status",stage:"error",message:Be,queue:!0,endpoint:h,fn_index:d,time:new Date});else if(x===422)o({type:"status",stage:"error",message:S.detail,queue:!0,endpoint:h,fn_index:d,code:"validation_error",time:new Date}),r();else if(x!==200)o({type:"status",stage:"error",broken:!1,message:S.detail,queue:!0,endpoint:h,fn_index:d,time:new Date});else{k=S.event_id,$e=k;let j=async function($){try{let{type:v,status:y,data:N,original_msg:Xe}=he($,oe[d]);if(v=="heartbeat")return;if(v==="update"&&y&&!O)o({type:"status",endpoint:h,fn_index:d,time:new Date,original_msg:Xe,...y});else if(v==="complete")O=y;else if(v=="unexpected_error"||v=="broken_connection"){console.error("Unexpected error",y?.message);let Ve=v==="broken_connection";o({type:"status",stage:"error",message:y?.message||"An Unexpected Error Occurred!",queue:!0,endpoint:h,broken:Ve,session_not_found:y?.session_not_found,fn_index:d,time:new Date})}else if(v==="log"){o({type:"log",title:N.title,log:N.log,level:N.level,endpoint:h,duration:N.duration,visible:N.visible,fn_index:d});return}else(v==="generating"||v==="streaming")&&(o({type:"status",time:new Date,...y,stage:y?.stage,queue:!0,endpoint:h,fn_index:d}),N&&J.connection!=="stream"&&["sse_v2","sse_v2.1","sse_v3"].includes(A)&&an(ne,k,N));N&&(o({type:"data",time:new Date,data:K(N.data,J,c.components,"output",R.with_null_state),endpoint:h,fn_index:d}),N.render_config&&await ke(N.render_config),O&&(o({type:"status",time:new Date,...O,stage:y?.stage,queue:!0,endpoint:h,fn_index:d}),r())),(y?.stage==="complete"||y?.stage==="error")&&(se[k]&&delete se[k],k in ne&&delete ne[k])}catch(v){console.error("Unexpected client exception",v),o({type:"status",stage:"error",message:"An Unexpected Error Occurred!",queue:!0,endpoint:h,fn_index:d,time:new Date}),["sse_v2","sse_v2.1","sse_v3"].includes(A)&&(ve(ee,Ge.abort_controller),ee.open=!1,r())}};k in te&&(te[k].forEach($=>j($)),delete te[k]),se[k]=j,We.add(k),ee.open||await this.open_stream()}})}});let Qe=!1,ae=[],H=[],Ee={[Symbol.asyncIterator]:()=>Ee,next:p,throw:async w=>(_(w),p()),return:async()=>(r(),p()),cancel:Ke,event_id:He};return Ee}catch(o){throw console.error("Submit function encountered an error:",o),o}}function pn(e){return{then:(t,n)=>n(e)}}function dn(e,t,n,s){let i,a,o;if(typeof t=="number")i=t,a=e.unnamed_endpoints[i],o=s.dependencies.find(r=>r.id==t);else{let r=t.replace(/^\//,"");i=n[r],a=e.named_endpoints[t.trim()],o=s.dependencies.find(l=>l.id==n[r])}if(typeof i!="number")throw new Error("There is no endpoint matching that name of fn_index matching that number.");return{fn_index:i,endpoint_info:a,dependency:o}}var G=class{constructor(t,n={events:["data"]}){u(this,"app_reference"),u(this,"options"),u(this,"deep_link",null),u(this,"config"),u(this,"api_prefix",""),u(this,"api_info"),u(this,"api_map",{}),u(this,"session_hash",Math.random().toString(36).substring(2)),u(this,"jwt",!1),u(this,"last_status",{}),u(this,"cookies",null),u(this,"stream_status",{open:!1}),u(this,"closed",!1),u(this,"pending_stream_messages",{}),u(this,"pending_diff_streams",{}),u(this,"event_callbacks",{}),u(this,"unclosed_events",new Set),u(this,"heartbeat_event",null),u(this,"abort_controller",null),u(this,"stream_instance",null),u(this,"current_payload"),u(this,"ws_map",{}),u(this,"view_api"),u(this,"upload_files"),u(this,"upload"),u(this,"handle_blob"),u(this,"post_data"),u(this,"submit"),u(this,"predict"),u(this,"open_stream"),u(this,"resolve_config"),u(this,"resolve_cookies");var s;this.app_reference=t,this.deep_link=((s=n.query_params)==null?void 0:s.deep_link)||null,n.events||(n.events=["data"]),this.options=n,this.current_payload={},this.view_api=Ut.bind(this),this.upload_files=It.bind(this),this.handle_blob=Wt.bind(this),this.post_data=Ht.bind(this),this.submit=un.bind(this),this.predict=Zt.bind(this),this.open_stream=on.bind(this),this.resolve_config=Tt.bind(this),this.resolve_cookies=Nt.bind(this),this.upload=Rt.bind(this),this.fetch=this.fetch.bind(this),this.handle_space_success=this.handle_space_success.bind(this),this.stream=this.stream.bind(this)}get_url_config(t=null){if(!this.config)throw new Error(L);t===null&&(t=window.location.href);let n=o=>o.replace(/^\/+|\/+$/g,""),s=n(new URL(this.config.root).pathname),i=n(new URL(t).pathname),a;return i.startsWith(s)?a=n(i.substring(s.length)):a="",this.get_page_config(a)}get_page_config(t){if(!this.config)throw new Error(L);let n=this.config;return t in n.page||(t=""),{...n,current_page:t,layout:n.page[t].layout,components:n.components.filter(s=>n.page[t].components.includes(s.id)),dependencies:this.config.dependencies.filter(s=>n.page[t].dependencies.includes(s.id))}}fetch(t,n){let s=new Headers(n?.headers||{});if(this&&this.cookies&&s.append("Cookie",this.cookies),this&&this.options.headers)for(let i in this.options.headers)s.append(i,this.options.headers[i]);return fetch(t,{...n,headers:s})}stream(t){let n=new Headers;if(this&&this.cookies&&n.append("Cookie",this.cookies),this&&this.options.headers)for(let s in this.options.headers)n.append(s,this.options.headers[s]);return this&&this.options.hf_token&&n.append("Authorization",`Bearer ${this.options.hf_token}`),this.abort_controller=new AbortController,this.stream_instance=ln(t.toString(),{credentials:"include",headers:n,signal:this.abort_controller.signal}),this.stream_instance}async init(){var t;this.options.auth&&await this.resolve_cookies(),await this._resolve_config().then(({config:n})=>this._resolve_heartbeat(n)),this.api_info=await this.view_api(),this.api_map=Ot(((t=this.config)==null?void 0:t.dependencies)||[])}async _resolve_heartbeat(t){if(t&&(this.config=t,this.api_prefix=t.api_prefix||"",this.config&&this.config.connect_heartbeat&&this.config.space_id&&this.options.hf_token&&(this.jwt=await je(this.config.space_id,this.options.hf_token,this.cookies))),t.space_id&&this.options.hf_token&&(this.jwt=await je(t.space_id,this.options.hf_token)),this.config&&this.config.connect_heartbeat){let n=new URL(`${this.config.root}${this.api_prefix}/${mt}/${this.session_hash}`);this.jwt&&n.searchParams.set("__sign",this.jwt),this.heartbeat_event||(this.heartbeat_event=this.stream(n))}}static async connect(t,n={events:["data"]}){let s=new this(t,n);return n.session_hash&&(s.session_hash=n.session_hash),await s.init(),s}async reconnect(){let t=new URL(`${this.config.root}${this.api_prefix}/${bt}`),n;try{let s=await this.fetch(t);if(!s.ok)throw new Error;n=(await s.json()).app_id}catch{return"broken"}return n!==this.config.app_id?"changed":"connected"}close(){this.closed=!0,ve(this.stream_status,this.abort_controller)}set_current_payload(t){this.current_payload=t}static async duplicate(t,n={events:["data"]}){return Xt(t,n)}async _resolve_config(){let{http_protocol:t,host:n,space_id:s}=await V(this.app_reference,this.options.hf_token),{status_callback:i}=this.options;s&&i&&await Je(s,i);let a;try{let o=`${t}//${n}`;if(a=await this.resolve_config(o),!a)throw new Error(L);return this.config_success(a)}catch(o){if(s&&i)Y(s,ye.test(s)?"space_name":"subdomain",this.handle_space_success);else throw i&&i({status:"error",message:"Could not load this space.",load_status:"error",detail:"NOT_FOUND"}),Error(o)}}async config_success(t){if(this.config=t,this.api_prefix=t.api_prefix||"",this.config.auth_required)return this.prepare_return_obj();try{this.api_info=await this.view_api()}catch(n){console.error(Et+n.message)}return this.prepare_return_obj()}async handle_space_success(t){var n;if(!this)throw new Error(L);let{status_callback:s}=this.options;if(s&&s(t),t.status==="running")try{if(this.config=await this._resolve_config(),this.api_prefix=((n=this==null?void 0:this.config)==null?void 0:n.api_prefix)||"",!this.config)throw new Error(L);return await this.config_success(this.config)}catch(i){throw s&&s({status:"error",message:"Could not load this space.",load_status:"error",detail:"NOT_FOUND"}),i}}async component_server(t,n,s){var i;if(!this.config)throw new Error(L);let a={},{hf_token:o}=this.options,{session_hash:r}=this;o&&(a.Authorization=`Bearer ${this.options.hf_token}`);let l,_=this.config.components.find(p=>p.id===t);(i=_?.props)!=null&&i.root_url?l=_.props.root_url:l=this.config.root;let m;if("binary"in s){m=new FormData;for(let p in s.data)p!=="binary"&&m.append(p,s.data[p]);m.set("component_id",t.toString()),m.set("fn_name",n),m.set("session_hash",r)}else m=JSON.stringify({data:s,component_id:t,fn_name:n,session_hash:r}),a["Content-Type"]="application/json";o&&(a.Authorization=`Bearer ${o}`);try{let p=await this.fetch(`${l}${this.api_prefix}/${wt}/`,{method:"POST",body:m,headers:a,credentials:"include"});if(!p.ok)throw new Error("Could not connect to component server: "+p.statusText);return await p.json()}catch(p){console.warn(p)}}set_cookies(t){this.cookies=Re(t).join("; ")}prepare_return_obj(){return{config:this.config,predict:this.predict,submit:this.submit,view_api:this.view_api,component_server:this.component_server}}async connect_ws(t){return new Promise((n,s)=>{let i;try{i=new WebSocket(t)}catch{this.ws_map[t]="failed";return}this.ws_map[t]="pending",i.onopen=()=>{this.ws_map[t]=i,n()},i.onerror=a=>{console.error("WebSocket error:",a),this.close_ws(t),this.ws_map[t]="failed",n()},i.onclose=()=>{this.ws_map[t]="closed"},i.onmessage=a=>{}})}async send_ws_message(t,n){if(!(t in this.ws_map))await this.connect_ws(t);else if(this.ws_map[t]==="pending"||this.ws_map[t]==="closed"||this.ws_map[t]==="failed")return;let s=this.ws_map[t];s instanceof WebSocket?s.send(JSON.stringify(n)):this.post_data(t,n)}async close_ws(t){if(t in this.ws_map){let n=this.ws_map[t];n instanceof WebSocket&&(n.close(),delete this.ws_map[t])}}};return ot(hn);})();
static/mermaid.min.js ADDED
The diff for this file is too large to render. See raw diff