Praneshrajan15 commited on
Commit
2a50757
·
verified ·
1 Parent(s): e7799c2

Deploy DataForge model space (CPU-basic, free)

Browse files
Files changed (3) hide show
  1. README.md +64 -13
  2. app.py +445 -0
  3. requirements.txt +4 -0
README.md CHANGED
@@ -1,13 +1,64 @@
1
- ---
2
- title: Dataforge Model
3
- emoji: 😻
4
- colorFrom: blue
5
- colorTo: gray
6
- sdk: gradio
7
- sdk_version: 6.19.0
8
- python_version: '3.13'
9
- app_file: app.py
10
- pinned: false
11
- ---
12
-
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: DataForge 0.5B GRPO
3
+ sdk: gradio
4
+ app_file: app.py
5
+ license: apache-2.0
6
+ models:
7
+ - Praneshrajan15/DataForge-0.5B-GRPO
8
+ - Praneshrajan15/DataForge-0.5B-SFT
9
+ tags:
10
+ - data-quality
11
+ - tabular-data
12
+ - gradio
13
+ - zerogpu
14
+ ---
15
+
16
+ # DataForge 0.5B (GRPO)
17
+
18
+ This Space serves `Praneshrajan15/DataForge-0.5B-GRPO`, the GRPO checkpoint from
19
+ the DataForge tabular-repair training path (override with the
20
+ `DATAFORGE_SPACE_MODEL_ID` Space variable). It powers two surfaces from one
21
+ loaded checkpoint:
22
+
23
+ 1. **Human demo** -- paste a CSV snippet (header row, up to 50 data rows) and run
24
+ **Detect + propose fixes**. The model returns proposed issue/fix rows when it
25
+ can parse the task.
26
+ 2. **Programmatic agent API** -- the DataForge playground drives this Space one
27
+ GPU round-trip per agent step through a torch-free remote policy.
28
+
29
+ The checkpoint is research-grade evidence that the DataForge training, merge,
30
+ evaluation, and publish path works. Its correction F1 is low; it is **not** a
31
+ production quality claim. Safety filtering and SMT verification run on the
32
+ caller (the playground API or CLI), never inside this Space.
33
+
34
+ ## Programmatic API
35
+
36
+ Two stable, version-pinned endpoints (see the "Agent API" accordion in the UI):
37
+
38
+ - `generate(messages_json, temperature, max_new_tokens) -> completion text`
39
+ where `messages_json` is a JSON array of `{"role", "content"}` chat turns.
40
+ `temperature <= 0` selects greedy decoding; `max_new_tokens` is clamped to a
41
+ fixed cap. Invalid payloads and inference failures surface as a Gradio error
42
+ so remote callers can degrade gracefully.
43
+ - `health() -> JSON` reporting the served `model_id` and caps.
44
+
45
+ ## ZeroGPU setup
46
+
47
+ Create a Hugging Face Space with the Gradio SDK and select ZeroGPU in the Space
48
+ settings. Hugging Face's current ZeroGPU documentation describes Gradio-only
49
+ dynamic GPU allocation backed by shared RTX Pro 6000 Blackwell capacity. Queue
50
+ priority and daily quota depend on the visitor's account tier, so public demo
51
+ and agent calls can occasionally wait or fail when quota is exhausted.
52
+
53
+ The Space loads model weights from the Hugging Face Hub with `from_pretrained()`
54
+ and caches them for the process so multi-step agent loops reuse the weights.
55
+ Model weights, generated caches, and user CSV snippets are not committed to this
56
+ repository.
57
+
58
+ ## Limitations
59
+
60
+ - Inputs are capped at 50 rows (demo) and a fixed message/token budget (API).
61
+ - The model may emit malformed JSON or propose incorrect fixes.
62
+ - Do not use this demo for autonomous production data modification.
63
+ - Run real DataForge repairs through the CLI, MCP server, or playground so
64
+ safety, verification, and transaction logging remain in the loop.
app.py ADDED
@@ -0,0 +1,445 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Gradio ZeroGPU Space for the DataForge-0.5B checkpoint.
2
+
3
+ This Space serves two audiences from one loaded checkpoint:
4
+
5
+ * a **human demo** (`Detect + propose fixes`) that takes a CSV snippet and shows
6
+ what the model proposes, and
7
+ * a **stable programmatic API** (`generate`, `health`) that the DataForge
8
+ playground drives, one GPU round-trip per agent step, through the torch-free
9
+ remote policy. The API contract is deliberately small and version-stable:
10
+ `generate(messages_json, temperature, max_new_tokens) -> assistant text`.
11
+
12
+ The checkpoint defaults to the verified GRPO model
13
+ (`Praneshrajan15/DataForge-0.5B-GRPO`); override with `DATAFORGE_SPACE_MODEL_ID`.
14
+ Nothing here applies repairs, stores data, or bypasses the DataForge safety and
15
+ SMT verification path -- those run on the caller (the playground API or CLI).
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import csv
21
+ import io
22
+ import json
23
+ import os
24
+ from collections.abc import Callable
25
+ from typing import Any
26
+
27
+ import gradio as gr
28
+
29
+ try:
30
+ import spaces
31
+ except ImportError: # pragma: no cover - local development fallback
32
+
33
+ class _SpacesFallback:
34
+ """Compatibility shim for non-Space local runs."""
35
+
36
+ @staticmethod
37
+ def GPU( # noqa: N802 - mirrors the Hugging Face spaces API.
38
+ *args: object,
39
+ **kwargs: object,
40
+ ) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
41
+ """Return an identity decorator when the HF `spaces` package is absent."""
42
+ del args, kwargs
43
+
44
+ def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
45
+ return func
46
+
47
+ return decorator
48
+
49
+ spaces = _SpacesFallback()
50
+
51
+
52
+ MODEL_ID = os.environ.get("DATAFORGE_SPACE_MODEL_ID", "Praneshrajan15/DataForge-0.5B-GRPO")
53
+ MAX_ROWS = 50
54
+ MAX_NEW_TOKENS_CAP = 512
55
+ MAX_MESSAGES = 32
56
+ MAX_MESSAGE_CHARS = 8000
57
+ EXAMPLE_SNIPPETS = [
58
+ "id,amount,department\n1,100,cardiology\n2,105,cardiology\n3,1020,cardiology",
59
+ "id,email,zip\n1,ana@example.com,02139\n2,bob@example.com,2139\n3,chen@example.com,02139",
60
+ "id,room,ward\n1,12A,north\n2,12A,north\n3,99Z,south",
61
+ ]
62
+ TABLE_HEADERS = [
63
+ "status",
64
+ "row",
65
+ "column",
66
+ "issue_type",
67
+ "old_value",
68
+ "new_value",
69
+ "confidence",
70
+ "reason",
71
+ ]
72
+ SYSTEM_PROMPT = (
73
+ "You are DataForge-0.5B. Given a CSV snippet, return JSON only. "
74
+ "Use either a list of repair objects or {'fixes': [...]} with keys row, "
75
+ "column, issue_type, old_value, new_value, confidence, reason. If no repair "
76
+ "is justified, return an empty list."
77
+ )
78
+
79
+ # Loaded once per Space process (populated inside the first GPU call, where CUDA
80
+ # is available on ZeroGPU) so multi-step agent loops reuse weights instead of
81
+ # re-instantiating the model on every round-trip.
82
+ _MODEL_CACHE: dict[str, Any] = {}
83
+
84
+
85
+ def _table_row(
86
+ *,
87
+ status: str,
88
+ row: str = "",
89
+ column: str = "",
90
+ issue_type: str = "",
91
+ old_value: str = "",
92
+ new_value: str = "",
93
+ confidence: str = "",
94
+ reason: str = "",
95
+ ) -> list[str]:
96
+ """Build one stable output-table row."""
97
+ return [status, row, column, issue_type, old_value, new_value, confidence, reason]
98
+
99
+
100
+ def parse_csv_snippet(csv_snippet: str) -> tuple[bool, str, list[dict[str, str]]]:
101
+ """Parse and validate a CSV snippet submitted to the demo.
102
+
103
+ Args:
104
+ csv_snippet: Raw CSV text from the Gradio textbox.
105
+
106
+ Returns:
107
+ Tuple of `(ok, message, rows)`. When `ok` is false, `message` is safe to
108
+ show in the UI and `rows` is empty.
109
+ """
110
+ if not csv_snippet.strip():
111
+ return False, "Paste a CSV snippet with a header row and up to 50 data rows.", []
112
+
113
+ try:
114
+ reader = csv.DictReader(io.StringIO(csv_snippet))
115
+ if reader.fieldnames is None or not any(name for name in reader.fieldnames):
116
+ return False, "CSV must include a header row.", []
117
+ rows = [dict(row) for row in reader]
118
+ except csv.Error as exc:
119
+ return False, f"CSV could not be parsed: {exc}", []
120
+
121
+ if not rows:
122
+ return False, "CSV must include at least one data row.", []
123
+ if len(rows) > MAX_ROWS:
124
+ return False, f"CSV snippet has {len(rows)} rows; the demo accepts at most {MAX_ROWS}.", []
125
+ return True, "CSV accepted.", rows
126
+
127
+
128
+ def _json_candidates(text: str) -> list[Any]:
129
+ """Return JSON payload candidates parsed from a model response."""
130
+ stripped = text.strip()
131
+ candidates: list[Any] = []
132
+ for candidate in (stripped, _extract_json_block(stripped)):
133
+ if not candidate:
134
+ continue
135
+ try:
136
+ candidates.append(json.loads(candidate))
137
+ except json.JSONDecodeError:
138
+ continue
139
+ return candidates
140
+
141
+
142
+ def _extract_json_block(text: str) -> str | None:
143
+ """Extract the outermost JSON-looking block from model text."""
144
+ starts = [index for index in (text.find("["), text.find("{")) if index >= 0]
145
+ if not starts:
146
+ return None
147
+ start = min(starts)
148
+ end = max(text.rfind("]"), text.rfind("}"))
149
+ if end <= start:
150
+ return None
151
+ return text[start : end + 1]
152
+
153
+
154
+ def parse_model_output(model_text: str) -> list[list[str]]:
155
+ """Normalize model output into stable table rows."""
156
+ for payload in _json_candidates(model_text):
157
+ raw_items: Any
158
+ if isinstance(payload, dict):
159
+ raw_items = payload.get("fixes", payload.get("issues", []))
160
+ else:
161
+ raw_items = payload
162
+ if not isinstance(raw_items, list):
163
+ continue
164
+ rows: list[list[str]] = []
165
+ for item in raw_items:
166
+ if not isinstance(item, dict):
167
+ continue
168
+ rows.append(
169
+ _table_row(
170
+ status="proposed",
171
+ row=str(item.get("row", "")),
172
+ column=str(item.get("column", "")),
173
+ issue_type=str(item.get("issue_type", item.get("detector_id", ""))),
174
+ old_value=str(item.get("old_value", item.get("actual", ""))),
175
+ new_value=str(item.get("new_value", item.get("expected", ""))),
176
+ confidence=str(item.get("confidence", "")),
177
+ reason=str(item.get("reason", "")),
178
+ )
179
+ )
180
+ return rows or [_table_row(status="ok", reason="The model returned no proposed fixes.")]
181
+ preview = model_text.strip().replace("\n", " ")
182
+ if len(preview) > 240:
183
+ preview = preview[:237] + "..."
184
+ return [_table_row(status="raw", reason=preview or "The model returned an empty response.")]
185
+
186
+
187
+ def _coerce_messages(messages_json: str) -> list[dict[str, str]]:
188
+ """Validate and normalize a chat payload for the `generate` API.
189
+
190
+ Accepts a JSON array of `{"role", "content"}` objects, a `{"messages": [...]}`
191
+ wrapper, or a bare string (treated as a single user turn). Roles are clamped
192
+ to the chat set and content is length-capped so a single call cannot exhaust
193
+ the GPU budget.
194
+ """
195
+ raw = messages_json.strip()
196
+ if not raw:
197
+ raise ValueError("messages payload is empty")
198
+ try:
199
+ parsed: Any = json.loads(raw)
200
+ except json.JSONDecodeError:
201
+ parsed = [{"role": "user", "content": raw}]
202
+ if isinstance(parsed, dict):
203
+ parsed = parsed.get("messages", [parsed])
204
+ if not isinstance(parsed, list) or not parsed:
205
+ raise ValueError("messages must be a non-empty list")
206
+ if len(parsed) > MAX_MESSAGES:
207
+ raise ValueError(f"too many messages ({len(parsed)} > {MAX_MESSAGES})")
208
+ out: list[dict[str, str]] = []
209
+ for item in parsed:
210
+ if not isinstance(item, dict):
211
+ raise ValueError("each message must be a JSON object")
212
+ role = str(item.get("role", "user"))
213
+ if role not in {"system", "user", "assistant"}:
214
+ role = "user"
215
+ content = str(item.get("content", ""))
216
+ if len(content) > MAX_MESSAGE_CHARS:
217
+ content = content[:MAX_MESSAGE_CHARS]
218
+ out.append({"role": role, "content": content})
219
+ return out
220
+
221
+
222
+ def _load_model() -> tuple[Any, Any]:
223
+ """Load (and cache) the tokenizer and model for this Space process."""
224
+ if "model" not in _MODEL_CACHE:
225
+ import torch
226
+ from transformers import AutoModelForCausalLM, AutoTokenizer
227
+
228
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
229
+ model_kwargs: dict[str, Any] = {}
230
+ if torch.cuda.is_available():
231
+ model_kwargs["torch_dtype"] = torch.float16
232
+ model = AutoModelForCausalLM.from_pretrained(MODEL_ID, **model_kwargs)
233
+ _MODEL_CACHE["tokenizer"] = tokenizer
234
+ _MODEL_CACHE["model"] = model
235
+ return _MODEL_CACHE["tokenizer"], _MODEL_CACHE["model"]
236
+
237
+
238
+ def _run_chat(
239
+ messages: list[dict[str, str]],
240
+ *,
241
+ temperature: float,
242
+ max_new_tokens: int,
243
+ ) -> str:
244
+ """Run a chat completion against the loaded checkpoint and return the text."""
245
+ import torch
246
+
247
+ tokenizer, model = _load_model()
248
+ if torch.cuda.is_available():
249
+ model = model.to("cuda")
250
+ device = next(model.parameters()).device
251
+
252
+ try:
253
+ input_ids = tokenizer.apply_chat_template(
254
+ messages,
255
+ add_generation_prompt=True,
256
+ return_tensors="pt",
257
+ ).to(device)
258
+ except Exception:
259
+ prompt = (
260
+ "\n".join(f"{message['role']}: {message['content']}" for message in messages)
261
+ + "\nassistant:"
262
+ )
263
+ input_ids = tokenizer(prompt, return_tensors="pt").input_ids.to(device)
264
+
265
+ gen_kwargs: dict[str, Any] = {
266
+ "max_new_tokens": max_new_tokens,
267
+ "pad_token_id": tokenizer.eos_token_id,
268
+ }
269
+ if temperature and temperature > 0:
270
+ gen_kwargs["do_sample"] = True
271
+ gen_kwargs["temperature"] = temperature
272
+ else:
273
+ gen_kwargs["do_sample"] = False
274
+
275
+ outputs = model.generate(input_ids=input_ids, **gen_kwargs)
276
+ generated = outputs[0][input_ids.shape[-1] :]
277
+ text = tokenizer.decode(generated, skip_special_tokens=True)
278
+
279
+ if torch.cuda.is_available():
280
+ torch.cuda.empty_cache()
281
+ return str(text)
282
+
283
+
284
+ def _generate_model_text(csv_snippet: str) -> str:
285
+ """Run the checkpoint on a CSV snippet for the human demo path."""
286
+ messages = [
287
+ {"role": "system", "content": SYSTEM_PROMPT},
288
+ {"role": "user", "content": f"CSV:\n{csv_snippet.strip()}\n\nJSON:"},
289
+ ]
290
+ return _run_chat(messages, temperature=0.0, max_new_tokens=384)
291
+
292
+
293
+ @spaces.GPU(duration=60)
294
+ def detect_and_propose(csv_snippet: str) -> list[list[str]]:
295
+ """Detect data-quality issues and propose fixes for a CSV snippet."""
296
+ ok, message, _rows = parse_csv_snippet(csv_snippet)
297
+ if not ok:
298
+ return [_table_row(status="error", reason=message)]
299
+ try:
300
+ model_text = _generate_model_text(csv_snippet)
301
+ except Exception as exc:
302
+ return [_table_row(status="error", reason=f"Model inference failed: {exc}")]
303
+ return parse_model_output(model_text)
304
+
305
+
306
+ def detect_and_propose_with_status(csv_snippet: str) -> tuple[list[list[str]], str]:
307
+ """Return model proposals plus an honest demo-status message."""
308
+ rows = detect_and_propose(csv_snippet)
309
+ first_status = rows[0][0] if rows else "raw"
310
+ if first_status == "error":
311
+ return rows, "Input rejected or inference failed. The verified playground path remains Profile -> Repair -> Verify -> Revert."
312
+ if first_status == "raw":
313
+ return rows, "The checkpoint returned unstructured text. Treat this as research output, not a verified repair."
314
+ if first_status == "ok":
315
+ return rows, "The checkpoint proposed no fixes for this snippet."
316
+ return rows, f"Experimental checkpoint returned {len(rows)} proposed fix row(s). Verify repairs with the CLI or playground API before trusting them."
317
+
318
+
319
+ @spaces.GPU(duration=60)
320
+ def generate(
321
+ messages_json: str,
322
+ temperature: float = 0.0,
323
+ max_new_tokens: float = 384,
324
+ ) -> str:
325
+ """Stable chat-completion endpoint driven by the DataForge agent loop.
326
+
327
+ Args:
328
+ messages_json: JSON array of `{"role", "content"}` chat messages (or a
329
+ bare string treated as a single user turn).
330
+ temperature: Sampling temperature; `<= 0` selects greedy decoding so the
331
+ agent's deterministic floor stays reproducible.
332
+ max_new_tokens: Requested generation cap, clamped to `MAX_NEW_TOKENS_CAP`.
333
+
334
+ Returns:
335
+ The assistant text completion with the chat scaffolding removed.
336
+
337
+ Raises:
338
+ gr.Error: If the payload is invalid or inference fails, so remote callers
339
+ observe a clear transport-level error and can degrade gracefully.
340
+ """
341
+ try:
342
+ messages = _coerce_messages(str(messages_json))
343
+ except ValueError as exc:
344
+ raise gr.Error(f"invalid messages payload: {exc}") from exc
345
+ capped = max(1, min(int(max_new_tokens), MAX_NEW_TOKENS_CAP))
346
+ try:
347
+ return _run_chat(messages, temperature=float(temperature), max_new_tokens=capped)
348
+ except Exception as exc: # pragma: no cover - surfaced to the remote caller
349
+ raise gr.Error(f"inference failed: {exc}") from exc
350
+
351
+
352
+ def health() -> str:
353
+ """Return a JSON capability descriptor for the remote policy (no GPU)."""
354
+ return json.dumps(
355
+ {
356
+ "status": "ok",
357
+ "model_id": MODEL_ID,
358
+ "max_new_tokens_cap": MAX_NEW_TOKENS_CAP,
359
+ "max_messages": MAX_MESSAGES,
360
+ "api": ["generate", "health"],
361
+ }
362
+ )
363
+
364
+
365
+ with gr.Blocks(title="DataForge 0.5B") as demo:
366
+ gr.Markdown(
367
+ """
368
+ # DataForge 0.5B (GRPO)
369
+
370
+ Experimental model demo for short CSV snippets, serving the verified GRPO
371
+ checkpoint. This Space shows what the checkpoint proposes and exposes a stable
372
+ `generate` API for the DataForge playground agent; it does not apply repairs,
373
+ store data, or replace the verified DataForge workflow.
374
+
375
+ **Use the product path for evidence:** Profile -> Repair -> Verify -> Revert
376
+ in the CLI or playground. Safety filtering and SMT verification run on the
377
+ caller, not here. This model surface is intentionally bounded to 50 rows, one
378
+ queued inference at a time, and research-grade outputs (GRPO correction F1 is
379
+ low; treat proposals as unverified until the caller checks them).
380
+ """
381
+ )
382
+ with gr.Row():
383
+ with gr.Column(scale=2):
384
+ csv_input = gr.Textbox(
385
+ label="CSV snippet",
386
+ lines=14,
387
+ max_lines=20,
388
+ placeholder="id,amount\n1,100\n2,105\n3,1020",
389
+ )
390
+ gr.Examples(
391
+ examples=EXAMPLE_SNIPPETS,
392
+ inputs=csv_input,
393
+ label="Audited examples",
394
+ )
395
+ run_button = gr.Button("Detect + propose fixes", variant="primary")
396
+ with gr.Column(scale=3):
397
+ output = gr.Dataframe(
398
+ headers=TABLE_HEADERS,
399
+ datatype=["str"] * len(TABLE_HEADERS),
400
+ row_count=1,
401
+ column_count=len(TABLE_HEADERS),
402
+ label="Model output",
403
+ )
404
+ status_output = gr.Markdown("Waiting for a CSV snippet.")
405
+ run_button.click(
406
+ detect_and_propose_with_status,
407
+ inputs=csv_input,
408
+ outputs=[output, status_output],
409
+ show_progress="full",
410
+ concurrency_limit=1,
411
+ )
412
+
413
+ with gr.Accordion("Agent API (programmatic)", open=False):
414
+ gr.Markdown(
415
+ "These endpoints back the DataForge playground agent. `generate` "
416
+ "takes a JSON chat payload and returns the assistant text; `health` "
417
+ "reports the served model id and caps. They are stable API names; "
418
+ "the UI controls below are for manual inspection only."
419
+ )
420
+ messages_input = gr.Textbox(
421
+ label="messages (JSON)",
422
+ lines=6,
423
+ value='[{"role": "user", "content": "Return an empty JSON list: []"}]',
424
+ )
425
+ with gr.Row():
426
+ temperature_input = gr.Number(label="temperature", value=0.0)
427
+ max_new_tokens_input = gr.Number(label="max_new_tokens", value=384)
428
+ generate_button = gr.Button("generate")
429
+ generate_output = gr.Textbox(label="completion", lines=6)
430
+ generate_button.click(
431
+ generate,
432
+ inputs=[messages_input, temperature_input, max_new_tokens_input],
433
+ outputs=generate_output,
434
+ api_name="generate",
435
+ concurrency_limit=1,
436
+ )
437
+ health_button = gr.Button("health")
438
+ health_output = gr.Textbox(label="health", lines=3)
439
+ health_button.click(health, inputs=None, outputs=health_output, api_name="health")
440
+
441
+ demo.queue(max_size=8, default_concurrency_limit=1)
442
+
443
+
444
+ if __name__ == "__main__":
445
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ transformers
2
+ accelerate
3
+ torch
4
+