Percy3822 commited on
Commit
f76d825
Β·
verified Β·
1 Parent(s): 70ef65d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +106 -113
app.py CHANGED
@@ -1,123 +1,117 @@
1
- import os, io, zipfile, shutil, subprocess, json, time, glob, tempfile
2
- import gradio as gr
3
  from pathlib import Path
4
- from typing import List, Tuple
5
 
6
- WORKDIR = Path(".")
7
- DATASET_PATH = WORKDIR / "dataset.jsonl"
8
- LOG_PATH = WORKDIR / "train.log"
9
- MODEL_DIR = WORKDIR / "trained_model" # training output folder
10
- ZIP_PATH = WORKDIR / "trained_model.zip" # zipped after train
11
- MODELS_ROOT = WORKDIR # where we scan for saved AIs
12
 
13
  # ---------- helpers ----------
14
- def _safe_unzip(zip_file: str, out_dir: Path) -> str:
15
- out_dir.mkdir(parents=True, exist_ok=True)
16
- with zipfile.ZipFile(zip_file, "r") as z:
17
- z.extractall(out_dir)
18
- # return the inner model folder if zip contained a single directory
19
- subdirs = [p for p in out_dir.iterdir() if p.is_dir()]
20
- return str(subdirs[0] if len(subdirs) == 1 else out_dir)
21
-
22
- def _list_local_models() -> List[str]:
23
- """
24
- Return model folders found under MODELS_ROOT that look like HF models.
25
- We include any folder that has a tokenizer.json or tokenizer_config.json.
26
- """
27
- candidates = []
28
- for p in MODELS_ROOT.iterdir():
29
- if not p.is_dir():
30
- continue
31
- if (p / "tokenizer.json").exists() or (p / "tokenizer_config.json").exists():
32
- candidates.append(str(p))
33
- return sorted(candidates)
34
-
35
- def _start_training_subprocess() -> int:
36
- # clear old outputs
 
 
 
 
 
 
 
 
 
 
37
  if MODEL_DIR.exists():
38
  shutil.rmtree(MODEL_DIR)
39
  if ZIP_PATH.exists():
40
  ZIP_PATH.unlink(missing_ok=True)
 
41
 
42
  cmd = [
43
  "python", "train.py",
44
  "--dataset", str(DATASET_PATH),
45
- "--output", str(MODEL_DIR),
46
- # sensible defaults for quick, real training; adjust in train.py if needed
47
  "--model_name", "Salesforce/codegen-350M-multi",
48
  "--epochs", "1",
49
  "--batch_size", "2",
50
  "--block_size", "256",
51
  "--learning_rate", "5e-5",
 
52
  ]
53
- LOG_PATH.write_text("πŸ”₯ Starting training...\n", encoding="utf-8")
54
  with open(LOG_PATH, "a", encoding="utf-8") as lf:
55
- proc = subprocess.Popen(cmd, stdout=lf, stderr=subprocess.STDOUT)
56
- return proc.wait()
57
-
58
- def _zip_model_folder() -> bool:
59
- if not MODEL_DIR.exists():
60
- return False
61
- if ZIP_PATH.exists():
62
- ZIP_PATH.unlink()
63
- shutil.make_archive(ZIP_PATH.with_suffix("").as_posix(), "zip", MODEL_DIR)
64
- return ZIP_PATH.exists()
65
-
66
- # ---------- UI callbacks ----------
67
- def upload_dataset(file) -> str:
68
- if file is None:
69
- return "❌ No file selected."
70
- shutil.copy(file.name, DATASET_PATH)
71
- return f"βœ… Uploaded: {file.name} β†’ {DATASET_PATH.name}"
72
-
73
- def start_training() -> Tuple[str, str, gr.File]:
74
- if not DATASET_PATH.exists():
75
- return ("❌ Please upload a JSONL first.", "", gr.File.update(visible=False))
76
- exit_code = _start_training_subprocess()
77
-
78
- # after training, try to zip and expose
79
- if exit_code == 0 and _zip_model_folder():
80
- status = "βœ… Training complete."
81
- model_info = f"Saved: {MODEL_DIR.name} | Zip: {ZIP_PATH.name}"
82
- return (status, model_info, gr.File.update(value=str(ZIP_PATH), visible=True))
83
  else:
84
- # surface the tail of the log for quick diagnosis
85
  tail = ""
