ailixir-api / HUGGINGFACE_FLOW.md
AILIXIR Bot
Auto-sync: 201d269f287526269b8ffded5f450ff36b46c740
907b200
|
Raw
History Blame Contribute Delete
7.12 kB
# 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)
```