Percy3822 commited on
Commit
50b5ef2
·
verified ·
1 Parent(s): f7938a4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +59 -387
app.py CHANGED
@@ -1,413 +1,85 @@
1
- # app.py
2
- import os, shutil, subprocess, zipfile, traceback, io
3
  from pathlib import Path
4
- from datetime import datetime
5
  import gradio as gr
6
 
7
- # ----------------- Paths -----------------
8
  ROOT = Path(__file__).resolve().parent
9
- DATA = ROOT / "dataset.jsonl"
10
- LOG = ROOT / "train.log"
11
  RUNS = ROOT / "runs"
12
  RUNS.mkdir(exist_ok=True)
13
 
14
- # ----------------- Logging -----------------
15
  def append_log(msg: str):
16
- msg = (msg or "").rstrip("\n")
17
  try:
18
- with open(LOG, "a", encoding="utf-8") as lf:
19
- lf.write(msg + "\n")
20
  except Exception:
21
  pass
22
 
23
- def read_logs():
24
- return LOG.read_text(encoding="utf-8")[-20000:] if LOG.exists() else "⏳ Waiting…"
 
25
 
26
- # ----------------- Workspace & Models -----------------
27
- def ls_workspace() -> str:
28
- rows = []
29
- for p in sorted(ROOT.iterdir(), key=lambda x: (x.is_file(), x.name.lower())):
30
- try:
31
- size = p.stat().st_size
32
- except Exception:
33
- size = 0
34
- rows.append(f"{'[DIR]' if p.is_dir() else ' '}\t{size:>10}\t{p.name}")
35
- return "\n".join(rows) or "(empty)"
36
 
37
  def list_models():
