From 69db07fe357a00fd89c351aec02af637e2d4e19d Mon Sep 17 00:00:00 2001 From: admin Date: Mon, 1 Jun 2026 19:34:24 +0700 Subject: [PATCH] 690601:1934 ADR-032-232 #08.1 docs: update ADR-032 and tasks.md with multipart upload decision [skip CI][skip CI] --- .../ADR-032-typhoon-ocr-integration.md | 42 +++++++++++++++---- .../232-typhoon-ocr-integration/tasks.md | 15 +++++++ 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/specs/06-Decision-Records/ADR-032-typhoon-ocr-integration.md b/specs/06-Decision-Records/ADR-032-typhoon-ocr-integration.md index 7a64b511..8df91eb8 100644 --- a/specs/06-Decision-Records/ADR-032-typhoon-ocr-integration.md +++ b/specs/06-Decision-Records/ADR-032-typhoon-ocr-integration.md @@ -2,13 +2,15 @@ # ADR-032: Typhoon OCR & LLM Integration Architecture **Status:** Active **Date:** 2026-05-30 -**Decision Makers:** Development Team, System Architect, AI Integration Lead +**Decision Makers:** Development Team, System Architect, AI Integration Lead **Related Documents:** - [ADR-023: Unified AI Architecture (Base)](./ADR-023-unified-ai-architecture.md) - [ADR-023A: Unified AI Architecture — Model Revision (gemma4:e2b, 2-Model Stack)](./ADR-023A-unified-ai-architecture.md) @@ -19,7 +21,7 @@ ## 🎯 Context and Problem Statement -โครงการ LCBP3-DMS มีความต้องการยกระดับความแม่นยำในการทำ OCR เอกสารภาษาไทยในระบบ **OCR Sandbox Runner** ให้สูงขึ้น (เป้าหมาย 95%+) โดยใช้โมเดลภาษาไทยเฉพาะทาง และเพิ่มโมเดลภาษาไทยระดับผู้เชี่ยวชาญใน **AI Model Management** +โครงการ LCBP3-DMS มีความต้องการยกระดับความแม่นยำในการทำ OCR เอกสารภาษาไทยในระบบ **OCR Sandbox Runner** ให้สูงขึ้น (เป้าหมาย 95%+) โดยใช้โมเดลภาษาไทยเฉพาะทาง และเพิ่มโมเดลภาษาไทยระดับผู้เชี่ยวชาญใน **AI Model Management** อย่างไรก็ดี การเพิ่มโมเดลสกัดข้อความที่เป็นวิสัยทัศน์คอมพิวเตอร์ (Vision-Language Model) และโมเดลภาษาขนาดใหญ่ (Large Language Model) เช่น `scb10x/typhoon-ocr-3b` (~3.5GB VRAM) และ `typhoon2.1-gemma3-4b` (~4.5GB VRAM) อาจส่งผลให้เกิดปัญหา **GPU VRAM Overflow** (เกินขีดจำกัด 8GB ของ RTX 2060 Super บน Admin Desktop Desk-5439) หากมีการโหลดเข้าสู่หน่วยความจำพร้อมกับโมเดลพื้นฐานอย่าง `gemma4` และ `nomic-embed-text`. @@ -40,12 +42,35 @@ * **AI Model Option:** เพิ่ม `typhoon2.1-gemma3-4b` เข้าไปในระบบ **AI Model Management** สำหรับงานวิเคราะห์ความหมายขั้นสูงในบริบทไทย. * **OCR Sandbox Option:** วางแผนเพิ่ม `Typhoon OCR-3B` (รันบน Ollama ที่เครื่อง Admin Desktop) เป็นตัวเลือกคู่ขนานกับ Tesseract OCR. -### 2. นโยบายการจัดการ VRAM ด้วย Ollama Model Swapping (VRAM Swapping Policy) +### 2. การส่งไฟล์ระหว่าง Backend และ OCR Sidecar (File Transfer Architecture) + +**การตัดสินใจ (2026-06-01):** เปลี่ยนจาก **shared volume mount** เป็น **multipart HTTP upload** ผ่าน endpoint `/ocr-upload` ใหม่ + +**สาเหตุ:** Docker Desktop บน Windows 11 ใช้ WSL2 เป็น backend — Linux VM ภายใน WSL2 ไม่สามารถ bind mount จาก Windows mapped drive letter (Z:) หรือ CIFS named volume ที่ mount ผ่าน Docker Desktop ได้ ทำให้ `/mnt/uploads` ใน sidecar container ว่างเปล่าเสมอ และเกิด 404 เมื่อ sidecar พยายามเปิดไฟล์ + +**Architecture ใหม่:** +``` +Backend (QNAP) + └── fs.readFileSync(pdfPath) ← อ่านจาก /app/uploads/ + └── POST /ocr-upload (multipart) ← ส่ง file bytes ผ่าน LAN 2.5 Gbps + └── Sidecar (Desk-5439) + └── fitz.open(stream=pdf_bytes) ← ประมวลผลใน memory +``` + +**ข้อดีเพิ่มเติม:** +- ไม่มี path coupling — sidecar ไม่รู้จัก path ของ backend +- Sidecar ย้าย host ได้โดยไม่ต้องแก้ config mount +- Overhead จาก file transfer < 200ms บน LAN 2.5 Gbps (น้อยกว่า OCR processing time มาก) +- endpoint `/ocr` (path-based, legacy) ยังคงอยู่เพื่อ backward compatibility + +--- + +### 3. นโยบายการจัดการ VRAM ด้วย Ollama Model Swapping (VRAM Swapping Policy) เพื่อหลีกเลี่ยงข้อจำกัด 8GB VRAM ของ GPU โดยยังคงใช้โมเดลขนาดใหญ่ได้ ระบบจะเปลี่ยนจากการโหลดโมเดลค้างไว้พร้อมกัน (Simultaneous) เป็น **"การทำงานแบบสลับลำดับและจำกัดการจองหน่วยความจำ (Sequential with Ollama keep_alive)"**: * **`keep_alive = 0`:** ในคำสั่งเรียกประมวลผล (Inference) ทุกชนิดไปยังโมเดล Typhoon จะต้องบังคับพารามิเตอร์ `"keep_alive": 0` เพื่อให้ Ollama ทำการคลายโมเดลออกจากหน่วยความจำ GPU ทันทีหลังตอบกลับสำเร็จ คืนพื้นที่ VRAM ให้โมเดลถัดไปทำงานได้ทันที. * **Stateless Sidecar:** ตัว Python OCR Sidecar Container จะรับตัวแปรสภาพแวดล้อม `OLLAMA_API_URL` ใน `docker-compose.yml` (ชี้ไปที่ `http://192.168.10.100:11434`) เพื่อประมวลผล PDF-to-Image และส่งภาพสกัดต่อไปยัง Ollama. -### 3. Hyperparameters และ System Prompt สำหรับ Typhoon OCR +### 4. Hyperparameters และ System Prompt สำหรับ Typhoon OCR เพื่อให้ได้ผลลัพธ์การสกัดอักษรภาษาไทยที่ถูกต้องและลดสัญญาณรบกวน (Noise): * **System Prompt:** ```text @@ -57,13 +82,13 @@ - `repeat_penalty = 1.0` (หรือ `repetition_penalty`) - `keep_alive = 0` -### 4. ระบบการเก็บแคชชิ่ง (24-Hour Redis Caching) +### 5. ระบบการเก็บแคชชิ่ง (24-Hour Redis Caching) ระบบจะทำการแคชผลลัพธ์ของการทำ OCR ด้วยโมเดลและไฟล์เดิมไว้เป็นเวลา **24 ชั่วโมง** ผ่าน Redis เพื่อลดต้นทุนเวลาประมวลผล (SLA < 60 วินาที/หน้า) * **Cache Key:** `ocr:cache:{documentPublicId}:{engine}:{hash}` * **TTL:** 86,400 วินาที (24 ชั่วโมง) * **การเคลียร์แคช:** ทำโดยอัตโนมัติเมื่อเอกสารอัปเดต หรือแอดมินสั่งล้างผ่านระบบหลังบ้าน. -### 5. ระบบสลับเอนจินสำรองอัตโนมัติ (Graceful Fallback) +### 6. ระบบสลับเอนจินสำรองอัตโนมัติ (Graceful Fallback) * หาก Ollama หรือโมเดล Typhoon ไม่สามารถเข้าถึงได้ หรือใช้เวลาทำ OCR **นานเกิน 60 วินาที** ระบบ NestJS backend (`OcrService`) จะทำการสลับเอนจินสำรองไปยัง **Tesseract OCR (tha+eng)** อัตโนมัติในเวลาไม่เกิน 5 วินาที พร้อมแจ้งเตือนผู้ใช้บนหน้าเว็บอินเตอร์เฟส. --- @@ -78,8 +103,11 @@ | OcrCacheService (24h Redis) | ✅ Complete | `backend/src/modules/ai/services/ocr-cache.service.ts` | | AiAuditLog entity extension | ✅ Complete | `backend/src/modules/ai/entities/ai-audit-log.entity.ts` | | OCR Sidecar: Typhoon OCR function | ✅ Complete | `specs/04-Infrastructure-OPS/.../ocr-sidecar/app.py` | +| OCR Sidecar: `/ocr-upload` multipart endpoint | ✅ Complete | `specs/04-Infrastructure-OPS/.../ocr-sidecar/app.py` | | OCR Sidecar: Dockerfile update | ✅ Complete | `specs/04-Infrastructure-OPS/.../ocr-sidecar/Dockerfile` | -| OCR Sidecar: docker-compose.yml | ✅ Complete | `specs/04-Infrastructure-OPS/.../ocr-sidecar/docker-compose.yml` | +| OCR Sidecar: docker-compose.yml (volumes ลบออก) | ✅ Complete | `specs/04-Infrastructure-OPS/.../ocr-sidecar/docker-compose.yml` | +| OcrService: multipart upload แทน remapPath | ✅ Complete | `backend/src/modules/ai/services/ocr.service.ts` | +| SandboxOcrEngineService: multipart upload แทน remapPath | ✅ Complete | `backend/src/modules/ai/services/sandbox-ocr-engine.service.ts` | | TyphoonOcrProcessor (BullMQ) | ✅ Complete | `backend/src/modules/ai/processors/typhoon-ocr.processor.ts` | | TyphoonLlmProcessor (BullMQ) | ✅ Complete | `backend/src/modules/ai/processors/typhoon-llm.processor.ts` | | ai.module.ts registration | ✅ Complete | `backend/src/modules/ai/ai.module.ts` | diff --git a/specs/200-fullstacks/232-typhoon-ocr-integration/tasks.md b/specs/200-fullstacks/232-typhoon-ocr-integration/tasks.md index 0b2a7776..c91284af 100644 --- a/specs/200-fullstacks/232-typhoon-ocr-integration/tasks.md +++ b/specs/200-fullstacks/232-typhoon-ocr-integration/tasks.md @@ -150,6 +150,21 @@ --- +## Phase 7: Bugfix — OCR Sidecar 404 (2026-06-01) + +**Root Cause:** Docker Desktop WSL2 ไม่สามารถ bind mount Windows network drive (Z:) หรือ CIFS volume ได้ ทำให้ `/mnt/uploads` ใน sidecar container ว่างเปล่า และ sidecar ตอบกลับ 404 ทุกครั้ง + +**Fix:** เปลี่ยน architecture จาก shared volume mount เป็น multipart HTTP upload + +- [x] T051 เพิ่ม `POST /ocr-upload` endpoint ใน `app.py` รับ multipart file โดยตรง (ไม่ต้องการ volume mount) +- [x] T052 Refactor `_process_pdf_doc()` เป็น shared function ระหว่าง `/ocr` และ `/ocr-upload` +- [x] T053 ลบ `remapPath()` และ `sidecarUploadBase` ออกจาก `ocr.service.ts` เปลี่ยนเป็น `fs.readFileSync` + Node.js `FormData` +- [x] T054 ลบ `remapPath()` และ `sidecarUploadBase` ออกจาก `sandbox-ocr-engine.service.ts` เปลี่ยนเป็น multipart upload +- [x] T055 ลบ `volumes:` section ออกจาก `docker-compose.yml` — ไม่ต้องการ shared storage อีกต่อไป +- [x] T056 อัพเดต ADR-032 บันทึก architectural decision เรื่อง file transfer approach + +--- + ## Dependencies & Execution Order ### Phase Dependencies