# GOLS – Hire2Exit · AI Avatar Video System

> Generate photorealistic lip-synced avatar videos from a photo and a script.

---

## ✅ Quick Start (3 steps)

```bash
# 1. Install
cd backend
python -m venv .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate
pip install -r requirements.txt
pip install gtts                 # TTS engine (already in requirements)

# 2. Configure
cp .env.example .env             # edit JWT_SECRET at minimum

# 3. Run
cd ..
python run.py
```

Open **http://localhost:8000** · Login: `admin` / `admin123`

---

## 🎥 How Video Generation Works

The pipeline runs as a **FastAPI BackgroundTask** — no Celery, no Redis needed.

```
Photo/Video + Script
        │
        ▼
  [1] gTTS / Piper            → voice.mp3   (always works, no model needed)
        │
        ▼
  [2] FFmpeg (image + audio)  → base.mp4    (always works)
        │
        ▼
  [3] LivePortrait (optional) → animated.mp4  (install model to enable)
        │
        ▼
  [4] Wav2Lip (optional)      → lipsync.mp4   (install model to enable)
        │
        ▼
  [5] CodeFormer (optional)   → enhanced.mp4  (install model to enable)
        │
        ▼
  [6] FFmpeg + Watermark      → avatar_XXXX.mp4  ← downloadable
```

Stages 3–5 are **gracefully skipped** if their model paths don't exist.
A working video is always produced using stages 1, 2, and 6.

---

## 🐛 Why was it stuck in queue? (Fixed)

The old code had:
```python
# TODO: dispatch to Celery: generate_video.delay(pid)
return ok({"status": "queued"})   # ← nothing actually ran
```

The fix:
```python
background_tasks.add_task(run_pipeline, pid)   # ← actually runs
```

Now `POST /api/projects/{id}/generate` dispatches `run_pipeline()` immediately
as a background thread. The frontend polls `GET /api/projects/{id}/status`
every 2.5 seconds to update the progress bar live.

---

## 📂 Storage Directories

| Directory | Purpose |
|-----------|---------|
| `backend/uploads/` | Source photos/videos uploaded when creating an avatar |
| `backend/data/` | JSON database files (avatars, projects, videos, settings) |
| `backend/outputs/` | Generated MP4 videos — download via the ⬇ button |

---

## ⬇ Download Button

Works on **Projects**, **Videos**, and **Dashboard** pages.
Uses `fetch()` with the `Authorization: Bearer <token>` header, converts response
to a Blob, and triggers a browser download — no extra auth step needed.

---

## 🌊 Watermark

Toggle in **Settings → Output → Video Watermark**.
When enabled, FFmpeg burns "GOLS Hire2Exit" text into the bottom-right corner
of every generated video. Setting is stored in `data/settings.json`.

---

## 🔐 Authentication

- Static admin: set `ADMIN_USERNAME` and `ADMIN_PASSWORD` in `.env`
- JWT token (8-hour expiry) in `localStorage`
- All API routes require `Authorization: Bearer <token>`
- No registration, no forgot-password — admin-only system

---

## 📁 Project Structure

```
gols-v2/
├── run.py                          ← PyCharm one-click start
├── backend/
│   ├── main.py                     ← FastAPI app + static mounts
│   ├── requirements.txt
│   ├── .env.example
│   └── app/
│       ├── config.py               ← All settings from .env
│       ├── middleware/auth.py      ← JWT guard + request logging
│       ├── repository/store.py     ← JSON repository (swap for SQLAlchemy here)
│       ├── services/pipeline.py    ← Full video generation pipeline
│       ├── routes/                 ← auth, avatars, projects, videos, analytics, settings
│       ├── schemas/schemas.py      ← Pydantic request/response models
│       └── utils/                  ← jwt, logger, response helpers
└── frontend/
    ├── login.html
    ├── dashboard.html
    ├── studio.html
    ├── projects.html               ← Live progress polling + download
    ├── videos.html                 ← Grid/list view + download
    ├── analytics.html
    ├── settings.html               ← Watermark toggle + storage guide
    └── static/
        ├── css/app.css             ← Full design system
        ├── css/login.css           ← Animated login
        └── js/
            ├── api.js              ← HTTP client + pollProject()
            ├── ui.js               ← Toast, modal, pagination
            └── sidebar.js          ← Shared sidebar (injected per page)
```

---

## 🗃️ Database Migration (JSON → PostgreSQL)

Only `backend/app/repository/store.py` does any I/O.

```python
# Current (JSON):
class Store:
    def create(self, data): ...   # writes to .json file
    def get(self, id): ...
    def list(self, ...): ...
    def update(self, id, data): ...
    def delete(self, id): ...

# Future (SQLAlchemy) — same interface, different internals:
class Store:
    def create(self, data): db.add(Model(**data)); db.commit()
    def get(self, id): return db.query(Model).filter_by(id=id).first()
    ...
```

Routes, schemas, middleware, and services stay **100% unchanged**.

---

## 🔧 Environment Variables

```env
ADMIN_USERNAME=admin
ADMIN_PASSWORD=admin123
JWT_SECRET=change-this-in-production

# Storage (absolute paths auto-resolved)
DATA_DIR=...
UPLOAD_DIR=...
OUTPUT_DIR=...

# AI Models (install models and set these paths)
FFMPEG_PATH=ffmpeg
LIVEPORTRAIT_PATH=models/liveportrait
WAV2LIP_PATH=models/wav2lip
CODEFORMER_PATH=models/codeformer

# External APIs (optional)
ELEVENLABS_KEY=
HEYGEN_KEY=
DID_KEY=
```

---

## 🚀 Pages

| Page | URL | Features |
|------|-----|---------|
| Login | `/login.html` | Animated dark panel + JWT login |
| Dashboard | `/dashboard.html` | Stats, recent projects/videos |
| AI Studio | `/studio.html` | Upload → script → generate → live progress → download |
| Projects | `/projects.html` | CRUD table, live progress bars, download button |
| Videos | `/videos.html` | Grid/list view, download all |
| Analytics | `/analytics.html` | Status charts, pipeline health |
| Settings | `/settings.html` | Engines, API keys, watermark, storage guide |
| API Docs | `/api/docs` | FastAPI Swagger UI |