86
  if LOG_PATH.exists():
87
  with open(LOG_PATH, "r", encoding="utf-8") as f:
88
- lines = f.readlines()[-30:]
89
- tail = "".join(lines)
90
- return (f"❌ Training failed (code {exit_code}).", tail, gr.File.update(visible=False))
91
 
92
- def read_logs() -> str:
93
  if LOG_PATH.exists():
94
- return LOG_PATH.read_text(encoding="utf-8")[-20_000:] # last ~20k chars
95
- return "⏳ Waiting for logs..."
96
 
97
- def refresh_model_list() -> List[str]:
98
- return _list_local_models()
99
 
100
- def upload_model_zip(zip_file) -> Tuple[str, List[str]]:
101
- if zip_file is None:
102
- return "❌ No zip provided.", refresh_model_list()
103
- out = WORKDIR / f"imported_{int(time.time())}"
104
- path = _safe_unzip(zip_file.name, out)
105
- msg = f"βœ… Imported model at: {path}"
106
- return msg, refresh_model_list()
107
 
108
- def generate(model_path: str, prompt: str) -> str:
 
 
 
 
 
 
 
 
 
 
109
  if not model_path:
110
  return "❌ Select a model."
 
 
111
  try:
112
  from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
113
- tok = AutoTokenizer.from_pretrained(model_path, use_fast=True)
114
  if tok.pad_token_id is None and tok.eos_token_id is not None:
115
  tok.pad_token = tok.eos_token
116
  model = AutoModelForCausalLM.from_pretrained(model_path)
117
  gen = pipeline("text-generation", model=model, tokenizer=tok)
118
 
119
- # decoding tuned for code
120
- out = gen(
121
  prompt,
122
  max_new_tokens=220,
123
  do_sample=True,
@@ -127,45 +121,44 @@ def generate(model_path: str, prompt: str) -> str:
127
  no_repeat_ngram_size=4,
128
  eos_token_id=tok.eos_token_id,
129
  pad_token_id=tok.pad_token_id,
130
- truncation=True,
131
  )[0]["generated_text"]
132
- return out
133
  except Exception as e:
134
  return f"❌ Error: {e}"
135
 
136
  # ---------- UI ----------
137
- with gr.Blocks(title="Python AI Trainer") as demo:
138
- gr.Markdown("## 🧠 Python AI Trainer\nUpload JSONL, train, then test your model.")
139
 
140
  with gr.Tab("Train"):
141
- file_in = gr.File(label="πŸ“₯ Upload JSONL Dataset", file_types=[".jsonl", ".jsonl.gz", ".json"])
142
  up_status = gr.Textbox(label="Upload Status", interactive=False)
143
- start_btn = gr.Button("πŸš€ Start Training", variant="primary")
144
- logs_box = gr.Textbox(label="πŸ“œ Live Logs (click Refresh)", lines=16)
145
- refresh_logs = gr.Button("Refresh Logs")
146
- status_box = gr.Textbox(label="Status", interactive=False)
147
  model_info = gr.Textbox(label="Model Output", interactive=False)
148
- dl = gr.File(label="πŸ“¦ Download Trained Model (.zip)", visible=False)
149
- refresh_dl = gr.Button("Refresh Download Area")
150
 
151
- file_in.change(fn=upload_dataset, inputs=file_in, outputs=up_status)
152
- start_btn.click(fn=start_training, outputs=[status_box, model_info, dl])
153
- refresh_logs.click(fn=read_logs, outputs=logs_box)
154
- refresh_dl.click(fn=lambda: (gr.File.update(value=str(ZIP_PATH), visible=ZIP_PATH.exists())),
155
- outputs=dl)
156
 
157
  with gr.Tab("Test"):
158
- gr.Markdown("### πŸ”¬ Choose a stored AI and prompt it")
159
- refresh_models_btn = gr.Button("↻ Refresh AI List")
160
- model_list = gr.Dropdown(choices=_list_local_models(), label="Available AIs", interactive=True)
161
- up_zip = gr.File(label="Or upload a model .zip to test", file_types=[".zip"])
162
- zip_status = gr.Textbox(label="Model Import Status", interactive=False)
163
- prompt = gr.Textbox(label="Prompt", lines=6, placeholder="### Instruction:\nPython: write a function ...\n### Response:\n")
164
- generate_btn = gr.Button("Generate")
165
- output = gr.Textbox(label="AI Response", lines=20)
166
-
167
- refresh_models_btn.click(fn=refresh_model_list, outputs=model_list)
168
- up_zip.change(fn=upload_model_zip, inputs=up_zip, outputs=[zip_status, model_list])
169
- generate_btn.click(fn=generate, inputs=[model_list, prompt], outputs=output)
170
-
171
- demo.launch()
 
