Skip to content

Commit 4a68acf

Browse files
authored
Merge pull request #51 from BitPolito/qvac-integration
QVAC SDK integration
2 parents 2416485 + e63d8d7 commit 4a68acf

47 files changed

Lines changed: 4313 additions & 434 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ jobs:
7070
- name: Set up Node.js
7171
uses: actions/setup-node@v4
7272
with:
73-
node-version: "20"
73+
node-version: "22"
7474
cache: npm
7575
cache-dependency-path: apps/web/package-lock.json
7676

@@ -85,3 +85,27 @@ jobs:
8585

8686
- name: Run tests (Jest)
8787
run: npm test -- --ci --passWithNoTests
88+
89+
qvac-service:
90+
name: QVAC Service (Node.js)
91+
runs-on: ubuntu-latest
92+
93+
defaults:
94+
run:
95+
working-directory: workers/qvac-service
96+
97+
steps:
98+
- uses: actions/checkout@v4
99+
100+
- name: Set up Node.js
101+
uses: actions/setup-node@v4
102+
with:
103+
node-version: "22"
104+
cache: npm
105+
cache-dependency-path: workers/qvac-service/package-lock.json
106+
107+
- name: Install dependencies
108+
run: npm ci
109+
110+
- name: Run tests
111+
run: npm test

README.md

Lines changed: 180 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,13 @@ An open-source, local-first platform for structured Bitcoin education. Transform
1818

1919
### Prerequisites
2020

21-
- Node.js 18+
22-
- Python 3.10+
23-
- PostgreSQL (running and accessible)
21+
| Requirement | Version | Notes |
22+
|---|---|---|
23+
| Node.js | **≥ 22.17** | Required by `@qvac/sdk` (bare runtime shims). |
24+
| Python | 3.11 | For the FastAPI backend and ingestion pipeline. |
25+
| PostgreSQL | any recent | Running and accessible. |
26+
| Disk space | ~2 GB | For the QVAC embedding model (~670 MB) downloaded on first run. |
27+
| RAM | ≥ 8 GB | For the default LLM when one is configured (see QVAC docs). |
2428

2529
### Recommended
2630

@@ -31,21 +35,22 @@ chmod +x start-dev.sh
3135

3236
This script creates a Python virtualenv under `services/ai/venv/`, installs dependencies for both services, seeds the database with test users, and starts both servers.
3337

34-
| Service | URL |
35-
|---------------|----------------------------------------------|
36-
| Frontend | <http://localhost:3000> |
37-
| Backend API | <http://localhost:8000> |
38-
| Swagger UI | <http://localhost:8000/docs> |
39-
| ReDoc | <http://localhost:8000/redoc> |
38+
| Service | URL |
39+
|----------------|----------------------------|
40+
| Frontend | <http://localhost:3000> |
41+
| Backend API | <http://localhost:8000> |
42+
| QVAC service | <http://localhost:3001> |
43+
| Swagger UI | <http://localhost:8000/docs> |
44+
| ReDoc | <http://localhost:8000/redoc> |
4045

4146
> Swagger UI and ReDoc are only available in `development` environment.
4247
4348
**Dev credentials (seeded automatically):**
4449

45-
| Role | Email | Password |
46-
|---------|----------------------------|-----------------------|
47-
| Admin | admin@bitpolito.it | DevAdmin@2024!Secure |
48-
| Student | student@bitpolito.it | DevStudent@2024!Learn |
50+
| Role | Email | Password |
51+
|---------|----------------------|-----------------------|
52+
| Admin | admin@bitpolito.it | DevAdmin@2024!Secure |
53+
| Student | student@bitpolito.it | DevStudent@2024!Learn |
4954

5055
### Manual setup
5156

