trainhub-api / README.md
Taimwe's picture
Add Space config (docker, port 7860)
f16f8f7 verified
|
Raw History Blame Contribute Delete
4.72 kB
---
title: TrainHub API
emoji: 🚂
colorFrom: indigo
colorTo: purple
sdk: docker
app_port: 7860
pinned: false
short_description: Self-hosted AI training platform backend (FastAPI)
---
# TrainHub API
A self-hosted AI training platform backend, modelled on the Hugging Face Hub.
**Stack:** FastAPI · SQLAlchemy (SQLite) · JWT auth · NumPy training worker · file storage · Hugging Face Hub bridge.
| Capability | Status |
|---|---|
| User registration / login (JWT) | ✅ real, persistent |
| Model / Dataset / Space repos (CRUD, likes) | ✅ real, persistent |
| File upload / list / download (disk + DB) | ✅ real |
| Training jobs (queue → run → metrics → complete) | ✅ real (NumPy backprop; swap in TRL for real models) |
| Hugging Face Hub search + model import | ✅ real (proxies hf.co) |
| Interactive API docs | ✅ `/docs` |
---
## Run locally
```bash
pip install -r requirements.txt
uvicorn app.main:app --reload --port 8000
# open http://localhost:8000/docs
```
## Run with Docker
```bash
docker build -t trainhub-api .
docker run -p 7860:7860 -e SECRET_KEY=secret -v $(pwd)/storage:/app/storage trainhub-api
```
## Deploy to Hugging Face Spaces
This repo is a `docker`-SDK Space. Push to `main` and it builds automatically at
`https://huggingface.co/spaces/Taimwe/trainhub-api`.
> **Custom domain (you own a domain):** in the Space settings open **Settings → Custom
> domain**, add e.g. `api.yourdomain.com`, then in your DNS create a `CNAME` from
> `api.yourdomain.com` → `Taimwe-trainhub-api.hf.space` (or the Space's `.hf.space`
> hostname). For a root domain (`yourdomain.com`) you need an `ALIAS`/`ANAME` record or
> a proxy; refer to your DNS provider. Custom domains require a paid HF plan + an
> HF token set on the Space.
## Environment variables
| Var | Default | Purpose |
|---|---|---|
| `SECRET_KEY` | `dev-secret-change-me` | JWT signing key — **change in prod** |
| `ACCESS_TOKEN_EXPIRE_MINUTES` | `1440` | token lifetime |
| `DATABASE_URL` | `sqlite:///./trainhub.db` | SQLAlchemy URL (Postgres works too) |
| `STORAGE_DIR` | `./storage` | where uploaded files land |
| `HF_TOKEN` | — | optional, raises Hub rate limits / enables private access |
---
## API quick tour
Base URL: `http://localhost:8000` (or your Space/domain).
### Auth
```
POST /auth/register {"username","email","password"} -> {access_token, user}
POST /auth/login {"username","password"} -> {access_token, user}
```
Send the token as `Authorization: Bearer <token>`.
### Models / Datasets / Spaces
```
POST /models {"name","description","pipeline_tag","tags","license"}
GET /models?search=&owner=
GET /models/{id}
PATCH /models/{id}
DELETE /models/{id}
POST /models/{id}/like
POST/GET/PATCH/DELETE /datasets (same pattern)
POST/GET/DELETE /spaces
```
### Files
```
POST /files/model/{id} multipart "file" -> upload
GET /files/model/{id} -> list
GET /files/model/{id}/{filename} -> download (streamed)
```
`dataset` works the same way (`/files/dataset/{id}`).
### Training jobs
```
POST /jobs {"base_model","dataset","config":{"epochs","lr","batch_size","seed"}}
GET /jobs
GET /jobs/{id}
GET /jobs/{id}/metrics -> [{epoch, loss}, ...] (loss genuinely decreases)
POST /jobs/{id}/cancel
```
Jobs run in a background thread and persist status + loss history to the DB.
### Hugging Face Hub bridge
```
GET /hub/search?q=llama -> real models from hf.co
POST /hub/import {"repo_id"} -> import metadata into your local models
```
### Meta
```
GET /health GET /stats GET /
```
---
## Fine-tuning real models
The worker in `app/services/training.py` trains a small MLP with NumPy so the whole
stack runs anywhere with zero GPU. To fine-tune actual models, replace
`_run()` with a `transformers`/`TRL` call, e.g.:
```python
from transformers import AutoModelForCausalLM, Trainer, TrainingArguments
model = AutoModelForCausalLM.from_pretrained(job.base_model)
trainer = Trainer(model=model, args=TrainingArguments(..., report_to=[]), train_dataset=ds)
for step in trainer.train(): # or a custom training loop
... # write loss to job.metrics each step, db.commit()
```
Point `base_model` at your HF model id (`Taimwe/...` or any public id) and add
`torch`/`trl` to `requirements.txt`.
## Notes
- Single-process design (threads) is ideal for a self-hosted box. To scale to many
workers, replace `services/training.py` with a Celery/Redis or Kubernetes job runner
and keep the same REST contract.
- SQLite is the default for simplicity; set `DATABASE_URL` to Postgres for production.
- `CORS` is wide open for local frontends; tighten `allow_origins` in production.