38
- out = []
39
- for base in [ROOT, RUNS]:
40
- if not base.exists():
41
- continue
42
- for p in base.iterdir():
43
- if p.is_dir() and (p / "config.json").exists() and (
44
- (p / "tokenizer.json").exists() or (p / "tokenizer_config.json").exists()
45
- ):
46
- out.append(str(p))
47
- return sorted(set(out))
48
-
49
- def dropdown_update_safe(models, prefer=None):
50
- val = prefer if (prefer and prefer in models) else (models[0] if models else None)
51
- return gr.update(choices=models, value=val)
52
-
53
- # ----------------- Dataset Upload -----------------
54
- def upload_dataset(file):
55
- append_log("📥 upload_dataset clicked")
56
- if not file:
57
- return "❌ No file selected.", ls_workspace()
58
- if hasattr(file, "name") and os.path.isfile(file.name):
59
- shutil.copy(file.name, DATA)
60
- return f"✅ Uploaded → {DATA.name}", ls_workspace()
61
- return "⚠ Unexpected item; please upload a .jsonl file.", ls_workspace()
62
-
63
- # ----------------- Training (Live Logs) -----------------
64
- def start_training_live(run_name):
65
- append_log("🚀 start_training_live clicked")
66
- # Quick guard: dataset must exist
67
- if not DATA.exists():
68
- msg = "❌ dataset.jsonl not found. Upload a JSONL dataset first."
69
- append_log(msg)
70
- yield (msg, gr.update(value=None, visible=False), ls_workspace(), read_logs(), dropdown_update_safe(list_models()))
71
- return
72
-
73
- run_id = (run_name or "").strip() or datetime.now().strftime("run_%Y%m%d_%H%M%S")
74
- out_dir = RUNS / run_id
75
- zip_path = RUNS / f"{run_id}.zip"
76
-
77
- # clean only this run
78
- if out_dir.exists():
79
- shutil.rmtree(out_dir, ignore_errors=True)
80
- if zip_path.exists():
81
- zip_path.unlink()
82
-
83
- # init log
84
- LOG.write_text(f"🔥 Training started…\nRun: {run_id}\n", encoding="utf-8")
85
- append_log(f"Workspace:\n{ls_workspace()}")
86
-
87
- cmd = [
88
- "python", str(ROOT / "train.py"),
89
- "--dataset", str(DATA),
90
- "--output", str(out_dir),
91
- "--zip_path", str(zip_path),
92
- "--model_name", "Salesforce/codegen-350M-multi",
93
- "--epochs", "1",
94
- "--batch_size", "2",
95
- "--block_size", "256",
96
- "--learning_rate", "5e-5",
97
- ]
98
- append_log("▶ " + " ".join(cmd))
99
-
100
- # start subprocess with live stdout
101
- try:
102
- proc = subprocess.Popen(
103
- cmd,
104
- stdout=subprocess.PIPE,
105
- stderr=subprocess.STDOUT,
106
- bufsize=1,
107
- universal_newlines=True,
108
- encoding="utf-8",
109
- errors="replace",
110
- )
111
- except Exception as e:
112
- err = "❌ Failed to start train.py: " + "".join(traceback.format_exception_only(type(e), e))
113
- append_log(err)
114
- yield (err, gr.update(value=None, visible=False), ls_workspace(), read_logs(), dropdown_update_safe(list_models()))
115
- return
116
-
117
- live_log = io.StringIO()
118
- status_msg = f"🚀 Training run '{run_id}' in progress…"
119
-
120
- # stream loop
121
- while True:
122
- line = proc.stdout.readline()
123
- if line == "" and proc.poll() is not None:
124
- break
125
- if line:
126
- append_log(line.rstrip("\n"))
127
- live_log.write(line)
128
- text = live_log.getvalue()[-20000:]
129
- yield (
130
- status_msg,
131
- gr.update(value=None, visible=False),
132
- ls_workspace(),
133
- text,
134
- dropdown_update_safe(list_models(), prefer=None),
135
- )
136
- if zip_path.exists():
137
- yield (
138
- "📦 Model zip created during run.",
139
- gr.update(value=str(zip_path), visible=True),
140
- ls_workspace(),
141
- text,
142
- dropdown_update_safe(list_models(), prefer=None),
143
- )
144
-
145
- code = proc.wait()
146
-
147
- models = list_models()
148
- model_update = dropdown_update_safe(models, prefer=str(out_dir) if out_dir.exists() else None)
149
- final_logs = read_logs()
150
-
151
- if code == 0 and zip_path.exists():
152
- info = f"✅ Training complete. Saved: {out_dir.name} | Zip: {zip_path.name}"
153
- append_log(info)
154
- yield (info, gr.update(value=str(zip_path), visible=True), ls_workspace(), final_logs, model_update)
155
- else:
156
- info = f"❌ Training failed (exit {code}). Check logs below."
157
- append_log(info)
158
- yield (info, gr.update(value=None, visible=False), ls_workspace(), final_logs, model_update)
159
-
160
- def refresh_download():
161
- append_log("↻ refresh_download clicked")
162
- zips = sorted(RUNS.glob("*.zip"), key=lambda p: p.stat().st_mtime, reverse=True)
163
- latest = zips[0] if zips else None
164
- models = list_models()
165
- return (
166
- gr.update(value=(str(latest) if latest else None), visible=bool(latest)),
167
- ls_workspace(),
168
- dropdown_update_safe(models)
169
- )
170
-
171
- # ----------------- Import a Zip as Model Folder -----------------
172
- def import_zip(zfile):
173
- append_log("📦 import_zip clicked")
174
- if not zfile:
175
- return "❌ No zip selected.", list_models()
176
- dest = ROOT / "imported_model"
177
- if dest.exists():
178
- shutil.rmtree(dest, ignore_errors=True)
179
- dest.mkdir(parents=True, exist_ok=True)
180
- with zipfile.ZipFile(zfile.name, "r") as z:
181
- z.extractall(dest)
182
- return f"✅ Imported to {dest.name}", list_models()
183
-
184
- # ----------------- Generation (cached pipeline) -----------------
185
- _GEN_CACHE = {"path": None, "pipe": None}
186
-
187
- def get_generation_pipeline(model_path: str):
188
- from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
189
- import torch
190
-
191
- if _GEN_CACHE["path"] == model_path and _GEN_CACHE["pipe"] is not None:
192
- return _GEN_CACHE["pipe"]
193
-
194
- append_log(f"🧩 Loading pipeline from: {model_path}")
195
- tok = AutoTokenizer.from_pretrained(model_path, use_fast=True)
196
- if tok.pad_token_id is None:
197
- if tok.eos_token_id is not None:
198
- tok.pad_token = tok.eos_token
199
- append_log("ℹ No pad_token; using eos_token as pad_token.")
200
- else:
201
- tok.add_special_tokens({"pad_token": "[PAD]"})
202
- append_log("ℹ Added [PAD] token to tokenizer.")
203
- model = AutoModelForCausalLM.from_pretrained(model_path)
204
- if getattr(model, "config", None) and getattr(model.config, "vocab_size", None) and len(tok) > model.config.vocab_size:
205
- model.resize_token_embeddings(len(tok))
206
- append_log(f"ℹ Resized embeddings to {len(tok)}.")
207
-
208
- pipe = pipeline(
209
- "text-generation",
210
- model=model,
211
- tokenizer=tok,
212
- device_map="auto" if torch.cuda.is_available() else None,
213
- )
214
- _GEN_CACHE["path"] = model_path
215
- _GEN_CACHE["pipe"] = pipe
216
- append_log("✅ Pipeline loaded.")
217
- return pipe
218
-
219
- # ----------------- Test Tab Helpers -----------------
220
- def ping():
221
- append_log("🔔 Ping pressed (UI wiring OK)")
222
- return "✅ UI is connected and responding."
223
-
224
- def load_selected_model(model_path):
225
- append_log("📦 load_selected_model clicked")
226
- # Dropdown may pass a list; coerce to string
227
- if isinstance(model_path, list):
228
- model_path = model_path[0] if model_path else None
229
- if not model_path:
230
- return "❌ Select a model first."
231
- if not isinstance(model_path, str):
232
- return f"❌ Invalid model path type: {type(model_path)._name_}"
233
- p = Path(model_path)
234
  if not p.exists() or not p.is_dir():