@@ -66,6 +71,15 @@ pip install -r requirements.txt
6671
python -m uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
6772
```
6873

74+
**QVAC service** (Node.js — embedding + retrieval + optional LLM generation):
75+
76+
```bash
77+
cd workers/qvac-service
78+
npm install
79+
node src/server.js
80+
# Downloads the embedding model (~670 MB) on first run, then listens on :3001
81+
```
82+
6983
---
7084

7185
## Project Structure
@@ -80,30 +94,43 @@ bitcoin-academy/
8094
│ ├── components/ # React components
8195
│ └── lib/ # API client, auth helpers, services
8296
├── services/
83-
│ └── ai/ # FastAPI backend (primary service)
97+
│ └── ai/ # FastAPI backend
8498
│ ├── Dockerfile
8599
│ └── app/
86-
│ ├── api/ # Route handlers (auth, courses, documents, progress)
87-
│ ├── workers/ # Document processing pipeline
88-
│ │ └── pipeline.py # parse → chunk → embed → index (runs as BackgroundTask)
89-
│ ├── services/ # Business logic
100+
│ ├── api/ # Route handlers (auth, chat, courses, documents, progress, quizzes, certificates)
101+
│ ├── workers/
102+
│ │ └── pipeline.py # parse → chunk → ChromaDB + QVAC ingest (BackgroundTask)
103+
│ ├── services/
104+
│ │ └── chat_service.py # Forwards /chat queries to the QVAC service via httpx
90105
│ ├── repositories/ # Data access layer
91106
│ ├── db/ # SQLAlchemy models and session
92-
│ ├── rag/ # LangChain RAG pipeline (chains, retrievers, prompts)
93107
│ ├── schemas/ # Pydantic request/response models
94108
│ ├── core/ # Config, DI container, error handling, token blacklist
95109
│ └── middleware/ # Request ID, security headers
96-
├── workers/ # Standalone pipeline script (reference / CLI testing)
97-
│ └── main.py
110+
├── workers/
111+
│ ├── python-ingester/ # Standalone Python ingestion pipeline (PDF/PPTX → JSONL)
112+
│ │ └── src/
113+
│ │ ├── module_1_ingestor.py # RamSafeIngestor — RAM-safe PDF/PPTX batch reader
114+
│ │ ├── module_2_parser.py # StructuralParser — hybrid pdfplumber + Docling ML
115+
│ │ ├── module_3_micro_chunker.py # VerilocalChunker — 3-level chunking (section/paragraph/micro)
116+
│ │ ├── module_4_exporter.py # JsonlExporter — writes *_contingency.jsonl
117+
│ │ ├── retrieval_*.py # ChromaDB embedder + searcher + benchmark
118+
│ │ └── main_ingester_pipeline.py # CLI entry point
119+
│ └── qvac-service/ # Node.js service — QVAC SDK (embedding + HyperDB + LLM)
120+
│ └── src/
121+
│ ├── models.js # loadModel lifecycle (GTE_LARGE_FP16 embedding; LLM placeholder)
122+
│ ├── ingest.js # ragIngest — reads *_contingency.jsonl, indexes paragraph chunks
123+
│ ├── query.js # ragSearch + optional completion
124+
│ └── server.js # HTTP server on :3001 — POST /ingest, POST /query, GET /health
98125
├── docs/
99-
── examples/
100-
└── prototype/ # Original in-memory API prototype (reference only)
126+
── qvac-integration.md # Step-by-step guide for the QVAC SDK integration
127+
│ └── src/ # Source PDFs and PPTX used in tests
101128
├── .github/
102129
│ └── workflows/
103130
│ └── ci.yml # CI: pytest + mypy + tsc + jest on every PR
104-
├── docker-compose.yml # Full stack: postgres + api + web
105-
├── start-dev.sh # Dev startup script (no Docker required)
106-
└── package.json # Root workspace (npm workspaces: apps/*, services/*)
131+
├── docker-compose.yml
132+
├── start-dev.sh
133+
└── package.json # Root workspace (npm workspaces: apps/*, workers/qvac-service)
107134
```
108135

109136
---
@@ -112,26 +139,46 @@ bitcoin-academy/
112139

113140
### Frontend (`apps/web`)
114141

115-
| Technology | Role |
116-
|----------------|-------------------------------|
117-
| Next.js 14 | React framework, App Router |
118-
| TypeScript | Type safety |
119-
| Tailwind CSS | Styling |
120-
| NextAuth.js 4 | Session-based authentication |
121-
| Jest + RTL | Unit and integration tests |
142+
| Technology | Role |
143+
|---------------|------------------------------|
144+
| Next.js 14 | React framework, App Router |
145+
| TypeScript | Type safety |
146+
| Tailwind CSS | Styling |
147+
| NextAuth.js 4 | Session-based authentication |
148+
| Jest + RTL | Unit and integration tests |
122149

