Percy3822 commited on
Commit
719f624
Β·
verified Β·
1 Parent(s): 74a6f59

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +171 -0
app.py ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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,
124
+ temperature=0.2,
125
+ top_p=0.9,
126
+ repetition_penalty=1.2,
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()