youtube-ai-learning-assistant

TV2 — Bản bàn giao tích hợp để review

Phạm vi và tình trạng

Thực hiện mục 5 trong docs/project-management/phan_cong_chi_tiet.txt trên nhánh feat/tv2-service-skeleton. Nhánh đã đối chiếu với origin/main ngày 09/09/2026. Không có thay đổi trong source TV1/TV3/TV4 hoặc shared/contracts/.

Đây là bản service chạy/test độc lập để review. Schema dùng chung và dependency chưa được nhóm phê duyệt. Không được ghi nhận hoàn thành tích hợp RAG hoặc E2E.

Các endpoint

Method/path (sau /api/v1) Input Output
GET /health không body 200 ready hoặc 503 not_ready kèm SERVICE_NOT_READY
POST /videos/{videoId}/index video, transcriptSegments 200 cached/ready/chunkCount hoặc 202 indexing
GET /videos/{videoId}/index-status không body not_indexed/indexing/ready/failed
POST /videos/{videoId}/retrieve query, purpose, maxResults? videoId, purpose, chunks; rỗng có NO_RELEVANT_CONTEXT
POST /videos/{videoId}/assessments/quiz questions, userAnswers, quizId? score, counts, questionResults, topics, reviewTimestamps
DELETE /videos/{videoId}/cache không body videoId, deleted, deletedChunkCount

Request/response dùng camelCase. Schema chi tiết được sinh từ models.py qua /openapi.json, giúp reviewer đối chiếu trực tiếp với route đang chạy. Validation trả HTTP 400 và ErrorResponse; OpenAPI loại response 422 mặc định của FastAPI.

Những quyết định dự thảo cần TV1 + TV3 chốt

Sau khi nhóm chốt, cập nhật shared/contracts/ trước và đối chiếu lại DTO/producer/ consumer trong các PR liên quan. Không coi tài liệu này thay thế quy trình review đó.

Giao diện cho TV3

app/core/rag_facade.py định nghĩa RagFacadeReadiness. Factory được chỉ định qua YALA_RAG_FACTORY=python.module:factory. Factory không nhận tham số và trả một object có các phương thức async:

Phương thức Trách nhiệm TV3
startup(cache_dir: Path) mở model và PersistentClient trong đúng cache_dir
shutdown() kết thúc/flush/cancel tác vụ của module, đóng tài nguyên; giữ cache hợp lệ
readiness() -> Readiness báo pipeline_version và trạng thái model/vector store
index(video_id, payload) -> dict điều phối normalize/chunk/embed/index; xử lý cache và tác vụ nền
index_status(video_id) -> dict đọc trạng thái đúng video, kể cả sau restart
retrieve(video_id, payload) -> dict truy vấn có filter videoId và trả context
assess_quiz(video_id, payload) -> dict scoring/topic/review timestamp; dữ liệu phiên không ghi lâu dài
delete_cache(video_id) -> dict xóa đúng record của video; gọi lại vẫn an toàn

Payload là dict đã validate bằng DTO. Kết quả dict phải theo DTO response. Facade có thể raise ServiceError("INDEX_NOT_FOUND") hoặc mã trong core/errors.py. Lỗi ngoài allowlist được đổi thành mã lỗi của endpoint; không trả exception text.

Facade phải nhường event loop và truyền tiếp asyncio.CancelledError. Transport cancel coroutine khi timeout hoặc client disconnect. Công việc CPU/I/O đồng bộ cần adapter quản lý worker/executor phù hợp; cancel coroutine không bảo đảm dừng một thread đã chạy. Timeout không rollback cache; TV3 chịu trách nhiệm transaction, idempotency và lifecycle của job index nền đã nhận qua response 202.

tests/service/fakes.py chỉ là fixture tổng hợp trong RAM để test adapter. Fixture không chunk/embed/search/chấm quiz thật và không dùng trong production.

Bằng chứng và giới hạn để ghi PR

Thiết kế lifecycle tham khảo FastAPI lifespan; validation strict theo Pydantic strict mode.