123150
### Backend (`services/ai`)
124151

125-
| Technology | Role |
126-
|---------------------|-----------------------------------------|
127-
| FastAPI | Async HTTP framework |
128-
| SQLAlchemy 2 | ORM |
129-
| Pydantic v2 | Data validation and serialization |
130-
| python-jose + bcrypt| JWT authentication |
131-
| LangChain + OpenAI | RAG pipeline for AI tutoring |
132-
| PostgreSQL | Primary database |
133-
| slowapi | Rate limiting |
134-
| pytest | Test suite |
152+
| Technology | Role |
153+
|----------------------|-----------------------------------------------|
154+
| FastAPI | HTTP framework |
155+
| SQLAlchemy 2 | ORM |
156+
| Pydantic v2 | Data validation and serialization |
157+
| python-jose + bcrypt | JWT authentication |
158+
| httpx | HTTP client — calls the QVAC service for chat |
159+
| ChromaDB | Vector store used during document ingestion |
160+
| fastembed | Embedding during ingestion (all-MiniLM-L6-v2) |
161+
| PostgreSQL | Primary database |
162+
| slowapi | Rate limiting |
163+
| pytest | Test suite |
164+
165+
### QVAC service (`workers/qvac-service`)
166+
167+
| Technology | Role |
168+
|---------------|-------------------------------------------------------------------|
169+
| Node.js 22.17+| Runtime |
170+
| `@qvac/sdk` | Local-first AI — embedding, HyperDB vector store, LLM generation |
171+
| `node:test` | Built-in test runner |
172+
173+
### Document ingestion pipeline (`workers/python-ingester`)
174+
175+
| Technology | Role |
176+
|--------------------|---------------------------------------------------|
177+
| pdfplumber | Primary PDF parser |
178+
| Docling | ML-based parser — flag `--docling` |
179+
| python-pptx | PPTX parser |
180+
| fastembed | Paragraph-level embedding (all-MiniLM-L6-v2 ONNX) |
181+
| ChromaDB | Persistent vector store |
135182

136183
---
137184