235
- return f"❌ Model folder not found: {model_path}"
236
- try:
237
- append_log(f"📦 Load request → {model_path}")
238
- _ = get_generation_pipeline(model_path)
239
- append_log(f"✅ Loaded pipeline: {model_path}")
240
- return f"✅ Loaded: {model_path}"
241
- except Exception as e:
242
- tb = traceback.format_exc()
243
- append_log("❌ Load error:\n" + tb)
244
- return "❌ Error while loading model:\n" + "".join(traceback.format_exception_only(type(e), e))
245
-
246
- def generate_once(model_path, prompt):
247
- """Non-streaming fallback."""
248
- append_log("▶ generate_once clicked")
249
- # Coerce
250
- if isinstance(model_path, list):
251
- model_path = model_path[0] if model_path else None
252
 
253
- # validate
254
- if not model_path:
255
- msg = "❌ Select a model from the dropdown first."
256
- append_log(msg); return msg
257
- if not isinstance(model_path, str):
258
- msg = f"❌ Invalid model path type: {type(model_path)._name_}"
259
- append_log(msg); return msg
260
- if not Path(model_path).exists():
261
- msg = f"❌ Model folder not found: {model_path}"
262
- append_log(msg); return msg
263
  if not prompt or not prompt.strip():
264
- msg = "❌ Enter a prompt."
265
- append_log(msg); return msg
 
266
 
267
- try:
268
- pipe = get_generation_pipeline(model_path)
269
- append_log(f"📝 Generating once… prompt_len={len(prompt)}")
270
- result = pipe(
271
- prompt.strip(),
272
- max_new_tokens=80,
273
- do_sample=True,
274
- temperature=0.3,
275
- top_p=0.9,
276
- repetition_penalty=1.15,
277
- no_repeat_ngram_size=4,
278
- truncation=True,
279
- return_full_text=True,
280
- )
281
- text = result[0].get("generated_text", "")
282
- if not text:
283
- append_log("⚠ Empty generated_text")
284
- return "⚠ Model returned empty text. Try lowering temperature or adding more context."
285
- append_log("✅ Generation OK.")
286
- return text
287
- except Exception as e:
288
- tb = traceback.format_exc()
289
- append_log("❌ Generation error:\n" + tb)
290
- return "❌ Error during generation:\n" + "".join(traceback.format_exception_only(type(e), e))
291
 
292
- def generate_stream(model_path, prompt):
293
- """Streaming version (if Frontend streaming works)."""
294
- yield " Loading model…"
295
- append_log(" generate_stream clicked")
296
 
297
- # Coerce
298
- if isinstance(model_path, list):
299
- model_path = model_path[0] if model_path else None
 
300
 
301
- # validate
302
- if not model_path:
303
- msg = "❌ Select a model from the dropdown first."
304
- append_log(msg); yield msg; return
305
- if not isinstance(model_path, str):
306
- msg = f"❌ Invalid model path type: {type(model_path)._name_}"
307
- append_log(msg); yield msg; return
308
- if not Path(model_path).exists():
309
- msg = f"❌ Model folder not found: {model_path}"
310
- append_log(msg); yield msg; return
311
- if not prompt or not prompt.strip():
312
- msg = "❌ Enter a prompt."
313
- append_log(msg); yield msg; return
314
 
