690601:0914 ADR-032-232 #02
CI / CD Pipeline / build (push) Successful in 4m58s
CI / CD Pipeline / deploy (push) Successful in 4m4s

This commit is contained in:
2026-06-01 09:14:57 +07:00
parent 268f34198b
commit 3c80617ffb
+20 -2
View File
@@ -10,6 +10,7 @@
// - 2026-05-23: เพิ่ม Migration Checkpoint API endpoints แทน MySQL direct access (ADR-023A) // - 2026-05-23: เพิ่ม Migration Checkpoint API endpoints แทน MySQL direct access (ADR-023A)
// - 2026-05-30: เพิ่ม @UseInterceptors(FileInterceptor('file')) ใน submitSandboxOcr เพื่อแก้ไขปัญหา BadRequestException (File is required) // - 2026-05-30: เพิ่ม @UseInterceptors(FileInterceptor('file')) ใน submitSandboxOcr เพื่อแก้ไขปัญหา BadRequestException (File is required)
// - 2026-05-30: เพิ่ม endpoints GET/POST/PATCH models และ GET vram/status สำหรับ dynamic AI model management และ VRAM monitoring (T031-T034, US2) // - 2026-05-30: เพิ่ม endpoints GET/POST/PATCH models และ GET vram/status สำหรับ dynamic AI model management และ VRAM monitoring (T031-T034, US2)
// - 2026-06-01: [BUGFIX] submitSandboxOcr: เพิ่ม @ApiBearerAuth(), @HttpCode(ACCEPTED), Body({ engineType }) และส่ง engineType ไปยัง enqueueSandboxJob
// Controller สำหรับ AI Gateway Endpoints (ADR-023) // Controller สำหรับ AI Gateway Endpoints (ADR-023)
import { import {
@@ -516,9 +517,11 @@ export class AiController {
// --- Step 1: OCR Only (สำหรับตรวจคุณภาพ OCR ก่อนทดสอบ AI) --- // --- Step 1: OCR Only (สำหรับตรวจคุณภาพ OCR ก่อนทดสอบ AI) ---
@Post('admin/sandbox/ocr') @Post('admin/sandbox/ocr')
@UseGuards(JwtAuthGuard, RbacGuard) @UseGuards(JwtAuthGuard, AiEnabledGuard, RbacGuard)
@ApiBearerAuth()
@RequirePermission('system.manage_all') @RequirePermission('system.manage_all')
@UseInterceptors(FileInterceptor('file')) @UseInterceptors(FileInterceptor('file'))
@HttpCode(HttpStatus.ACCEPTED)
@ApiOperation({ @ApiOperation({
summary: 'Step 1: Run OCR Only — สำหรับตรวจคุณภาพ OCR ก่อนทดสอบ AI', summary: 'Step 1: Run OCR Only — สำหรับตรวจคุณภาพ OCR ก่อนทดสอบ AI',
description: description:
@@ -533,6 +536,11 @@ export class AiController {
type: 'string', type: 'string',
format: 'binary', format: 'binary',
}, },
engineType: {
type: 'string',
enum: ['auto', 'tesseract', 'typhoon-ocr-3b'],
description: 'OCR engine ที่ต้องการใช้ (default: auto)',
},
}, },
}, },
}) })
@@ -541,20 +549,30 @@ export class AiController {
new ParseFilePipe({ new ParseFilePipe({
validators: [ validators: [
new MaxFileSizeValidator({ maxSize: 50 * 1024 * 1024 }), new MaxFileSizeValidator({ maxSize: 50 * 1024 * 1024 }),
new FileTypeValidator({ fileType: 'pdf' }), new FileTypeValidator({ fileType: /(pdf|application\/pdf)/ }),
], ],
}) })
) )
file: Express.Multer.File, file: Express.Multer.File,
@Body('engineType') engineType: string | undefined,
@CurrentUser() user: User @CurrentUser() user: User
): Promise<{ requestPublicId: string; jobId: string; status: string }> { ): Promise<{ requestPublicId: string; jobId: string; status: string }> {
const attachment = await this.fileStorageService.upload(file, user.user_id); const attachment = await this.fileStorageService.upload(file, user.user_id);
const requestPublicId = uuidv7(); const requestPublicId = uuidv7();
// ตรวจสอบและ normalize engineType ให้เป็นค่าที่ valid
const validEngineTypes = ['auto', 'tesseract', 'typhoon-ocr-3b'] as const;
const resolvedEngineType: 'auto' | 'tesseract' | 'typhoon-ocr-3b' =
validEngineTypes.includes(
engineType as 'auto' | 'tesseract' | 'typhoon-ocr-3b'
)
? (engineType as 'auto' | 'tesseract' | 'typhoon-ocr-3b')
: 'auto';
const jobId = await this.aiQueueService.enqueueSandboxJob( const jobId = await this.aiQueueService.enqueueSandboxJob(
'sandbox-ocr-only', 'sandbox-ocr-only',
{ {
idempotencyKey: requestPublicId, idempotencyKey: requestPublicId,
pdfPath: attachment.filePath, pdfPath: attachment.filePath,
engineType: resolvedEngineType,
} }
); );
return { requestPublicId, jobId, status: 'queued' }; return { requestPublicId, jobId, status: 'queued' };