1
+ # app.py
2
+ import os, shutil, subprocess, zipfile, time
3
  from pathlib import Path
4
+ import gradio as gr
5
 
6
+ WORKDIR = Path(".")
7
+ DATASET_PATH = WORKDIR / "dataset.jsonl"
8
+ LOG_PATH = WORKDIR / "train.log"
9
+ MODEL_DIR = WORKDIR / "trained_model" # created by train.py
10
+ ZIP_PATH = WORKDIR / "trained_model.zip" # created after train
 
11
 
12
  # ---------- helpers ----------
13
+ def _list_models():
14
+ """List model-looking folders in the workspace."""
15
+ out = []
16
+ for p in WORKDIR.iterdir():
17
+ if p.is_dir() and (p / "config.json").exists() and (
18
+ (p / "tokenizer.json").exists() or (p / "tokenizer_config.json").exists()
19
+ ):
20
+ out.append(str(p))
21
+ # also include the default training output if present
22
+ if MODEL_DIR.exists() and str(MODEL_DIR) not in out:
23
+ out.insert(0, str(MODEL_DIR))
24
+ return sorted(out)
25
+
26
+ def _zip_model_folder():
27
+ """Zip trained_model/ into trained_model.zip (overwrite if exists)."""
28
+ if not MODEL_DIR.exists():
29
+ return False
30
+ if ZIP_PATH.exists():
31
+ ZIP_PATH.unlink()
32
+ shutil.make_archive(ZIP_PATH.with_suffix("").as_posix(), "zip", MODEL_DIR)
33
+ return ZIP_PATH.exists()
34
+
35
+ # ---------- TRAIN callbacks ----------
36
+ def upload_dataset(file):
37
+ if file is None:
38
+ return "❌ No file selected."
39
+ shutil.copy(file.name, DATASET_PATH)
40
+ return f"βœ… Uploaded {file.name} β†’ {DATASET_PATH.name}"
41
+
42
+ def start_training():
43
+ if not DATASET_PATH.exists():
44
+ return ("❌ Upload a JSONL first.", "", gr.File.update(visible=False))
45
+ # clean previous outputs
46
  if MODEL_DIR.exists():
47
  shutil.rmtree(MODEL_DIR)
48
  if ZIP_PATH.exists():
49
  ZIP_PATH.unlink(missing_ok=True)
50
+ LOG_PATH.write_text("πŸ”₯ Starting training...\n", encoding="utf-8")
51
 
52
  cmd = [
53
  "python", "train.py",
54
  "--dataset", str(DATASET_PATH),
55
+ "--output", str(MODEL_DIR),
 
56
  "--model_name", "Salesforce/codegen-350M-multi",
57
  "--epochs", "1",
58
  "--batch_size", "2",
59
  "--block_size", "256",
60
  "--learning_rate", "5e-5",
61
+ "--subset", "0"
62
  ]
 
63
  with open(LOG_PATH, "a", encoding="utf-8") as lf:
64
+ code = subprocess.Popen(cmd, stdout=lf, stderr=subprocess.STDOUT).wait()
65
+
66
+ if code == 0:
67
+ ok = _zip_model_folder()
68
+ info = f"Saved to: {MODEL_DIR.name}"
69
+ if ok:
70
+ info += f" | Zip: {ZIP_PATH.name}"
71
+ return ("βœ… Training complete.", info, gr.File.update(value=str(ZIP_PATH), visible=ok))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  else:
 
73
  tail = ""
74
  if LOG_PATH.exists():
75
  with open(LOG_PATH, "r", encoding="utf-8") as f:
76
+ tail = "".join(f.readlines()[-40:])
77
+ return (f"❌ Training failed (exit {code}). See logs.", tail, gr.File.update(visible=False))
 
78
 
79
+ def read_logs():
80
  if LOG_PATH.exists():
81
+ return LOG_PATH.read_text(encoding="utf-8")[-20000:]
82
+ return "⏳ Waiting for logs…"
83
 