315
- try:
316
- pipe = get_generation_pipeline(model_path)
317
- yield "⚙ Generating… (this may take a bit on CPU)"
318
- append_log(f"📝 Generating (stream)… prompt_len={len(prompt)}")
319
- result = pipe(
320
- prompt.strip(),
321
- max_new_tokens=80,
322
- do_sample=True,
323
- temperature=0.3,
324
- top_p=0.9,
325
- repetition_penalty=1.15,
326
- no_repeat_ngram_size=4,
327
- truncation=True,
328
- return_full_text=True,
329
- )
330
- text = result[0].get("generated_text", "")
331
- if not text:
332
- append_log("⚠ Empty generated_text")
333
- yield "⚠ Model returned empty text. Try lowering temperature or adding more context."
334
- return
335
- append_log("✅ Generation OK.")
336
- yield text
337
- except Exception as e:
338
- tb = traceback.format_exc()
339
- append_log("❌ Generation error:\n" + tb)
340
- yield "❌ Error during generation:\n" + "".join(traceback.format_exception_only(type(e), e))
341
 
342
- # ----------------- UI -----------------
343
- with gr.Blocks(title="Python AI — Train & Test") as app:
344
- gr.Markdown("## 🧠 Python AI — Train & Test\n• Unique runs • Safe download • Cached generation • Live logs\n")
345
-
346
- # ---------- Test Tab ----------
347
- with gr.Tab("Test"):
348
- gr.Markdown("### Choose a model folder or upload a .zip, then prompt it")
349
- with gr.Row():
350
- refresh_btn = gr.Button("↻ Refresh Model List")
351
- ping_btn = gr.Button("🔔 Ping UI") # sanity check
352
- model_list = gr.Dropdown(
353
- choices=list_models(),
354
- label="Available AIs",
355
- interactive=True,
356
- allow_custom_value=True,
357
- multiselect=False
358
- )
359
- load_btn = gr.Button("📦 Load Model")
360
- load_status = gr.Textbox(label="Model Status", interactive=False)
361
-
362
- zip_in = gr.File(label="Or upload a model .zip", file_types=[".zip"])
363
- import_status = gr.Textbox(label="Import Status", interactive=False)
364
-
365
- prompt = gr.Textbox(
366
- label="Prompt",
367
- lines=8,
368
- placeholder="### Instruction:\nPython: write a function ...\n### Response:\n"
369
- )
370
- with gr.Row():
371
- go_stream = gr.Button("Generate (stream)")
372
- go_once = gr.Button("Generate (once)")
373
- out = gr.Textbox(label="AI Response", lines=20)
374
-
375
- # ---------- Train Tab ----------
376
- with gr.Tab("Train"):
377
- with gr.Row():
378
- ds = gr.File(label="📥 Upload JSONL", file_types=[".jsonl"])
379
- ws = gr.Textbox(label="Workspace", lines=16, value=ls_workspace())
380
- run_name = gr.Textbox(label="Run name (optional)", placeholder="e.g., python_small_v1")
381
- up_status = gr.Textbox(label="Upload Status", interactive=False)
382
- start = gr.Button("🚀 Start Training (Live Logs)", variant="primary")
383
- logs = gr.Textbox(label="📜 Training Logs (live)", lines=18, value=read_logs())
384
- status = gr.Textbox(label="Status", interactive=False)
385
- download_file = gr.File(label="📦 Latest trained zip", visible=False)
386
- refresh_dl_btn = gr.Button("Refresh Download")
387
-
388
- # ---------- Wiring ----------
389
- ds.change(upload_dataset, inputs=ds, outputs=[up_status, ws])
390
-
391
- start.click(
392
- start_training_live,
393
- inputs=[run_name],
394
- outputs=[status, download_file, ws, logs, model_list]
395
- )
396
-
397
- refresh_dl_btn.click(
398
- refresh_download,
399
- outputs=[download_file, ws, model_list]
400
- )
401
-
402
- refresh_btn.click(lambda: dropdown_update_safe(list_models()), outputs=model_list)
403
  ping_btn.click(ping, outputs=out)
404
- load_btn.click(load_selected_model, inputs=[model_list], outputs=[load_status])
405
- zip_in.change(import_zip, inputs=zip_in, outputs=[import_status, model_list])
406
-
407
- # Generation (two modes)
408
- go_stream.click(generate_stream, inputs=[model_list, prompt], outputs=out)
409
- go_once.click(generate_once, inputs=[model_list, prompt], outputs=out)
410
 