@@ -146,9 +193,34 @@ DATABASE_URL=postgresql://user:password@localhost:5432/bitcoin_academy
146193
SECRET_KEY=your-secret-key
147194
ENVIRONMENT=development
148195
CORS_ORIGINS=http://localhost:3000
196+
197+
# QVAC service (default: http://localhost:3001)
198+
QVAC_SERVICE_URL=http://localhost:3001
199+
200+
# Directory where the pipeline writes JSONL files for QVAC ingestion
201+
# (default: services/ai/qvac_ingest/)
202+
QVAC_INGEST_DIR=/absolute/path/to/qvac_ingest
203+
204+
# ChromaDB path (default: services/ai/chroma_db/)
205+
CHROMA_DB_PATH=/absolute/path/to/chroma_db
149206
```
150207

151-
`DATABASE_URL` and `SECRET_KEY` are required at startup — the app will crash without them.
208+
`DATABASE_URL` and `SECRET_KEY` are required at startup.
209+
210+
**QVAC service** — environment variables (optional):
211+
212+
```env
213+
# Override the LLM model — any of the four modelSrc options in qvac-integration.md
214+
# Default: QWEN3_4B_INST_Q4_K_M from the QVAC registry (~2.4 GB, requires ≥ 8 GB RAM)
215+
# Leave unset to run without an LLM (embedding + retrieval only)
216+
QVAC_LLM_SRC=/path/to/local/model.gguf
217+
218+
# Override the embedding model (default: GTE_LARGE_FP16, ~670 MB)
219+
QVAC_EMB_SRC=
220+
221+
# Port (default: 3001)
222+
QVAC_PORT=3001
223+
```
152224

153225
**Frontend** — create `apps/web/.env.local`:
154226

@@ -175,27 +247,74 @@ npm run format # Prettier
175247

176248
```bash
177249
cd services/ai
178-
mypy . # Type checking
179-
pytest # All tests
180-
pytest tests/unit -v # Unit tests with coverage
181-
pytest tests/integration # Integration tests
250+
pytest # All tests (excludes slow)
251+
pytest tests/unit -v # Unit tests
252+
pytest tests/integration # Integration tests
253+
pytest -m slow # Pipeline e2e (requires fastembed + chromadb)
254+
mypy .
255+
```
256+
257+
**QVAC service only:**
258+
259+
```bash
260+
cd workers/qvac-service
261+
npm test # node:test unit suite (no model download)
262+
node src/server.js # Start service — downloads models on first run
263+
```
264+
265+
**Ingestion pipeline (CLI):**
266+
267+
```bash
268+
cd workers/python-ingester
269+
# Index a document into both ChromaDB and QVAC (QVAC service must be running)
270+
python src/main_ingester_pipeline.py lecture.pdf \
271+
--course-id BTC_2025 --lecture-id L01 --docling
272+
```
273+
274+
### Document ingestion flow
275+
276+
```
277+
Upload via API CLI (direct)
278+
│ │
279+
▼ ▼
280+
pipeline.py (BackgroundTask) main_ingester_pipeline.py
281+
282+
├─ RamSafeIngestor + StructuralParser (PDF/PPTX → blocks)
283+
├─ VerilocalChunker (section / paragraph / micro)
284+
├─ fastembed + ChromaDB (paragraph chunks → vector store)
285+
├─ Write *_contingency.jsonl to QVAC_INGEST_DIR
286+
└─ POST http://localhost:3001/ingest ←── QVAC service
287+
└─ ragIngest → HyperDB workspace
288+
```
289+
290+
### Chat query flow
291+
292+
```
293+
Student question
294+
→ POST /api/courses/{id}/chat (FastAPI, JWT required)
295+
→ chat_service.py
296+
→ POST http://localhost:3001/query (QVAC service)
297+
└─ ragSearch (HyperDB) → optional LLM completion
298+
→ ChatResponse { answer, citations: [{snippet, score}], retrieval_used }
182299
```
183300

184301
---
185302

186303
## API
187304

188-
Registered routers in `services/ai/app/main.py`:
305+
All routers registered in `services/ai/app/main.py`:
189306

190-
| Prefix | Description |
191-
|--------------|------------------------------|
192-
| `/auth` | Registration, login, JWT |
193-
| `/courses` | Course CRUD |
194-
| `/documents` | PDF upload and indexing |
195-
| `/progress` | User progress tracking |
196-
| `/health` | Health check with DB ping |
307+
| Prefix | Description |
308+
|-------------------------------|-------------------------------------|
309+
| `/api/auth` | Registration, login, JWT refresh |
310+
| `/api/courses/{id}/chat` | RAG-backed Q&A (QVAC service) |
311+
| `/api/courses` | Course CRUD and lesson listing |
312+
| `/api/courses/{id}/documents` | PDF/PPTX upload and indexing |
313+
| `/api/users/me/...` | Progress tracking and certificates |
314+
| `/api/quizzes` | Quiz placeholders (not yet active) |
315+
| `/health` | Health check with DB ping |
197316

198-
> **Implemented but not yet registered:** `quizzes_api.py`, `chat_api.py`, `certificates_api.py` exist in `app/api/` but are not included in `app/main.py`.
317+
Full interactive reference: `http://localhost:8000/docs` (development only).
199318

200319
---
201320

@@ -208,9 +327,10 @@ Registered routers in `services/ai/app/main.py`:
208327

209328
**Guidelines:**
210329

211-
- TypeScript for frontend, Python for backend
212-
- Run `npm run type-check` and `pytest` before opening a PR
213-
- Update this README if you change the project structure or add new routes
330+
- TypeScript for frontend, Python for backend, JavaScript (ESM) for the QVAC service
331+
- Run `npm run type-check`, `pytest`, and `npm test` (in `workers/qvac-service`) before opening a PR
332+
- Node.js ≥ 22.17 is required — earlier versions will fail on `import "@qvac/sdk"`
333+
- Update this README if you change the project structure, add new routes, or modify the startup sequence
214334

215335
---
216336

0 commit comments

Comments
 (0)