A three-app local studio for the whole fine-tuning loop: build the dataset, train the model, then actually test it β on your own machine, on your own GPU, with no cloud in the path.
β The three labs, end to end. Source: docs/demo/demo.html β a deterministic, frame-addressable animation rendered to GIF by docs/demo/render_demo.py.
Why β’ The three labs β’ Quick start β’ Dataset Lab β’ Finetune Lab β’ Chat Lab β’ API β’ Troubleshooting
Fine-tuning a model on your own material normally means stitching together four different worlds: a scraper, a chunking script, a training notebook full of CUDA incantations, and some throwaway REPL to see whether the result is any good.
This repo collapses that into three web apps that hand off to each other:
| Lab | What you do | What comes out | |
|---|---|---|---|
| 1 | Dataset Lab | Point it at text or the web. It cleans, chunks, semantically de-duplicates, and has an LLM write instruction/QA pairs. | alpaca / sharegpt / openai JSONL |
| 2 | Finetune Lab | Pick a model, drop in that JSONL, choose QLoRA/LoRA/SFT/CPT/Full/Vision, watch loss stream live. | A LoRA adapter, a merged 16-bit checkpoint, or GGUF |
| 3 | Chat Lab | Chat with the run you just trained, and put it head-to-head against its own base model. | Proof the training actually landed |
No step uploads your data anywhere. Generation can use a local Ollama model; training and inference run on your GPU.
flowchart LR
subgraph DL["π Dataset Lab Β· :5173"]
A["π .txt upload<br/>π web scrape"] --> B["clean β chunk<br/>β embed-refine"]
B --> C["LLM generates<br/>QA pairs"]
C --> D["alpaca / sharegpt<br/>/ openai .jsonl"]
end
subgraph FL["π Finetune Lab Β· :5173"]
E["Model β Dataset β Config<br/>β Hardware β Launch"] --> F["Unsloth trainer<br/>live loss Β· VRAM Β· logs"]
F --> G["adapter Β· merged 16-bit<br/>GGUF Β· HF Hub"]
end
subgraph CL["π¬ Chat Lab Β· :5273"]
H["stream Β· compare<br/>history Β· presets"]
end
D -->|"dataset"| E
G -->|"reads runs/ directly"| H
Each lab is a self-contained FastAPI backend + React/Vite frontend, sharing one dark "control console" design system (documented in skill.md).
| Backend | Frontend | Needs a GPU? | Own docs | |
|---|---|---|---|---|
| Dataset Lab | :8000 |
:5173 |
No β Ollama or OpenAI does the generating | dataset-lab/README.md |
| Finetune Lab | :8000 |
:5173 |
Yes, to train. The whole UI works without one. | finetune-lab/GUIDE.md |
| Chat Lab | :8100 |
:5273 |
Yes, to load a model. The API boots torch-free. | chat-lab/README.md |
Important
Dataset Lab and Finetune Lab both default to backend :8000 and frontend :5173. Run them one at a time, or move one of them (--port on uvicorn / vite --port, plus VITE_API_URL for the frontend). Chat Lab is already out of the way on :8100/:5273.
Dataset Lab ships a full installer and CLI runner. This is the only lab with a double-click path.
| Windows | macOS / Linux |
|---|---|
git clone https://github.com/amarnath123456789/Dataset-Creator-App.git
cd Dataset-Creator-App
start.batOr just double-click |
git clone https://github.com/amarnath123456789/Dataset-Creator-App.git
cd Dataset-Creator-App
bash start.sh |
The script runs install.py if needed (creates dataset-lab/.venv, installs pip + npm deps, writes .env), then boots both servers and opens http://localhost:5173.
CLI runner β datasetlab.py:
| Command | Does |
|---|---|
python datasetlab.py start |
Start backend + frontend |
python datasetlab.py stop |
Stop both cleanly |
python datasetlab.py status |
Live status + PIDs |
python datasetlab.py open |
Open the dashboard |
python datasetlab.py logs |
Tail recent server output |
cd finetune-lab/backend
python -m venv .venv && .venv\Scripts\activate # Windows
pip install -r requirements.txt
python start_backend.py # β :8000
cd ../frontend && npm install && npm run dev # β :5173Warning
Plain pip install -r requirements.txt silently gives you the CPU-only torch wheel, even on a machine with an NVIDIA GPU β no error, torch.cuda.is_available() just returns False and training fails at launch. After installing, note the torch version pip settled on and reinstall it from the CUDA index:
python -c "import torch; print(torch.__version__)" # e.g. 2.10.0
pip install --index-url https://download.pytorch.org/whl/cu126 \
torch==<that-version> torchvision --force-reinstall --no-deps
python -c "import torch; print(torch.cuda.is_available(), torch.__version__)"
# expect: True 2.x.x+cu126Verified combo: RTX 3070 / driver 591.59 β torch 2.10.0+cu126, bitsandbytes 0.49.2, unsloth 2026.6.9. Full detail in finetune-lab/GUIDE.md.
No GPU, just exploring? pip install fastapi uvicorn python-multipart pydantic is enough β the ML stack is imported lazily and only touched at Launch.
cd chat-lab/backend
pip install -r requirements.txt # use the same env as Finetune Lab
python start_backend.py # β :8100
cd ../frontend && npm install && npm run dev # β :5273File-based dataset engineering. Every project is a folder on disk β no database, no hidden state, and a crashed run resumes from exactly where it stopped.
raw.txt β cleaned.txt β chunks.json β qa_v1.json β export_*.jsonl
clean chunk refine generate export
| Stage | What actually happens |
|---|---|
| Clean | Normalises whitespace, artefacts and encoding noise out of the raw text |
| Chunk | RecursiveCharacterTextSplitter with real token counting (tiktoken / cl100k_base), configurable size + overlap |
| Refine | Embeds every chunk with sentence-transformers (all-MiniLM-L6-v2) and merges adjacent chunks whose cosine similarity is above the threshold β kills near-duplicate context before it wastes generation calls |
| Generate | Walks the chunks and asks an LLM for instruction/QA pairs, with an editable prompt template, domain hint and QA-density factor |
| Export | Renders qa_v1.json through a format template into training-ready JSONL |
Resumable and stoppable by design. State lives in flag files (.running, .stop), progress in progress.json, and partial output in qa_partial.json. Hit Stop mid-run and the pairs generated so far survive; hit Resume and it picks up at the chunk it left off, skipping clean/chunk/refine entirely.
- Upload β UTF-8
.txtfiles. - Web scraping β a full crawler in its own dashboard: DuckDuckGo search or a URL list, crawl depth, page cap, domain restriction, relevance scoring/threshold,
robots.txtrespect and rate limiting. It runs readability-based article extraction, downloads images with size/format filtering, drops exact and near-duplicates by hash, auto-labels each page with an LLM (labels, category, language, summary), and can run a second LLM refinement pass over the scraped text.
| Provider | Notes |
|---|---|
| Ollama (local) | Auto-detected at http://localhost:11434; the UI lists your pulled models. Free, offline, private. |
| OpenAI | Key from the Settings panel or OPENAI_API_KEY in .env. |
alpaca Β· sharegpt Β· openai β driven by dataset-lab/backend/formats/formats.json, so adding a format is a JSON template, not code.
Configuration (.env, written by the installer)
DEFAULT_CHUNK_SIZE=800
DEFAULT_CHUNK_OVERLAP=100
DEFAULT_SIMILARITY_THRESHOLD=0.92
OPENAI_API_KEY=your_openai_api_key_hereNo-code local fine-tuning. A five-step wizard between you and a trained adapter β you never write a training script.
Model β Dataset β Config β Hardware β Review β Launch β Monitor β Export
All six run single- or multi-GPU (DDP via accelerate), on the canonical Unsloth runner with OOM auto-retry:
| Method | For |
|---|---|
| QLoRA | 4-bit base + LoRA adapter β the cheapest way to train an 8B on 8 GB |
| LoRA | 16-bit base + adapter |
| SFT | Supervised fine-tuning on instruction data |
| CPT | Continued pre-training on a raw corpus (+ trainable embeddings, separate embedding LR) |
| Full | Full-parameter fine-tune |
| Vision | VLM fine-tuning, with per-layer control (vision / language / attention / MLP) |
LoftQ, rsLoRA, scheduler/optimizer/warmup/decay/save-steps/seed and every method-specific flag are exposed in the UI and flow straight through to the engine.
Three sources: the curated registry, any Hugging Face repo id, or a local path on the training box. The registry ships:
| Model | Params | Ctx | Min VRAM | Methods |
|---|---|---|---|---|
| Llama 3 8B Instruct | 8B | 8k | 6 GB | SFT Β· LoRA Β· QLoRA Β· CPT Β· Full |
| Mistral 7B v0.3 | 7B | 32k | 6 GB | SFT Β· LoRA Β· QLoRA Β· CPT Β· Full |
| Qwen 2.5 3B | 3B | 32k | 4 GB | SFT Β· LoRA Β· QLoRA Β· CPT Β· Full |
| Gemma 2 9B IT | 9B | 8k | 8 GB | SFT Β· LoRA Β· QLoRA Β· CPT Β· Full |
| Phi-3 Mini 4K | 3.8B | 4k | 4 GB | SFT Β· LoRA Β· QLoRA Β· CPT Β· Full |
| Llama 3.2 11B Vision | 11B | 8k | 10 GB | Vision |
| Qwen2-VL 7B | 7B | 32k | 7 GB | Vision |
The Config step only offers the methods the chosen model supports.
Upload .jsonl / .json / .csv and the backend auto-detects the schema and row count:
| Schema | Shape |
|---|---|
| Instruction | {"instruction", "input", "output"} |
| ChatML | {"messages": [{"role", "content"}]} |
| ShareGPT | {"conversations": [...]} |
| Completion / CPT | {"text": "..."} |
Preference data (chosen/rejected) is flagged DPO-only and blocked for SFT. Hugging Face dataset ids work too, and are required for Vision (image datasets β e.g. unsloth/LaTeX_OCR).
The Run Dashboard streams status, loss value and loss curve, step/epoch, VRAM, tok/s, ETA, and a live log terminal. Smart Config pre-fills sane hyperparameters from the model size; the Hardware step reads your CUDA devices and gives a VRAM/time estimate with an OOM guard. Stop cancels cooperatively and still saves a partial adapter.
| Target | Notes |
|---|---|
| Adapter | Copy the LoRA adapter β instant, no GPU |
| Merged 16-bit | Base + adapter into a standalone checkpoint |
| GGUF | llama.cpp / Ollama format |
| Push to Hub | Upload the merged model to Hugging Face |
Artifacts land in finetune-lab/backend/storage/runs/<run_id>/final/; export jobs are tracked on the Exports page.
GPU validation harness
Finetune Lab ships a harness that drives the real run_service β gpu_worker β runner path for every method on a tiny model and a few steps, asserting completion, true step-based progress, live loss and saved artifacts:
python -m validation.gpu_validate selftest # torch-free, passes off-GPU today
python -m validation.gpu_validate preflight
python -m validation.gpu_validate run --all # run this on the GPU boxWhere you find out whether the training worked. Chat Lab trains nothing β it reads Finetune Lab's output directly, so a completed run shows up in the model picker with no export step.
| Finetune Lab writes | Chat Lab reads |
|---|---|
runs/{id}/final/ (adapter + tokenizer) |
loads it for inference |
runs/{id}/run_manifest.json |
base model, quantization, context length |
storage/jobs.json |
which runs are completed |
model_registry/models.json |
base models to chat with / compare against |
- Chat β multi-turn, token-streaming conversation with any fine-tuned run or base model. Live system-prompt editor, full generation controls, stop and regenerate.
- Compare β same prompt, two models, side by side. One click sets up base vs fine-tuned (did my training change anything?), or pit two checkpoints against each other.
- History β save, reopen, and export conversations to Markdown.
- Presets β batch a fixed set of prompts through a model for repeatable sanity checks.
Every response reports tokens, tokens/sec, and time-to-first-token.
Unsloth FastLanguageModel loads the saved adapter directory directly (resolving the base model from adapter_config.json); a transformers + PEFT path is the automatic fallback. Tokens stream from a TextIteratorStreamer running model.generate on a background thread, relayed to the browser over SSE, and cancelled mid-flight by a threading.Event set on /stop or on browser disconnect.
Chat Lab always applies each model's own tokenizer chat template (apply_chat_template, add_generation_prompt=True) and trims the oldest turns to fit the context window.
Defaults: temperature 0.7 Β· top_p 0.9 Β· top_k 20 Β· repetition_penalty 1.1 Β· max_new_tokens 512 (all adjustable per chat; temperature 0 β greedy).
All torch/unsloth/transformers imports are deferred, so the API boots and lists models even on a machine with no GPU β loading one then returns a clear, actionable error instead of a stack trace at import time.
| Details | |
|---|---|
| OS | Windows 10/11 (primary), macOS, Linux |
| Python | 3.10+ (3.10/3.11 recommended β Unsloth support) |
| Node.js | 18+ |
| GPU | NVIDIA + CUDA, required only to train and to load a model in Chat Lab. Dataset Lab, the wizards, estimates and run history all work without one. |
| RAM | 8 GB min Β· 16 GB+ with local LLMs |
| Disk | ~2 GB for the apps, plus 4β10 GB per model |
| Ollama | Optional β enables 100% offline dataset generation (ollama.com) |
Dataset Lab β :8000 Β· docs at /docs
| Method | Path | Purpose |
|---|---|---|
GET/POST |
/projects/ |
List / create projects |
DELETE |
/projects/{name} |
Delete a project |
POST |
/projects/{name}/upload |
Upload raw text |
POST |
/projects/{name}/run |
Start the pipeline (supports resume) |
POST |
/projects/{name}/stop |
Signal a cooperative stop |
GET |
/projects/{name}/status |
File-based state, counts, progress |
GET |
/projects/{name}/data/{cleaned|chunks|qa} |
Inspect each stage |
GET |
/projects/{name}/export |
Export in a chosen format |
GET |
/llm/ollama/models |
Locally pulled Ollama models |
GET/POST |
/prompt/ |
Read / update the prompt template |
POST |
/scrape/start Β· /refine Β· /test_refinement Β· /cancel/{id} |
Crawl + LLM refinement |
GET |
/scrape/status/{id} Β· /preview/{project} Β· /download/{project} Β· /image/{project}/{name} |
Scrape results |
Finetune Lab β :8000 Β· docs at /docs
| Method | Path | Purpose |
|---|---|---|
POST |
/api/training/create |
Launch a run |
GET |
/api/training/status/{job_id} |
Live status, loss, logs |
GET |
/api/training/runs Β· /runs/{id} Β· /runs/{id}/checkpoints |
Run history |
POST/DELETE |
/api/training/stop/{id} Β· /runs/{id} |
Cancel / delete |
GET |
/api/models/ Β· /search/hf Β· /{model_id} |
Registry + HF search |
POST |
/api/models/upload |
Register a local model |
GET/POST |
/api/datasets/ Β· /upload Β· /validate Β· /search/hf |
Dataset intake + schema detection |
POST/GET |
/api/export/create Β· /status/{id} Β· /run/{id} Β· /list Β· /hf Β· /gguf |
Export jobs |
GET |
/api/hardware/gpus |
Detected CUDA devices |
Chat Lab β :8100 Β· docs at /docs
| Method | Path | Purpose |
|---|---|---|
GET |
/api/models/finetuned |
Runs with loadable weights on disk |
GET |
/api/models/base |
Base models from the Finetune Lab registry |
GET |
/api/models/status |
Resident models, GPU/VRAM snapshot, torch availability |
POST |
/api/models/load Β· /unload |
Warm / free a model |
POST |
/api/chat/stream |
SSE reply (meta/ready/start/token/done/error) |
POST |
/api/chat/stop |
Cancel an active stream |
POST |
/api/chat/compare |
One reply per target for the same prompt |
GET/POST/DELETE |
/api/conversations[...] |
CRUD + /{id}/export.md |
Dataset-Creator-App/
βββ install.py β Dataset Lab one-command installer
βββ datasetlab.py β Dataset Lab CLI (start/stop/status/open/logs)
βββ start.bat / start.sh β double-click / shell starters
βββ skill.md β the shared "control console" UI design system
βββ docs/demo/ β the animated demo above (demo.html + render_demo.py β demo.gif)
β
βββ dataset-lab/
β βββ backend/ β FastAPI: engines/ (chunking, cleaning, embedding_refiner,
β β generation, exporter, scraping/, processing/, labeling/),
β β llm/ (local, openai), routes/, formats/, prompts/
β βββ frontend/ β React 19 + Vite + Tailwind (Dashboard, Workspace, Scraping)
β βββ projects/ β generated: one folder of files per project
β βββ .venv / .logs / .env β created by the installer / on start
β
βββ finetune-lab/
β βββ backend/ β FastAPI: api/, core/ (training_engine, model_engine,
β β dataset_engine, hardware_engine), training/ (Unsloth runners),
β β job_engine/, workers/, validation/, model_registry/
β βββ frontend/ β wizard + run dashboard + loss chart
β βββ backend/storage/ β datasets/ Β· runs/<id>/final/ Β· exports/ Β· jobs.json
β
βββ chat-lab/
βββ backend/ β FastAPI: api/, engine/ (model_manager, inference,
β chat_format), services/ (run_registry, conversation_store)
βββ frontend/ β Chat Β· Compare Β· History Β· Presets
| Symptom | Cause | Fix |
|---|---|---|
Port 8000 / 5173 already in use |
Dataset Lab and Finetune Lab share both defaults | Run one at a time, or repoint one (--port, vite --port, VITE_API_URL) |
| Dataset Lab pipeline stuck in "Running" | Server died mid-run, lock file survived | Delete .running / .stop in dataset-lab/projects/<project>/ |
| Can't reach Ollama | Service not running | ollama run llama3, then check http://localhost:11434 |
torch.cuda.is_available() is False with an NVIDIA GPU |
CPU-only torch wheel β not a driver problem | nvidia-smi confirms the driver; pip show torch with no +cuXXX suffix confirms the wheel. Reinstall from the CUDA index (see Finetune Lab quick start) |
Launch β run immediately failed, log mentions unsloth/torch |
ML stack missing in the backend's env | Install torch (CUDA) + unsloth on the GPU box |
| OOM during training | Batch/seq too large | The runner auto-retries lighter (visible in the log); or lower batch/seq, or switch to QLoRA 4-bit |
| Hardware step shows "Reference GPUs" | No CUDA device detected | Expected β estimates still work, training needs a real GPU |
| Multi-GPU run won't launch | Needs accelerate + >1 CUDA device |
Single-GPU always works |
Form data requires "python-multipart" on boot |
Wrong interpreter | pip install python-multipart |
ModuleNotFoundError / npm error in Dataset Lab |
Deps drifted | python install.py again |
| Frontend loads, every call fails / CORS | Backend down or on another host | Start it, or set VITE_API_URL |
Dataset Lab crashed and you want to know why: python datasetlab.py logs.
| Lab | State |
|---|---|
| Dataset Lab | Stable. Full pipeline, resume/stop, scraping dashboard, three export formats. |
| Finetune Lab | Feature-complete, GPU validation in progress. All six methods implemented end-to-end on the canonical Unsloth runner with real step-based progress, live loss/VRAM/ETA and streaming logs; verified off-GPU (torch-free API boot, route table, eventβrecord translation, schema detection, config mapping). Remaining: validating real GPU runs β especially multi-GPU and Vision β via backend/validation/. |
| Chat Lab | v1, verified off-GPU. API boots torch-free; routes, model discovery and conversation CRUD tested; frontend builds and lints clean. Remaining: a real GPU chat/compare pass on a machine with the training stack. |
Roadmaps: finetune-lab/ROADMAP.md Β· dataset-lab/FUTURE_ENHANCEMENTS.md
All three frontends share one dark skeuomorphic "control console" language β a fixed top-left light source, true-black drop shadows, recessed troughs, glowing orange LEDs and terminal-green log surfaces. The complete kit (Tailwind config, CSS variables, shadow physics, component dictionary) is in skill.md, written so it can be dropped into another project wholesale.
python docs/demo/render_demo.py # β docs/demo/demo.gifdemo.html renders frame N deterministically from ?f=N, so the capture is reproducible; the script drives headless Chrome once per frame at 2Γ scale, downsamples with Lanczos, and encodes a single-global-palette GIF that diff-compresses to ~1 MB. Open it without the query string to watch it autoplay in a browser.
- Fork, then branch:
git checkout -b feature/awesome-thing - Match the existing style β backends are FastAPI + Pydantic, frontends are React 19 + Tailwind against the
skill.mdcomponent set. - Commit with clear messages, push, and open a PR describing what changed and why.
Found a bug? Open an issue.
MIT.
Dataset Lab β Finetune Lab β Chat Lab. Your documents, your model, your chat β all of it local.





