Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
| 1 |
# app.py
|
| 2 |
-
import os, shutil, subprocess, zipfile, traceback
|
| 3 |
from pathlib import Path
|
| 4 |
from datetime import datetime
|
| 5 |
import gradio as gr
|
| 6 |
|
| 7 |
-
ROOT = Path(
|
| 8 |
DATA = ROOT / "dataset.jsonl"
|
| 9 |
LOG = ROOT / "train.log"
|
| 10 |
RUNS = ROOT / "runs"
|
|
@@ -55,8 +55,12 @@ def upload_dataset(file):
|
|
| 55 |
return f"β
Uploaded β {DATA.name}", ls_workspace()
|
| 56 |
return "β Unexpected item; please upload a .jsonl file.", ls_workspace()
|
| 57 |
|
| 58 |
-
# -------- training --------
|
| 59 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
run_id = (run_name or "").strip() or datetime.now().strftime("run_%Y%m%d_%H%M%S")
|
| 61 |
out_dir = RUNS / run_id
|
| 62 |
zip_path = RUNS / f"{run_id}.zip"
|
|
@@ -67,7 +71,9 @@ def start_training(run_name):
|
|
| 67 |
if zip_path.exists():
|
| 68 |
zip_path.unlink()
|
| 69 |
|
|
|
|
| 70 |
LOG.write_text(f"π₯ Training startedβ¦\nRun: {run_id}\n", encoding="utf-8")
|
|
|
|
| 71 |
|
| 72 |
cmd = [
|
| 73 |
"python", str(ROOT / "train.py"),
|
|
@@ -81,21 +87,62 @@ def start_training(run_name):
|
|
| 81 |
"--learning_rate", "5e-5",
|
| 82 |
]
|
| 83 |
append_log("βΆ " + " ".join(cmd))
|
| 84 |
-
|
| 85 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
|
| 87 |
models = list_models()
|
| 88 |
model_update = dropdown_update_safe(models, prefer=str(out_dir) if out_dir.exists() else None)
|
|
|
|
| 89 |
|
| 90 |
if code == 0 and zip_path.exists():
|
| 91 |
info = f"β
Training complete. Saved: {out_dir.name} | Zip: {zip_path.name}"
|
| 92 |
-
|
|
|
|
| 93 |
else:
|
| 94 |
info = f"β Training failed (exit {code}). Check logs below."
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
append_log(info)
|
| 98 |
-
return info, dl_update, ls_workspace(), read_logs(), model_update
|
| 99 |
|
| 100 |
def refresh_download():
|
| 101 |
zips = sorted(RUNS.glob("*.zip"), key=lambda p: p.stat().st_mtime, reverse=True)
|
|
@@ -165,6 +212,7 @@ def generate(model_path, prompt):
|
|
| 165 |
if not model_path:
|
| 166 |
return "β Select a model from the dropdown first."
|
| 167 |
if not isinstance(model_path, str):
|
|
|
|
| 168 |
return f"β Invalid model path type: {type(model_path)._name_}"
|
| 169 |
if not Path(model_path).exists():
|
| 170 |
return f"β Model folder not found: {model_path}"
|
|
@@ -193,7 +241,7 @@ def generate(model_path, prompt):
|
|
| 193 |
|
| 194 |
# -------- UI --------
|
| 195 |
with gr.Blocks(title="Python AI β Train & Test") as app:
|
| 196 |
-
gr.Markdown("## π§ Python AI β Train & Test\nβ’ Unique runs β’ Safe download β’ Cached generation\n")
|
| 197 |
|
| 198 |
# Test first (so Train can update its dropdown)
|
| 199 |
with gr.Tab("Test"):
|
|
@@ -218,19 +266,22 @@ with gr.Blocks(title="Python AI β Train & Test") as app:
|
|
| 218 |
ws = gr.Textbox(label="Workspace", lines=16, value=ls_workspace())
|
| 219 |
run_name = gr.Textbox(label="Run name (optional)", placeholder="e.g., python_small_v1")
|
| 220 |
up_status = gr.Textbox(label="Upload Status", interactive=False)
|
| 221 |
-
start = gr.Button("π Start Training", variant="primary")
|
| 222 |
-
logs = gr.Textbox(label="π Training Logs", lines=18, value=read_logs())
|
| 223 |
status = gr.Textbox(label="Status", interactive=False)
|
| 224 |
download_file = gr.File(label="π¦ Latest trained zip", visible=False)
|
| 225 |
refresh_dl_btn = gr.Button("Refresh Download")
|
| 226 |
|
| 227 |
# wiring
|
| 228 |
ds.change(upload_dataset, inputs=ds, outputs=[up_status, ws])
|
|
|
|
|
|
|
| 229 |
start.click(
|
| 230 |
-
|
| 231 |
inputs=[run_name],
|
| 232 |
outputs=[status, download_file, ws, logs, model_list]
|
| 233 |
)
|
|
|
|
| 234 |
refresh_dl_btn.click(
|
| 235 |
refresh_download,
|
| 236 |
outputs=[download_file, ws, model_list]
|
|
|
|
| 1 |
# app.py
|
| 2 |
+
import os, shutil, subprocess, zipfile, traceback, time, io
|
| 3 |
from pathlib import Path
|
| 4 |
from datetime import datetime
|
| 5 |
import gradio as gr
|
| 6 |
|
| 7 |
+
ROOT = Path(_file_).resolve().parent
|
| 8 |
DATA = ROOT / "dataset.jsonl"
|
| 9 |
LOG = ROOT / "train.log"
|
| 10 |
RUNS = ROOT / "runs"
|
|
|
|
| 55 |
return f"β
Uploaded β {DATA.name}", ls_workspace()
|
| 56 |
return "β Unexpected item; please upload a .jsonl file.", ls_workspace()
|
| 57 |
|
| 58 |
+
# -------- training (LIVE LOGS) --------
|
| 59 |
+
def start_training_live(run_name):
|
| 60 |
+
"""
|
| 61 |
+
Streams training logs to the UI while the subprocess runs.
|
| 62 |
+
Yields tuples for outputs: [status, download_file, workspace, logs, model_dropdown]
|
| 63 |
+
"""
|
| 64 |
run_id = (run_name or "").strip() or datetime.now().strftime("run_%Y%m%d_%H%M%S")
|
| 65 |
out_dir = RUNS / run_id
|
| 66 |
zip_path = RUNS / f"{run_id}.zip"
|
|
|
|
| 71 |
if zip_path.exists():
|
| 72 |
zip_path.unlink()
|
| 73 |
|
| 74 |
+
# init log
|
| 75 |
LOG.write_text(f"π₯ Training startedβ¦\nRun: {run_id}\n", encoding="utf-8")
|
| 76 |
+
append_log(f"Workspace:\n{ls_workspace()}")
|
| 77 |
|
| 78 |
cmd = [
|
| 79 |
"python", str(ROOT / "train.py"),
|
|
|
|
| 87 |
"--learning_rate", "5e-5",
|
| 88 |
]
|
| 89 |
append_log("βΆ " + " ".join(cmd))
|
| 90 |
+
|
| 91 |
+
# start subprocess with live stdout
|
| 92 |
+
proc = subprocess.Popen(
|
| 93 |
+
cmd,
|
| 94 |
+
stdout=subprocess.PIPE,
|
| 95 |
+
stderr=subprocess.STDOUT,
|
| 96 |
+
bufsize=1,
|
| 97 |
+
universal_newlines=True,
|
| 98 |
+
encoding="utf-8",
|
| 99 |
+
errors="replace",
|
| 100 |
+
)
|
| 101 |
+
|
| 102 |
+
live_log = io.StringIO()
|
| 103 |
+
status_msg = f"π Training run '{run_id}' in progressβ¦"
|
| 104 |
+
# stream loop
|
| 105 |
+
while True:
|
| 106 |
+
line = proc.stdout.readline()
|
| 107 |
+
if line == "" and proc.poll() is not None:
|
| 108 |
+
break
|
| 109 |
+
if line:
|
| 110 |
+
append_log(line.rstrip("\n"))
|
| 111 |
+
live_log.write(line)
|
| 112 |
+
# Trim to last ~20k chars for UI
|
| 113 |
+
text = live_log.getvalue()[-20000:]
|
| 114 |
+
# yield with download hidden (until zip exists)
|
| 115 |
+
yield (
|
| 116 |
+
status_msg,
|
| 117 |
+
gr.update(value=None, visible=False),
|
| 118 |
+
ls_workspace(),
|
| 119 |
+
text,
|
| 120 |
+
dropdown_update_safe(list_models(), prefer=None),
|
| 121 |
+
)
|
| 122 |
+
# if zip appears during training (e.g., early save), surface it
|
| 123 |
+
if zip_path.exists():
|
| 124 |
+
yield (
|
| 125 |
+
"π¦ Model zip created during run.",
|
| 126 |
+
gr.update(value=str(zip_path), visible=True),
|
| 127 |
+
ls_workspace(),
|
| 128 |
+
text,
|
| 129 |
+
dropdown_update_safe(list_models(), prefer=None),
|
| 130 |
+
)
|
| 131 |
+
|
| 132 |
+
code = proc.wait()
|
| 133 |
|
| 134 |
models = list_models()
|
| 135 |
model_update = dropdown_update_safe(models, prefer=str(out_dir) if out_dir.exists() else None)
|
| 136 |
+
final_logs = read_logs()
|
| 137 |
|
| 138 |
if code == 0 and zip_path.exists():
|
| 139 |
info = f"β
Training complete. Saved: {out_dir.name} | Zip: {zip_path.name}"
|
| 140 |
+
append_log(info)
|
| 141 |
+
yield (info, gr.update(value=str(zip_path), visible=True), ls_workspace(), final_logs, model_update)
|
| 142 |
else:
|
| 143 |
info = f"β Training failed (exit {code}). Check logs below."
|
| 144 |
+
append_log(info)
|
| 145 |
+
yield (info, gr.update(value=None, visible=False), ls_workspace(), final_logs, model_update)
|
|
|
|
|
|
|
| 146 |
|
| 147 |
def refresh_download():
|
| 148 |
zips = sorted(RUNS.glob("*.zip"), key=lambda p: p.stat().st_mtime, reverse=True)
|
|
|
|
| 212 |
if not model_path:
|
| 213 |
return "β Select a model from the dropdown first."
|
| 214 |
if not isinstance(model_path, str):
|
| 215 |
+
# fix minor bug: _name_ not name
|
| 216 |
return f"β Invalid model path type: {type(model_path)._name_}"
|
| 217 |
if not Path(model_path).exists():
|
| 218 |
return f"β Model folder not found: {model_path}"
|
|
|
|
| 241 |
|
| 242 |
# -------- UI --------
|
| 243 |
with gr.Blocks(title="Python AI β Train & Test") as app:
|
| 244 |
+
gr.Markdown("## π§ Python AI β Train & Test\nβ’ Unique runs β’ Safe download β’ Cached generation β’ Live logs\n")
|
| 245 |
|
| 246 |
# Test first (so Train can update its dropdown)
|
| 247 |
with gr.Tab("Test"):
|
|
|
|
| 266 |
ws = gr.Textbox(label="Workspace", lines=16, value=ls_workspace())
|
| 267 |
run_name = gr.Textbox(label="Run name (optional)", placeholder="e.g., python_small_v1")
|
| 268 |
up_status = gr.Textbox(label="Upload Status", interactive=False)
|
| 269 |
+
start = gr.Button("π Start Training (Live Logs)", variant="primary")
|
| 270 |
+
logs = gr.Textbox(label="π Training Logs (live)", lines=18, value=read_logs())
|
| 271 |
status = gr.Textbox(label="Status", interactive=False)
|
| 272 |
download_file = gr.File(label="π¦ Latest trained zip", visible=False)
|
| 273 |
refresh_dl_btn = gr.Button("Refresh Download")
|
| 274 |
|
| 275 |
# wiring
|
| 276 |
ds.change(upload_dataset, inputs=ds, outputs=[up_status, ws])
|
| 277 |
+
|
| 278 |
+
# STREAMED training: function yields updates
|
| 279 |
start.click(
|
| 280 |
+
start_training_live,
|
| 281 |
inputs=[run_name],
|
| 282 |
outputs=[status, download_file, ws, logs, model_list]
|
| 283 |
)
|
| 284 |
+
|
| 285 |
refresh_dl_btn.click(
|
| 286 |
refresh_download,
|
| 287 |
outputs=[download_file, ws, model_list]
|