# AILIXIR Hugging Face Spaces — Migration Flow > **Base commit:** `fd94aa0` — pre-HF, Docker Compose with MySQL+Redis --- ## 1. Why Hugging Face Spaces? | Need | Solution | |------|----------| | Free hosting for 5 microservices | 5 HF Spaces (2 accounts to keep more awake) | | No MySQL/Redis infrastructure | SQLite for storage, `database` queue driver | | Simple CI/CD | GitHub Actions auto-syncs code to each HF Space | | Binary model files | Git LFS + Xet storage on HF | --- ## 2. Architecture Decisions ### SQLite over MySQL - **Why:** HF Spaces provide ephemeral storage; SQLite has zero dependencies - **Trade-off:** No concurrent write scaling; fine for single-user/small-team usage - **DB Location:** `database/ailixir.sqlite` (mounted in the container) - **Migrations:** Run automatically via `entrypoint.sh` on startup ### Two HF Accounts - **`Ailixir-AI-Team`**: Backend API - **`RottenShadow`**: Chemical RAG, Drug Repurposing - **`shdwRow`** (secondary): ADMET, Generation - **Why:** HF Spaces free tier puts unused spaces to sleep; spreading across 2 accounts keeps more services warm ### Queue: `sync` driver - **Why:** No need for Redis/DB-backed queue worker; jobs run inline - **Note:** For production scale, switch back to `database` and run a queue worker ### Binary Model Files: Git LFS + Xet - **Why:** HF rejects large files in raw Git; Xet provides efficient binary storage - **Tracked:** `*.ckpt`, `*.pt`, `*.pkl` --- ## 3. Per-Service Details ### Backend API (`Ailixir-AI-Team/ailixir-api`) - **Tech:** Laravel 12 + PHP 8.3 CLI - **Port:** 7860 (HF default) - **Dockerfile:** Multi-stage (composer → vite → runtime) - **Entrypoint:** Sources `RUN_MODE=hf` → starts supervisord (laravel serve + queue worker) - **Fixes applied:** - `config/view.php` — explicit compiled path (fixes 500 on `/`) - `bootstrap/app.php` — `trustProxies(at: '*')` (fixes mixed-content CSS) - `config/scribe.php` — `docs_url` moved to `/scribe-docs` - `/docs` route — serves rendered `API.md` (curl examples, responses, grouped) - `QUEUE_CONNECTION=sync` — no worker needed ### ADMET Prediction (`shdwRow/ailixir-admet`) - **Tech:** FastAPI + PyTorch - **Port:** 7860 - **Model:** `best_model.ckpt` (LFS-tracked) - **Sync:** Xet-enabled checkout in workflow ### Chemical RAG (`RottenShadow/ailixir-chemical-rag`) - **Tech:** FastAPI + ChromaDB - **Port:** 7860 ### Drug Repurposing (`RottenShadow/ailixir-drug-repurposing`) - **Tech:** FastAPI + DeepPurpose - **Port:** 7860 - **Special:** `Dockerfile.hf` with mock-mode fallback ### Generation (`shdwRow/ailixir-generation`) - **Tech:** FastAPI + REINVENT4 + RDKit + DeepPurpose (optional) - **Port:** 7860 - **Fixes applied:** - **REINVENT4** — git cloned and `install.py cpu` in `Dockerfile.hf` - **libXrender** — `libxrender1 libxext6` added (RDKit image rendering) - **DeepPurpose** — optional install; integrated `/reinvent_predict` route on same port 7860 - **Graceful fallback** — if DeepPurpose unavailable, enrichment returns null affinity values - **Enrichment** — catches connection errors, sets `pred_pAff_mean` to `None` --- ## 4. Sync Workflow **File:** `.github/workflows/sync-hf-all.yml` ### Trigger - Push to `main` branch - Manual dispatch via GitHub UI ### Jobs (5 total) | Job | HF Space | Account | Token | Notes | |-----|----------|---------|-------|-------| | `backend` | `ailixir-api` | Ailixir-AI-Team | `HF_TOKEN_AILIXIR` | Excludes `ai_apps/`, `database/ailixir.sqlite`, `storage/` | | `drug-repurposing` | `ailixir-drug-repurposing` | RottenShadow | `HF_TOKEN` | Renames `Dockerfile.hf` → `Dockerfile` | | `admet` | `ailixir-admet` | shdwRow | `HF_TOKEN_SHDWROW` | LFS + Xet for `.ckpt` | | `chemical-rag` | `ailixir-chemical-rag` | RottenShadow | `HF_TOKEN` | | | `generation` | `ailixir-generation` | shdwRow | `HF_TOKEN_SHDWROW` | LFS + Xet for `.ckpt`, `.pt`, `.pkl` | ### How each job works 1. Clone the HF Space repo (shallow, depth 1) 2. `rsync -av --delete` — sync files from main repo, delete files removed in source 3. Write `.env` with all required vars 4. Rename `Dockerfile.hf` → `Dockerfile` if present 5. Setup LFS/Xet for model files (ADMET, Generation) 6. Commit and push to HF Space ### Key exclusions (backend job) ``` --exclude=ai_apps --exclude=.git --exclude=.env --exclude=.dockerignore --exclude=public/imgs --exclude=storage --exclude=Diagrams --exclude=database/ailixir.sqlite ``` ### Required GitHub Secrets | Secret | Used by | |--------|---------| | `HF_TOKEN` | drug-repurposing, chemical-rag | | `HF_TOKEN_AILIXIR` | backend | | `HF_TOKEN_SHDWROW` | admet, generation | | `GOOGLE_CLIENT_ID` | backend .env | | `GOOGLE_CLIENT_SECRET` | backend .env | --- ## 5. Environment Variables (`.env` written by sync) ``` RUN_MODE=hf APP_KEY=base64:... AI_INTEGRATION_ROUTES_ENABLED=true APP_URL=https://Ailixir-AI-Team-ailixir-api.hf.space APP_DEBUG=true QUEUE_CONNECTION=sync ADMET_AI_URL=https://shdwRow-ailixir-admet.hf.space CHEMICAL_AI_URL=https://RottenShadow-ailixir-chemical-rag.hf.space DRUG_REPURPOSING_URL=https://RottenShadow-ailixir-drug-repurposing.hf.space GENERATION_SERVICE_URL=https://shdwRow-ailixir-generation.hf.space GOOGLE_CLIENT_ID=... GOOGLE_CLIENT_SECRET=... GOOGLE_REDIRECT_URI=https://Ailixir-AI-Team-ailixir-api.hf.space/api/user/auth/google CLOUDINARY_CLOUD_NAME=dummy_cloud CLOUDINARY_API_KEY=dummy_key CLOUDINARY_API_SECRET=dummy_secret ``` --- ## 6. Database Protection The sync workflow **excludes** `database/ailixir.sqlite` from rsync and runs `git checkout HEAD -- database/ailixir.sqlite` before commit to prevent the live database from being pushed to git. On HF Spaces, the database file persists across restarts (HF Spaces keep filesystem between restarts) but is **reset** when the Space rebuilds (code push). --- ## 7. Known Issues & Future Work | Issue | Status | Resolution | |-------|--------|------------| | DeepPurpose on Python 3.10 | Unstable | Falls back to null affinity predictions; could switch to conda base image | | Google OAuth secrets | Not set | Needs `GOOGLE_CLIENT_ID` / `GOOGLE_CLIENT_SECRET` added to GitHub secrets | | Space sleep on free tier | Ongoing | Two-account setup mitigates; upgrade to HF Pro for always-on | | Cloudinary credentials | Dummy values | Set real Cloudinary keys for image upload features | | ADMET model files in Xet | Working | Large `.ckpt` files stored via HF Xet | | Docs route `/docs` | Working | Serves rendered `API.md` with all examples and grouping | --- ## 8. Commit History (cleaned) ``` c49c94f Add HF Spaces sync workflow with two-account setup, DB protection 30f0a11 Generation HF: REINVENT4, DeepPurpose, libXrender, graceful fallback a342297 AI microservices HF: ports 8000→7860, Dockerfiles, README_HF af62962 Backend HF fixes: trustProxies, view cache path, docs route with API.md fd80b74 Add HF Spaces environment config, deployment guide, and changelog b4a5d77 Foundation: migrate MySQL→SQLite, add supervisor, port 7860, APP_KEY auto-gen fd94aa0 Limit Docker Compose build parallelism in CI (original base) ```