parthmax24 Claude Sonnet 5 commited on
Commit
a62cfd3
·
1 Parent(s): 2d88665

Add FastAPI + vanilla JS frontend mounted alongside ZeroGPU Gradio

Browse files

Gradio is mounted at /gradio purely as the ZeroGPU harness. Custom
routes live on /api/*, and the vanilla JS UI is served at / via
StaticFiles. Previous crash was StaticFiles raising on a missing
frontend/ directory that hadn't actually been pushed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Files changed (5) hide show
  1. app.py +22 -2
  2. frontend/app.js +3 -5
  3. frontend/index.html +2 -6
  4. frontend/style.css +1 -16
  5. requirements.txt +1 -0
app.py CHANGED
@@ -1,6 +1,12 @@
 
 
1
  import spaces
2
  import gradio as gr
3
  import torch
 
 
 
 
4
 
5
 
6
  @spaces.GPU(duration=30)
@@ -8,5 +14,19 @@ def infer(x):
8
  return f"cuda available: {torch.cuda.is_available()}, got: {x}"
9
 
10
 
11
- demo = gr.Interface(fn=infer, inputs="text", outputs="text")
12
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
  import spaces
4
  import gradio as gr
5
  import torch
6
+ from fastapi import FastAPI
7
+ from fastapi.staticfiles import StaticFiles
8
+
9
+ FRONTEND = os.path.join(os.path.dirname(os.path.abspath(__file__)), "frontend")
10
 
11
 
12
  @spaces.GPU(duration=30)
 
14
  return f"cuda available: {torch.cuda.is_available()}, got: {x}"
15
 
16
 
17
+ with gr.Blocks() as demo:
18
+ inp, out = gr.Textbox(), gr.Textbox()
19
+ gr.Button("Run").click(infer, inp, out, api_name="infer")
20
+
21
+ demo.queue()
22
+
23
+ app = FastAPI()
24
+
25
+
26
+ @app.get("/api/health")
27
+ def health():
28
+ return {"status": "ok"}
29
+
30
+
31
+ app = gr.mount_gradio_app(app, demo, path="/gradio")
32
+ app.mount("/", StaticFiles(directory=FRONTEND, html=True), name="ui")
frontend/app.js CHANGED
@@ -1,5 +1,4 @@
1
  const promptEl = document.getElementById("prompt");
2
- const tokensEl = document.getElementById("tokens");
3
  const outputEl = document.getElementById("output");
4
  const runBtn = document.getElementById("run");
5
 
@@ -14,7 +13,7 @@ async function generate() {
14
  const startRes = await fetch("/gradio/call/infer", {
15
  method: "POST",
16
  headers: { "Content-Type": "application/json" },
17
- body: JSON.stringify({ data: [prompt, Number(tokensEl.value)] }),
18
  });
19
  if (!startRes.ok) throw new Error(`start failed: ${startRes.status}`);
20
  const { event_id } = await startRes.json();
@@ -26,13 +25,12 @@ async function generate() {
26
  outputEl.textContent = payload[0] ?? "";
27
  });
28
 
29
- es.addEventListener("error", () => {
30
  es.close();
31
  runBtn.disabled = false;
32
  });
33
 
34
- // Gradio sends a "complete" typed event when generation finishes.
35
- es.addEventListener("complete", () => {
36
  es.close();
37
  runBtn.disabled = false;
38
  });
 
1
  const promptEl = document.getElementById("prompt");
 
2
  const outputEl = document.getElementById("output");
3
  const runBtn = document.getElementById("run");
4
 
 
13
  const startRes = await fetch("/gradio/call/infer", {
14
  method: "POST",
15
  headers: { "Content-Type": "application/json" },
16
+ body: JSON.stringify({ data: [prompt] }),
17
  });
18
  if (!startRes.ok) throw new Error(`start failed: ${startRes.status}`);
19
  const { event_id } = await startRes.json();
 
25
  outputEl.textContent = payload[0] ?? "";
26
  });
27
 
28
+ es.addEventListener("complete", () => {
29
  es.close();
30
  runBtn.disabled = false;
31
  });
32
 
33
+ es.addEventListener("error", () => {
 
34
  es.close();
35
  runBtn.disabled = false;
36
  });
frontend/index.html CHANGED
@@ -9,12 +9,8 @@
9
  <body>
10
  <main class="wrap">
11
  <h1>dllm</h1>
12
- <textarea id="prompt" placeholder="Type a prompt..."></textarea>
13
- <div class="row">
14
- <label for="tokens">Max tokens</label>
15
- <input id="tokens" type="number" value="128" min="16" max="512" step="16" />
16
- <button id="run">Generate</button>
17
- </div>
18
  <pre id="output"></pre>
19
  </main>
20
  <script src="/app.js"></script>
 
9
  <body>
10
  <main class="wrap">
11
  <h1>dllm</h1>
12
+ <textarea id="prompt" placeholder="Type something..."></textarea>
13
+ <button id="run">Generate</button>
 
 
 
 
14
  <pre id="output"></pre>
15
  </main>
16
  <script src="/app.js"></script>
frontend/style.css CHANGED
@@ -25,23 +25,8 @@ textarea {
25
  resize: vertical;
26
  }
27
 
28
- .row {
29
- display: flex;
30
- align-items: center;
31
- gap: 0.5rem;
32
- margin: 0.75rem 0;
33
- }
34
-
35
- .row input {
36
- width: 5rem;
37
- padding: 0.4rem;
38
- background: #1a1d24;
39
- color: inherit;
40
- border: 1px solid #2a2e37;
41
- border-radius: 6px;
42
- }
43
-
44
  button {
 
45
  padding: 0.5rem 1rem;
46
  background: #6d5ef8;
47
  color: white;
 
25
  resize: vertical;
26
  }
27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  button {
29
+ margin: 0.75rem 0;
30
  padding: 0.5rem 1rem;
31
  background: #6d5ef8;
32
  color: white;
requirements.txt CHANGED
@@ -1,3 +1,4 @@
1
  torch
2
  transformers
3
  spaces
 
 
1
  torch
2
  transformers
3
  spaces
4
+ fastapi