84
+ def refresh_download():
85
+ return gr.File.update(value=str(ZIP_PATH), visible=ZIP_PATH.exists())
86
 
87
+ # ---------- TEST callbacks ----------
88
+ def refresh_models():
89
+ return _list_models()
 
 
 
 
90
 
91
+ def upload_model_zip(zip_file):
92
+ if zip_file is None:
93
+ return "❌ No zip selected.", _list_models()
94
+ # extract to a unique folder
95
+ dest = WORKDIR / f"imported_{int(time.time())}"
96
+ dest.mkdir(parents=True, exist_ok=True)
97
+ with zipfile.ZipFile(zip_file.name, "r") as z:
98
+ z.extractall(dest)
99
+ return f"βœ… Imported to {dest}", _list_models()
100
+
101
+ def generate(model_path, prompt):
102
  if not model_path:
103
  return "❌ Select a model."
104
+ if not prompt or not prompt.strip():
105
+ return "❌ Enter a prompt."
106
  try:
107
  from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
108
+ tok = AutoTokenizer.from_pretrained(model_path, use_fast=True)
109
  if tok.pad_token_id is None and tok.eos_token_id is not None:
110
  tok.pad_token = tok.eos_token
111
  model = AutoModelForCausalLM.from_pretrained(model_path)
112
  gen = pipeline("text-generation", model=model, tokenizer=tok)
113
 
114
+ text = gen(
 
115
  prompt,
116
  max_new_tokens=220,
117
  do_sample=True,
 
121
  no_repeat_ngram_size=4,
122
  eos_token_id=tok.eos_token_id,
123
  pad_token_id=tok.pad_token_id,
124
+ truncation=True
125
  )[0]["generated_text"]
126
+ return text
127
  except Exception as e:
128
  return f"❌ Error: {e}"
129
 
130
  # ---------- UI ----------
131
+ with gr.Blocks(title="Python AI Trainer") as app:
132
+ gr.Markdown("## 🧠 Python AI β€” Train & Test\nUpload JSONL β†’ Train β†’ Download ZIP. Test any stored model separately.")
133
 
134
  with gr.Tab("Train"):
135
+ ds = gr.File(label="πŸ“₯ Upload JSONL dataset", file_types=[".jsonl", ".jsonl.gz", ".json"])
136
  up_status = gr.Textbox(label="Upload Status", interactive=False)
137
+ start = gr.Button("πŸš€ Start Training", variant="primary")
138
+ logs = gr.Textbox(label="πŸ“œ Logs (click Refresh)", lines=18)
139
+ refresh_logs_btn = gr.Button("Refresh Logs")
140
+ status = gr.Textbox(label="Status", interactive=False)
141
  model_info = gr.Textbox(label="Model Output", interactive=False)
142
+ download_file = gr.File(label="πŸ“¦ Download trained_model.zip", visible=False)
143
+ refresh_dl_btn = gr.Button("Refresh Download Area")
144
 
145
+ ds.change(upload_dataset, inputs=ds, outputs=up_status)
146
+ start.click(start_training, outputs=[status, model_info, download_file])
147
+ refresh_logs_btn.click(read_logs, outputs=logs)
148
+ refresh_dl_btn.click(refresh_download, outputs=download_file)
 
149
 
150
  with gr.Tab("Test"):
151
+ gr.Markdown("### πŸ”¬ Pick a stored AI (folder) or upload a ZIP, then prompt it")
152
+ refresh_btn = gr.Button("↻ Refresh Model List")
153
+ model_list = gr.Dropdown(choices=_list_models(), label="Available AIs", interactive=True)
154
+ zip_in = gr.File(label="Or upload a model .zip", file_types=[".zip"])
155
+ import_status = gr.Textbox(label="Import Status", interactive=False)
156
+ prompt = gr.Textbox(label="Prompt", lines=8, placeholder="### Instruction:\nPython: write a function ...\n### Response:\n")
157
+ go = gr.Button("Generate")
158
+ out = gr.Textbox(label="AI Response", lines=20)
159
+
160
+ refresh_btn.click(refresh_models, outputs=model_list)
161
+ zip_in.change(upload_model_zip, inputs=zip_in, outputs=[import_status, model_list])
162
+ go.click(generate, inputs=[model_list, prompt], outputs=out)
163
+
164
+ app.launch()