411
- # Critical: disable SSR; ensure queue is enabled
412
- app.queue(default_concurrency_limit=1)
413
- app.launch(ssr_mode=False, show_error=True)
 
1
+ # app.py (minimal callback sanity check)
2
+ import os, time
3
  from pathlib import Path
 
4
  import gradio as gr
5
 
 
6
  ROOT = Path(__file__).resolve().parent
7
+ LOG = ROOT / "callback_test.log"
 
8
  RUNS = ROOT / "runs"
9
  RUNS.mkdir(exist_ok=True)
10
 
 
11
  def append_log(msg: str):
 
12
  try:
13
+ with open(LOG, "a", encoding="utf-8") as f:
14
+ f.write(msg.rstrip() + "\n")
15
  except Exception:
16
  pass
17
 
18
+ def ping():
19
+ append_log("PING called")
20
+ return "✅ Backend alive (ping)"
21
 
22
+ def stream():
23
+ append_log("STREAM start")
24
+ for i in range(5):
25
+ time.sleep(0.3)
26
+ yield f"tick {i}"
27
+ append_log("STREAM done")
28
+ yield "✅ Stream ok"
 
 
 
29
 
30
  def list_models():
31
+ # Just list subfolders under runs/ to prove dropdown gets values
32
+ items = [str(p) for p in sorted(RUNS.glob("*")) if p.is_dir()]
33
+ append_log(f"LIST_MODELS -> {items}")
34
+ return items
35
+
36
+ def refresh_models():
37
+ return gr.update(choices=list_models(), value=None)
38
+
39
+ def load_model(path):
40
+ append_log(f"LOAD_MODEL clicked: {path}")
41
+ if not path:
42
+ return "❌ Select a folder under runs/ (create one manually if empty)."
43
+ p = Path(path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  if not p.exists() or not p.is_dir():
45
+ return f"❌ Not found: {path}"
46
+ return f"✅ (Mock) loaded folder: {path}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
+ def generate_once(path, prompt):
49
+ append_log(f"GENERATE clicked: path={path!r}, len(prompt)={len(prompt or '')}")
50
+ if not path:
51
+ return "❌ Pick a folder in the dropdown."
 
 
 
 
 
 
52
  if not prompt or not prompt.strip():
53
+ return "❌ Enter a prompt."
54
+ # No model here—just echo to prove callback path works.
55
+ return f"🤖 MOCK RESPONSE\nModelFolder: {path}\nPrompt: {prompt.strip()[:120]}"
56
 
57
+ with gr.Blocks(title="Callback Sanity Check") as demo:
58
+ gr.Markdown("## 🔧 Minimal Callback Test\nIf these buttons do nothing, the issue is front-end/runtime (not your code).")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
 
60
+ with gr.Row():
61
+ ping_btn = gr.Button("🔔 Ping")
62
+ stream_btn = gr.Button("📡 Stream Test")
63
+ out = gr.Textbox(label="Output", lines=8)
64
 
65
+ gr.Markdown("### Model list mock (folders under runs/)")
66
+ with gr.Row():
67
+ refresh_btn = gr.Button("↻ Refresh List")
68
+ model_dd = gr.Dropdown(choices=list_models(), label="Available Folders", interactive=True)
69
 
70
+ load_btn = gr.Button("📦 Load Folder (mock)")
71
+ load_status = gr.Textbox(label="Load Status", interactive=False)
 
 
 
 
 
 
 
 
 
 
 
72
 
73
+ prompt = gr.Textbox(label="Prompt", lines=4, placeholder="Type anything…")
74
+ gen_btn = gr.Button("Generate (mock)")
75
+ gen_out = gr.Textbox(label="Generated Text", lines=10)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
 
77
+ # Wiring
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  ping_btn.click(ping, outputs=out)
79
+ stream_btn.click(stream, outputs=out)
80
+ refresh_btn.click(refresh_models, outputs=model_dd)
81
+ load_btn.click(load_model, inputs=model_dd, outputs=load_status)
82
+ gen_btn.click(generate_once, inputs=[model_dd, prompt], outputs=gen_out)
 
 
83
 
84
+ demo.queue(default_concurrency_limit=1)
85
+ demo.launch(ssr_mode=False, show_error=True)