Self-hosted annotation platform for Star Citizen localization. Provides collaborative NER annotation with RBAC, review workflows, and VerseBridge integration — features that Label Studio locks behind a paid tier.
Stack: FastAPI + React/TypeScript (MUI, MobX) + PostgreSQL (async SQLAlchemy + asyncpg)
The fastest way to run VerseLab — no need to install Python, Node.js, or PostgreSQL.
Prerequisites: Docker and Docker Compose
# First time: build and start database + backend with hot-reload
docker compose -f docker-compose.dev.yml up -d --build
# After code changes: rebuild
docker compose -f docker-compose.dev.yml build && docker compose -f docker-compose.dev.yml up -d
# View logs
docker compose -f docker-compose.dev.yml logs -f backend
# Stop without destroying network
docker compose -f docker-compose.dev.yml stop
# In a separate terminal — start frontend with HMR
cd frontend && npm install && npm run dev- API: http://localhost:8000/docs (Swagger)
- UI: http://localhost:5173
# 1. Clone the repo
git clone <repo-url> && cd VerseLab
# 2. Create .env from template
cp .env.example .env
# 3. Set secure values
nano .env.env contents:
DB_PASSWORD=your-strong-database-password
SECRET_KEY=generate-with-python-see-belowGenerate a secret key:
python3 -c "import secrets; print(secrets.token_urlsafe(64))"# 4. Build and start all services (first time)
docker compose up -d --build
# Restart after code changes (rebuild without recreating network)
docker compose build && docker compose up -d
# Stop / start without destroying network
docker compose stop
docker compose startThe app will be available at http://<your-server-ip> (port 80).
By default, Docker binds to 0.0.0.0, so the app is accessible from any machine on the network.
-
Find your server IP:
# On the server ip addr show | grep "inet " # or hostname -I
-
Open firewall ports (if firewall is enabled):
# UFW (Ubuntu/Debian) sudo ufw allow 80/tcp # production (nginx serves frontend + proxies API) # firewalld (CentOS/RHEL) sudo firewall-cmd --permanent --add-port=80/tcp sudo firewall-cmd --reload
-
Access from other computers:
- Production:
http://<server-ip>
- Production:
-
(Optional) Custom domain: Point a domain to your server IP and set up a reverse proxy (nginx/Caddy) with SSL.
If you prefer running services directly:
# Install
sudo apt update && sudo apt install postgresql postgresql-contrib
sudo service postgresql start
# Create database
sudo -u postgres psql -c "CREATE DATABASE verselab_db;"
sudo -u postgres psql -c "ALTER USER postgres PASSWORD 'postgres';"cd backend
cp .env.example .env # edit .env with your DB credentials
uv sync # install dependencies
uv run uvicorn app.main:app --reloadAPI: http://localhost:8000/docs
cd frontend
npm install
npm run devVerseLab/
├── docker-compose.yml # production (db + backend + frontend/nginx)
├── docker-compose.dev.yml # development (db + backend with hot-reload)
├── .env.example # environment variables template
│
├── backend/ # FastAPI application
│ ├── Dockerfile
│ ├── app/
│ │ ├── main.py # app entrypoint, lifespan, routers
│ │ ├── config.py # pydantic-settings (.env loader)
│ │ ├── database.py # async SQLAlchemy engine
│ │ ├── models.py # ORM models
│ │ ├── schemas.py # Pydantic schemas
│ │ ├── security.py # JWT auth, Argon2 password hashing
│ │ ├── permissions.py # RBAC checks
│ │ └── routers/
│ │ ├── auth.py # register, login
│ │ ├── users.py # user management
│ │ ├── organizations.py
│ │ ├── projects.py # NER / TRANSLATION projects
│ │ └── tasks.py # annotation tasks
│ └── pyproject.toml
│
└── frontend/ # React application
├── Dockerfile
├── nginx.conf # production nginx config
└── src/
├── api/ # axios client
├── components/ # UI components, editors
├── pages/ # Dashboard, Auth, Workspace, etc.
├── routes/ # routing, protected routes
└── store/ # MobX stores
- Tables are created automatically on first backend start (
Base.metadata.create_all) - Data persists across restarts (Docker named volume
pgdata) - To reset the database:
docker compose down -v(deletes all data) - Recommended GUI clients: DBeaver (free), pgAdmin, DataGrip (paid)
Connection settings for GUI clients:
| Parameter | Value |
|---|---|
| Host | localhost |
| Port | 5432 |
| Database | verselab_db |
| User | postgres |
| Password | value from .env (postgres for dev) |
VerseLab is part of the sc_localization ecosystem. It replaces the Streamlit annotation UI in VerseBridge's NER pipeline.
VerseBridge (extract) VerseLab (annotate/review) VerseBridge (train/translate)
───────────────────── ──────────────────────── ─────────────────────────────
NER extraction Import → Annotate → Review BIO conversion → Training
│ ▲ │ ▲
▼ │ ▼ │
ner_unannotated.json ──────► POST /import GET /export ──────► dataset_corrected.json
[
{
"id": "key_name",
"text": "cleaned text string",
"entities": [
{"start": 0, "end": 5, "label": "PER"}
]
}
]Standard: PER, ORG, MISC, GPE, FAC, LOC, PRODUCT, EVENT, QUANTITY, DATE, MONEY
Game-specific: SHIP, ARMOR, WEAPON
- Corrected entities → BIO conversion (token-level labels)
- BIO data → fine-tune NER model (roberta-large-ner-english)
- Fine-tuned model → extract entities from new text
- Entities → regex patterns → placeholders (
<N_0>,<N_1>) - Placeholders protect game terms during MADLAD-400 translation
- After translation, placeholders are restored to original terms