Skip to content

vtrc-ocr-api — Core Pipeline

บทนี้ (branch: main) แยก flow ที่ README โฆษณา กับ flow ที่โค้ดทำจริง — รวม in-memory lifecycle และจุดที่ config ไม่มีผล


Flow ที่ README ตั้งใจ vs flow จริง

README บรรยายว่าส่ง base64 image แล้วได้ข้อความจาก OCR (README.md:78-93)

Flow จริง:

Client
  │  POST /api/ocr/process
  │  body: { image: string, options?: object }

routes/ocr.routes.js
  │  validateOCRRequest → ocrController.processOCR
  │  `ocr.routes.js:38`

middleware/validation.middleware.js
  │  image: notEmpty + isString
  │  options: optional + isObject
  │  ไม่ตรวจ base64 validity / MIME / ขนาดไฟล์
  │  `validation.middleware.js:3-23`

controllers/ocr.controller.js#processOCR
  │  ดึง { image, options } → ocrService.processImage
  │  `ocr.controller.js:3-17`

services/ocr.service.js#processImage          (ocr.service.js:6-41)
  │  1. ถ้า !image → throw { status: 400, message: 'Image is required' }
  │     (ซ้ำกับ validator — กันกรณีเรียก service โดยตรง)
  │  2. generateProcessingId() → `ocr_{Date.now()}_{random36}`
  │     `ocr.service.js:69-71`
  │  3. save record { id, status:'processing', createdAt, options }
  │  4. setTimeout(1000ms):
  │       update → {
  │         status: 'completed',
  │         text: 'Sample OCR result text',   ← คงที่
  │         confidence: 0.95,                 ← คงที่
  │         completedAt: ISO
  │       }
  │  5. return ทันที { processingId, status:'processing', message }

HTTP 200 { success: true, data: { processingId, status, message } }

ไม่มี decode base64, ไม่มีเรียก OCR library, ไม่มี HTTP ออกไปยัง Vision API — ค่า text/confidence hard-code ที่ ocr.service.js:26-32 เท่านั้น

ค่า image และ options ถูกเก็บใน record ตอนสร้าง (options เท่านั้นใน object ที่ save — image ไม่ถูกเก็บ ใน model) (ocr.service.js:14-19)


Poll status

GET /api/ocr/status/:id

getProcessingStatus(id)                     (ocr.service.js:43-51)
  │  ocrModel.getProcessingRecord(id)
  │  ไม่พบ → throw { status: 404, message: 'Processing record not found' }

200 { success: true, data: record }

สถานะขึ้นกับว่า setTimeout ยิงแล้วหรือยัง:

เวลาหลัง POSTstatus ใน Mapfields พิเศษ
< ~1sprocessingcreatedAt, options
≥ ~1scompleted+ text, confidence, completedAt (merge ทับ)

หลัง process restart → Map ว่าง → ทุก id ได้ 404


History + pagination

GET /api/ocr/history?page=1&limit=10

getProcessingHistory(page, limit)           (ocr.service.js:53-67)
  │  getAllProcessingRecords() → reverse chronological
  │  slice((page-1)*limit, page*limit)
  │  pagination: { page, limit, total, totalPages } หลัง parseInt

Controller ส่ง query string ตรง ๆ (ocr.controller.js:39) — ไม่มี validation ของ page/limit

Input ผิดปกติพฤติกรรมที่สังเกตได้จากโค้ด
limit ไม่ใช่ตัวเลขparseInt → NaN → .slice(NaN, NaN)[]
page=0startIndex = -limit → slice จากท้าย array (พฤติกรรมของ Array#slice)
ไม่ส่ง page/limitdefault 1 / 10 จาก destructuring (ocr.controller.js:39)

Config ที่ไม่มีผลต่อ pipeline

Config fieldDefaultถูกใช้ใน OCR path?Citation
ocr.maxImageSize'10MB'ไม่config.js:22
ocr.supportedFormatsjpg/jpeg/png/pdfไม่config.js:23
ocr.timeout30000ไม่ — ใช้ setTimeout(1000) คงที่config.js:24 vs ocr.service.js:25
cors.origin'*'ไม่ — app.use(cors()) ไม่รับ optionsconfig.js:15-18 vs app.js:16

Error handling ที่ใช้จริง vs ที่ประกาศไว้

Pathวิธีจับ errorCitation
OCR controllerstry/catch ในแต่ละ handler + error.statusocr.controller.js:12-16,29-33,46-50
Health controllerstry/catch แยกhealth.controller.js:7-11,19-23
Global app.js(err, req, res, next) inlineapp.js:58-64
middleware/error.middleware.jserrorHandler + asyncHandlerไม่มี import ใน app.js — dead

Controllers ไม่ใช้ asyncHandler ดังนั้น rejected promise ที่ไม่ถูก catch ใน try จะไม่เข้า Express error middleware โดยอัตโนมัติ — แต่ทุก handler ปัจจุบันมี try/catch ครอบ await อยู่แล้ว

Response shape ไม่สม่ำเสมอ:

SourceSuccess shapeError shape
OCR controller{ success, data }{ success: false, error }
Validation MW{ success: false, errors: [...] }
Health service via controllerobject ตรงจาก service (ไม่มี success){ error, message }
GET /health ใน app.js{ status, message, timestamp }
utils/response.js (unused){ success, message, data }{ success, message, errors? }

Data flow กับระบบอื่นในแพลตฟอร์ม

ตรวจทั้ง repo: ไม่มี axios / fetch / http.request ไป host ภายนอก

(ไม่มี caller ใน workspace ที่ยืนยันได้)


  vtrc-ocr-api (standalone stub)

        └── in-memory Map เท่านั้น
            ไม่มี DB, ไม่มี queue, ไม่มี callback ไป service อื่น

ถือเป็น standalone mock — ไม่ถูกผูกเข้า legacy GraphQL หรือ NestJS microservices ในโค้ดที่ตรวจได้


Swagger coverage

docs/swagger.js กำหนด OpenAPI 3.0, server http://localhost:{port}, schemas:

SchemaFieldsCitation
OCRRequestimage (required string), options (object)swagger.js:21-34
OCRStatusResponseid, status enum, text, confidence, createdAt, completedAtswagger.js:35-45

JSDoc ใน routes/*.js document: /api, /api/health, /api/health/detailed, /api/ocr/process, /api/ocr/status/{id}, /api/ocr/history

ไม่ document GET /health (นอก /api) และ GET / ใน OpenAPI — แต่มีใน Express