690606:1354 ADR-035-135 #03.1 [skip CI]
CI / CD Pipeline / build (push) Has been skipped
CI / CD Pipeline / deploy (push) Has been skipped

This commit is contained in:
2026-06-06 13:54:36 +07:00
parent 866fea7946
commit e3e0de66e9
6 changed files with 416 additions and 2 deletions
+2
View File
@@ -12,6 +12,7 @@
// - 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
// - 2026-06-02: เพิ่ม REST endpoints GET /ai/ocr-engines และ POST /ai/ocr-engines/:engineId/select (T003, T004, ADR-033) และนำเข้า SystemException เพื่อป้องกันความเสียหายในการคอมไพล์
// - 2026-06-06: [BUGFIX] เพิ่ม @Throttle({ default: { limit: 300, ttl: 60000 } }) บน GET admin/sandbox/job/:id เพื่อแก้ ThrottlerException spam จาก frontend polling
// Controller สำหรับ AI Gateway Endpoints (ADR-023)
import {
@@ -452,6 +453,7 @@ export class AiController {
@UseGuards(JwtAuthGuard, RbacGuard)
@ApiBearerAuth()
@RequirePermission('system.manage_all')
@Throttle({ default: { limit: 300, ttl: 60000 } }) // 300 req/min — รองรับ admin polling ทุก 200ms
@ApiOperation({
summary:
'AI Admin Sandbox Job Status — ตรวจสอบสถานะ RAG sandbox job (T036)',
@@ -11,6 +11,7 @@
// - 2026-05-28: EC-001 ใช้ findOrSuggestTags เพื่อตรวจจับ Tag ใหม่และบันทึก aiIssues; EC-002 ตรวจสอบ UUID ของผู้ส่ง/ผู้รับ และ Flag เมื่อหาไม่พบ
// - 2026-06-03: ADR-034 — เพิ่ม 'ocr-extract' job type + OCR_JOB_TYPES constant + processOcrExtract() ที่มี model switching logic (unload main → load OCR → generate → reload main)
// - 2026-06-06: แก้ไข bug LLM JSON parse failure — เพิ่ม retry logic (2 attempts), debug log raw response, และปรับปรุง error message ให้แสดงทั้ง raw และ cleaned response
// - 2026-06-06: เพิ่ม OCR text truncation (MAX_OCR_TEXT_CHARS=15000) เพื่อป้องกัน context overflow เมื่อเอกสารยาวมากชน num_ctx 8192
import { Processor, WorkerHost } from '@nestjs/bullmq';
import { Logger } from '@nestjs/common';
@@ -75,6 +76,9 @@ export interface AiBatchJobData {
idempotencyKey: string;
}
/** OCR text สูงสุดที่ส่งเข้า LLM prompt — ป้องกัน context overflow (num_ctx 8192, Thai ~3 chars/token) */
const MAX_OCR_TEXT_CHARS = 15000;
const readString = (value: unknown): string | undefined =>
typeof value === 'string' && value.trim().length > 0 ? value : undefined;
@@ -421,8 +425,16 @@ export class AiBatchProcessor extends WorkerHost {
overrideProjPublicId === 'default' ? undefined : overrideProjPublicId
);
const ocrTextSafe =
ocrResult.text.length > MAX_OCR_TEXT_CHARS
? (this.logger.warn(
`OCR text truncated: ${ocrResult.text.length} chars > ${MAX_OCR_TEXT_CHARS} limit (context overflow protection)`
),
ocrResult.text.substring(0, MAX_OCR_TEXT_CHARS))
: ocrResult.text;
const resolvedPrompt = activePrompt.template
.replace('{{ocr_text}}', ocrResult.text)
.replace('{{ocr_text}}', ocrTextSafe)
.replace(
'{{master_data_context}}',
JSON.stringify(masterDataContext, null, 2)
@@ -636,8 +648,16 @@ export class AiBatchProcessor extends WorkerHost {
projectPublicId === 'default' ? undefined : projectPublicId
);
const ocrTextSafe =
ocrText.length > MAX_OCR_TEXT_CHARS
? (this.logger.warn(
`OCR text truncated: ${ocrText.length} chars > ${MAX_OCR_TEXT_CHARS} limit (context overflow protection)`
),
ocrText.substring(0, MAX_OCR_TEXT_CHARS))
: ocrText;
const resolvedPrompt = targetPrompt.template
.replace('{{ocr_text}}', ocrText)
.replace('{{ocr_text}}', ocrTextSafe)
.replace(
'{{master_data_context}}',
JSON.stringify(masterDataContext, null, 2)
@@ -0,0 +1,62 @@
HEC CHEC(THAI) CO.,LTD บริษัท ซีเอชบี (ไทย) จำกัด
Bangkok Liaison Office: 87/2 CRC Tower, 20 FL Wireless Rd, Lumphini, Pathumwan, Bangkok 10330
สำนักงานใหญ่ : 87/2 อาคารเซียาร์ซี พาวเวอร์ ชั้น 20 ถนนวิทยุ แขวงลุมพินี เขตปทุมวัน กรุงเทพมหานคร 10330 Tel.02-002-8683 Fax. 02-002-8685
Project Site Office: Thung Sukhla,Si Racha District Chon Buri 20230 สำนักงานโครงการ : ตำบลธงสุขลา สันทวีศรีราชา จังหวัดชลบุรี 20230
ต้นฉบับ
Project of Laem Chabang Port Phase 3, Infrastructure Works (Contract 2)
สัญญาจ้างเหมาก่อสร้างโครงการพัฒนาท่าเรือแหลมฉบังระยะที่ 3 ( ส่วนที่ 2 ) งานก่อสร้างอาคาร ท่าเทียบเรือ ระบบถนน และสาธารณูปโภค
PSLCP3
ได้รับเอกสารฉบับนี้แล้ว
เลขที่รับเอกสาร....................
วันที่ 19 ก.พ. 2568
ผู้รับ ลายเซ็น
10 กุมภาพันธ์ 2568
เรื่อง ส่งมอบพื้นที่ถมทะเลพื้นที่ 1 และ 2
โครงการพัฒนาท่าเรือแหลมฉบังระยะที่ 3 (ส่วนที่ 2) งานก่อสร้างอาคาร ท่าเทียบเรือ ระบบถนน และสาธารณูปโภค
เรียน คุณสุวัฒน์ พิพัฒนปัญญกูล
ผู้จัดการโครงการงานควบคุมงานก่อสร้างโครงการพัฒนาท่าเรือแหลมฉบัง ระยะที่ 3 (ส่วนที่ 1-4)
อ้างถึง 1) สัญญาจ้างเหมาก่อสร้างโครงการพัฒนาท่าเรือแหลมฉบังระยะที่ 3 (ส่วนที่2) งานก่อสร้างอาคาร ท่าเทียบเรือ ระบบถนนและสาธารณูปโภค สัญญาเลขที่ ทลฉ.จ.19/2567 ลงวันที่ 31 กรกฎาคม 2567
2) หนังสือการท่าเรือแหลมฉบัง เลขที่ สคฉ.03/0036 ลงวันที่ 4 กุมภาพันธ์ 2568 เรื่อง ขอส่งมอบ พื้นที่ โครงการพัฒนาท่าเรือแหลมฉบังระยะที่3 (ส่วนที่2) งานก่อสร้างอาคาร ท่าเทียบเรือ ระบบ ถนนและสาธารณูปโภค
3) หนังสือขอข้อคิดเห็นและข้อมูลเพิ่มเติม เลขที่ LCBP3-C2-RFI-BUD-0001-A ลงวันที่ 4 มกราคม 2568 เรื่อง ขอข้อคิดเห็นงานก่อสร้างอาคารบริเวณพื้นที่ 1 (Area 1) เมื่อเทียบกับระดับดินเดิม ณ ปัจจุบัน จากการสำรวจลักษณะภูมิประเทศ (Topographic Survey)
4) หนังสือขออนุมัติเอกสาร เลขที่ LCBP3-C2-RFA-ROW-RPT-0007-A ลงวันที่ 22 มกราคม 2568 เรื่อง ขออนุมัติรายงานการสำรวจเพื่อการก่อสร้างอาคารประตูตรวจสอบ 5 และถนน RN-2
สิ่งที่ส่งมาด้วย
1) รูปแสดง การร่วมตรวจสอบพื้นที่ระหว่างผู้ควบคุมงาน/คคง. และผู้รับจ้าง/ผรม.2 และ รูปแสดงอุปสรรคในพื้นที่ก่อสร้างที่ได้รับมอบพื้นที่ถมทะเลพื้นที่ 1 และ 2
ตามสัญญาที่อ้างถึง
1) สัญญาจ้างเหมาก่อสร้างโครงการพัฒนาท่าเรือแหลมฉบังระยะที่ 3 (ส่วนที่2) งานก่อสร้างอาคาร ท่าเทียบเรือ ระบบถนนและสาธารณูปโภค สัญญาเลขที่ ทลฉ.จ.19/2567 ลงวันที่ 31 กรกฎาคม 2567 หนังสือการท่าเรือแหลมฉบัง ที่อ้างถึง
2) เรื่องขอส่งมอบพื้นที่ โครงการพัฒนาท่าเรือแหลม ฉบังระยะที่3 (ส่วนที่2) งานก่อสร้างอาคาร ท่าเทียบเรือ ระบบถนนและระบบสาธารณูปโภค
ผู้รับจ้าง/ผรม.2 รับทราบการส่งมอบพื้นที่ถมทะเลพื้นที่ 1 และ 2 และขอแจ้งยืนยันวันเริ่ม Keydate ตามรายละเอียดดังนี้
เริ่มใช้เมื่อวันที่ 20 กันยายน 2567
<page
บริษัท ซีเอชบี (ไทย) จำกัด
Project of Laem Chabang Port Phase 3, Infrastructure Works (Contract 2)
สัญญาจ้างเหมาก่อสร้างโครงการพัฒนาท่าเรือแหลมฉบังระยะที่ 3 ( ส่วนที่ 2 ) งานก่อสร้างอาคาร ท่าเทียบเรือ ระบบถนน และระบบสาธารณูปโภค
Bangkok Branch Office : 87/2, Aroon Tower, 26 FL., Wireless Rd. Lumpini, Pathumwan, Bangkok 10330
สำนักงานใหญ่ : 87/2 อาคารซีอาร์ซี พาวเวอร์ ชั้น 20 ถนนวิทยุ แขวงลุมพินี เขตปทุมวัน กรุงเทพมหานคร 10330 Tel. 02 002-8683 Fax. 02 002-8685
Project Site Office: Thung Sukhla,Si Racha District Chon Buri 20230
สำนักงานโครงการ : ตำบลทุ่งสุขลา อำเภอศรีราชา จังหวัดชลบุรี 20230
* Keydate 1.1 Substation 115 KV ระยะเวลาก่อสร้าง 540 วัน วันงานเริ่ม 1 กุมภาพันธ์ 2568
* **วันที่กำหนดแล้วเสร็จ** 25 กรกฎาคม 2569 ประกอบด้วย งานก่อสร้างอาคารสถานีไฟฟ้าย่อย ขนาด 115 KV ลานกองวัสดุ รั้วรอบพื้นที่ ประตูรั้ว ถนน ระบบสาธารณูปโภคทั้งหมดที่อยู่ใน พื้นที่รั้วของ Substation 115 KV การติดตั้ง และทดสอบ Power Transformer และ 115 KV GIS และรวมถึง การจ่ายค่าธรรมเนียมการขอใช้ไฟฟ้าแรงสูง 115 KV เพื่อให้ Substation 115 KV พร้อมจ่ายพลังงานไฟฟ้าได้
* Keydate 2.1 งานก่อสร้างสะพานยกระดับ 4, 12, 12.1 และ 12.2 ระยะเวลาก่อสร้าง 720 วัน **วันงานเริ่ม** 1 กุมภาพันธ์ 2568 วันที่กำหนดแล้วเสร็จ 21 มกราคม 2570
* Keydate 2.2 งานก่อสร้างอาคาร ระยะเวลาก่อสร้าง 720 วัน **วันงานเริ่ม** 1 กุมภาพันธ์ 2568 **วันที่กำหนดแล้วเสร็จ** 21 มกราคม 2570 ประกอบด้วย งานก่อสร้าง อาคารพักขยะอันตราย อาคารพักขยะทั่วไป อาคารควบคุมสถานีสูบระบบน้ำ อาคารสูบจ่ายน้ำประปา งานก่อสร้าง อาคารประตูตรวจสอบ 5 อาคารด่านตรวจสอบขาเข้า-ขาออก ตู้ควบคุมการเข้า-ออก Toll Island, WEIGHT STATION ลานจอดรถบรรทุก บริเวณอาคารประตูตรวจสอบ 5 และ รวมถึง การติดตั้งอุปกรณ์ และการทดสอบระบบต่างๆของอาคารแล้วเสร็จ
ผู้รับจ้าง/ผรม.2 จะดำเนินการแก้ไขแผนงานก่อสร้างให้สอดคล้องกับการส่งมอบพื้นที่ เพื่อนำเสนอ ขออนุมัติ และดำเนินงานก่อสร้างให้สำเร็จลุล่วงตามแผนดำเนินงานเพื่อส่งมอบงาน ให้ผู้ว่าจ้าง/การทำเรือแห่ง ประเทศไทย ตามกรอบเวลางานก่อสร้างดังกล่าว
อย่างไรก็ตาม ผู้รับจ้าง/ผรม.2 ได้ร่วมตรวจสอบพื้นที่กับผู้ควบคุมงาน/คคง. เมื่อวันที่ 7 กุมภาพันธ์ 2568 พบว่าพื้นที่ถมทะเล 1 ที่ได้รับมอบพื้นที่นั้น ยังมีวัสดุอุปกรณ์ เครื่องจักร และสิ่งก่อสร้าง ตั้งอยู่ในพื้นที่ ซึ่งเป็นอุปสรรคในการเริ่มดำเนินการงานก่อสร้าง โดยมีรายละเอียดดังนี้
* สำนักงานโครงการ บ้านพักพนักงาน และกองวัสดุอุปกรณ์ ผู้รับจ้าง/ผรม.1 สัญญาส่วนที่ 1 ตั้งอยู่ ในบริเวณพื้นที่ก่อสร้างอาคารประตูตรวจสอบ 5 อาคารด่านตรวจสอบขาเข้า-ขาออก ตู้ควบคุม การเข้า-ออก Toll Island, WEIGHT STATION ลานจอดรถบรรทุก บริเวณอาคารประตู ตรวจสอบ 5 ซึ่งได้แสดงรายละเอียดไว้ใน รายงานการสำรวจเพื่อการก่อสร้างอาคารประตู ตรวจสอบ 5 และถนน RN-2 ตามหนังสือที่อ้างถึง 4)
* คันดินกองวัสดุที่ไม่เหมาะสมตามข้อกำหนด ยังกองอยู่ในพื้นที่ซ
บริษัท ซีเอชอีซี (ไทย) จำกัด
Project of Laem Chabang Port Phase 3, Infrastructure Works (Contract 2)
สัญญาจ้างเหมาก่อสร้างโครงการพัฒนาท่าเรือแหลมฉบังระยะที่ 3 ( ส่วนที่ 2 ) งานก่อสร้างอาคาร ท่าเทียบเรือ ระบบถนน และระบบสาธารณูปโภค
Bangkok Branch Office: 87/2 Aroon Chomchit, Phahonyothin, Bangkok 10330
สำนักงานใหญ่ : 87/2 อาคารซี.ซี.ทาวเวอร์ ชั้น 20 ถนนวิภาวดี แขวงลุมพินี เขตปทุมวัน กรุงเทพมหานคร 10330 Tel. 02 002-8683 Fax. 02 002-8685
Project Site Office: Thung Sukhla,Si Racha District Chon Buri 20230
สำนักงานโครงการ : ตำบลทุ่งสุขลา อำเภอศรีราชา จังหวัดชลบุรี 20230
* พื้นที่ถมทะเล 1 ที่ส่งมอบ มีวัชพืชขึ้นปกคลุม และระดับดินเดิมเฉลี่ยอยู่ที่ระดับ +3.400 MSL
* ต้องดำเนินการงานถากถางและขุดต่อขุดราก และถมดินเพิ่มจึงจะสามารถเริ่มงานก่อสร้างในพื้นที่ดังกล่าวได้ ตามรายละเอียดที่แสดงในหนังสือขอข้อคิดเห็นและข้อมูลเพิ่มเติม เรื่อง ขอข้อคิดเห็นงานก่อสร้างอาคารบริเวณพื้นที่ 1 (Area 1) เมื่อเทียบกับระดับดินเดิม ณ ปัจจุบัน จากการสำรวจลักษณะภูมิประเทศ (Topographic Survey) ตามหนังสือที่อ้างถึง 3) ซึ่งยังรอ ผู้ควบคุมงาน/คคง. ชี้แจงข้อคิดเห็น และสั่งการเพื่อดำเนินการงานดังกล่าว
รายละเอียดรูปแสดงรูปแสดง การร่วมตรวจสอบพื้นที่ระหว่างผู้ควบคุมงาน/คคง. และผู้รับจ้าง/ ผรม.2 และรูปแสดงอุปสรรคในพื้นที่ก่อสร้างที่ได้รับมอบพื้นที่ถมทะเลพื้นที่ 1 และ 2 ตามสิ่งที่ส่งมาด้วย 1)
โดยหนังสือฉบับนี้ ผู้รับจ้าง/ผรม.2 แจ้งมายัง ผู้ควบคุมงาน/คคง. เพื่อโปรดทราบ และโปรดพิจารณาประสานงานรื้อย้ายอุปสรรคดังกล่าวออกจากพื้นที่ที่ส่งมอบ เพื่อป้องกันความล่าช้าในการดำเนินการก่อสร้างในพื้นที่ดังกล่าว ซึ่งอาจส่งผลกระทบกับ Keydate 1.1, 2.1 และ 2.2 เพื่อให้งานก่อสร้างสามารถดำเนินการได้ตามวัตถุประสงค์ แผนงานก่อสร้าง และส่งมอบงานให้ผู้ว่าจ้าง/การท่าเรือฯ ได้ตามสัญญา
หากอุปสรรคดังกล่าว ส่งผลกระทบให้เกิดความล่าช้าในการทำงาน รวมถึงการส่งมอบงานให้กับผู้ว่าจ้าง/การท่าเรือฯ ผู้รับจ้าง/ผรม.2 ขอสงวนสิทธิ์ในการขยายระยะเวลากำหนดวันแล้วเสร็จของงานตามสัญญา และขอสงวนสิทธิ์เรียกร้องหากมีค่าใช้จ่ายที่เพิ่มขึ้นจากความล่าช้าจากปัญหาดังกล่าว
จึงเรียนมาเพื่อทราบและโปรดพิจารณา แจ้งผู้เกี่ยวข้องดำเนินการรื้อย้ายวัสดุอุปกรณ์ เครื่องจักร และสิ่งก่อสร้าง ออกจากพื้นที่ถมทะเล 1 ก่อนกำหนดการเริ่มงานก่อสร้างตามลำดับขั้นตอนการทำงานที่แสดงในแผนงานก่อสร้าง ทั้งนี้เพื่อไม่ให้มีผลกระทบกับแผนงานก่อสร้าง และสามารถส่งมอบงานให้กับผู้ว่าจ้าง/การท่าเรือฯ ได้ตามกำหนดวันแล้วเสร็จดังกล่าวข้างต้น
ขอแสดงความนับถือ
(นายไห่กวง หวัง)
บริษัท ซีเอชอีซี (ไทย) จำกัด
เริ่มใช้เมื่อวันที่ 20 กันยายน 2567
<page_number>3</page_number>
@@ -0,0 +1,157 @@
# ทดสอบ typhoon2.5-np-dms โดยใช้ prompt template จริง + OCR text จาก test.md + master data context จาก DB
# รันด้วย: powershell -ExecutionPolicy Bypass -File test_llm.ps1
$ErrorActionPreference = "Stop"
$OLLAMA_URL = "http://192.168.10.100:11434"
$MODEL = "typhoon2.5-np-dms:latest"
$OCR_TEXT_FILE = Join-Path $PSScriptRoot "test.md"
# --- Prompt Template (ดึงจาก DB: ai_prompts version=2, prompt_type=ocr_extraction) ---
$TEMPLATE = @"
(Document Intelligence Engine)
OCR Laem Chabang Port Phase 3 JSON object
OCR :
{{ocr_text}}
(Master Data Context):
{{master_data_context}}
:
1. OCR Master Data Context
2. (project) UUID (projectPublicId)
3. (correspondence type) (correspondenceTypeCode) RFA, Transmittal
4. (discipline) (disciplineCode) GEN, STR
5. (originator) availableOrganizations UUID (originatorOrganizationPublicId)
6. (recipients) Array UUID (organizationPublicId) (recipientType: "TO" "CC")
7. (subject)
8. (documentDate) YYYY-MM-DD
9. (tags) Tags ( availableTags )
10. (summary) 4-5
11. confidence: ( 0.0 1.0)
JSON Object markdown
JSON :
{
"projectPublicId": "string null",
"correspondenceTypeCode": "string null",
"disciplineCode": "string null",
"originatorOrganizationPublicId": "string null",
"recipients": [
{
"organizationPublicId": "string",
"recipientType": "TO CC"
}
],
"subject": "string null",
"documentDate": "string:YYYY-MM-DD null",
"tags": ["string"],
"summary": "string null",
"confidence": 0.95
}
"@
# --- Master Data Context (ดึงจาก DB จริง) ---
$MASTER_DATA = @{
availableProjects = @(
@{code = "LCBP3"; uuid = "c957f1e3-538b-11f1-8c7d-0242ac1d0007"; name = "โครงการพัฒนาท่าเรือแหลมฉบัง ระยะที่ 3 (ส่วนที่ 1-4)"}
@{code = "LCBP3-C1"; uuid = "c957f44b-538b-11f1-8c7d-0242ac1d0007"; name = "โครงการพัฒนาท่าเรือแหลมฉบัง ระยะที่ 3 (ส่วนที่ 1) งานก่อสร้างงานทางทะเล"}
@{code = "LCBP3-C2"; uuid = "c957f523-538b-11f1-8c7d-0242ac1d0007"; name = "โครงการพัฒนาท่าเรือแหลมฉบัง ระยะที่ 3 (ส่วนที่ 2) งานก่อสร้างอาคาร ท่าเทียบเรือ ระบบถนน และระบบสาธารณูปโภค"}
@{code = "LCBP3-C3"; uuid = "c957f57c-538b-11f1-8c7d-0242ac1d0007"; name = "โครงการพัฒนาท่าเรือแหลมฉบัง ระยะที่ 3 (ส่วนที่ 3) งานก่อสร้าง"}
@{code = "LCBP3-C4"; uuid = "c957f5cc-538b-11f1-8c7d-0242ac1d0007"; name = "โครงการพัฒนาท่าเรือแหลมฉบัง ระยะที่ 3 (ส่วนที่ 4) งานก่อสร้าง"}
)
availableOrganizations = @(
@{code = "กทท."; uuid = "c94cb0b4-538b-11f1-8c7d-0242ac1d0007"; name = "การท่าเรือแห่งประเทศไทย"}
@{code = "สคฉ.3"; uuid = "c94cb3f6-538b-11f1-8c7d-0242ac1d0007"; name = "โครงการพัฒนาท่าเรือแหลมฉบัง ระยะที่ 3"}
@{code = "สคฉ.3-01"; uuid = "c94cb532-538b-11f1-8c7d-0242ac1d0007"; name = "ตรวจรับพัสดุ ที่ปรึกษาควบคุมงาน"}
@{code = "สคฉ.3-02"; uuid = "c94cb5ab-538b-11f1-8c7d-0242ac1d0007"; name = "ตรวจรับพัสดุ งานทางทะเล"}
@{code = "สคฉ.3-03"; uuid = "c94cb616-538b-11f1-8c7d-0242ac1d0007"; name = "ตรวจรับพัสดุ อาคารและระบบสาธารณูปโภค"}
@{code = "คคง."; uuid = "c94cb8ac-538b-11f1-8c7d-0242ac1d0007"; name = "Construction Supervision Ltd."}
@{code = "ผรม.1"; uuid = "c94cb907-538b-11f1-8c7d-0242ac1d0007"; name = "Contractor งานทางทะเล"}
@{code = "ผรม.2"; uuid = "c94cb95e-538b-11f1-8c7d-0242ac1d0007"; name = "Contractor งานก่อสร้าง"}
@{code = "ผรม.3"; uuid = "c94cb9b3-538b-11f1-8c7d-0242ac1d0007"; name = "Contractor งานก่อสร้าง ส่วนที่ 3"}
@{code = "ผรม.4"; uuid = "c94cba0c-538b-11f1-8c7d-0242ac1d0007"; name = "Contractor งานก่อสร้าง ส่วนที่ 4"}
)
availableDisciplines = @(
@{code = "GEN"; name = "งานบริหารโครงการ"}
@{code = "COD"; name = "สัญญาและข้อโต้แย้ง"}
@{code = "QSB"; name = "สำรวจปริมาณและควบคุมงบประมาณ"}
@{code = "PPG"; name = "บริหารแผนและความก้าวหน้า"}
@{code = "BST"; name = "งานโครงสร้างอาคาร"}
@{code = "UTL"; name = "งานระบบสาธารณูปโภค"}
@{code = "EPW"; name = "งานระบบไฟฟ้า"}
@{code = "SRV"; name = "งานสำรวจ"}
@{code = "ODC"; name = "สำนักงาน-ควบคุมเอกสาร"}
)
availableCorrespondenceTypes = @(
@{code = "RFA"; name = "Request for Approval"}
@{code = "RFI"; name = "Request for Information"}
@{code = "TRANSMITTAL"; name = "Transmittal"}
@{code = "LETTER"; name = "Letter"}
@{code = "MEMO"; name = "Memorandum"}
@{code = "MOM"; name = "Minutes of Meeting"}
@{code = "NOTICE"; name = "Notice"}
@{code = "OTHER"; name = "Other"}
)
availableTags = @()
}
function Check-Models {
try {
$resp = Invoke-RestMethod -Uri "$OLLAMA_URL/api/ps" -Method Get -TimeoutSec 5
if ($resp.models) {
Write-Host " Models in VRAM: $($resp.models.name -join ', ')"
} else {
Write-Host " VRAM: ไม่มี model โหลดอยู่ (ว่าง)"
}
} catch {
Write-Host " Error checking models: $_"
}
}
Write-Host "=" * 60
Write-Host "🔍 ตรวจสอบ VRAM ก่อนรัน..."
Check-Models
$ocrText = Get-Content $OCR_TEXT_FILE -Raw -Encoding UTF8
Write-Host "`n📄 OCR text: $($ocrText.Length) chars"
$masterDataJson = $MASTER_DATA | ConvertTo-Json -Depth 10 -Compress:$false
$prompt = $TEMPLATE -replace "{{ocr_text}}", $ocrText -replace "{{master_data_context}}", $masterDataJson
Write-Host "📝 Total prompt: $($prompt.Length) chars"
Write-Host "=" * 60
Write-Host "⏳ กำลังส่งไปยัง Ollama..."
$body = @{
model = $MODEL
prompt = $prompt
stream = $false
} | ConvertTo-Json -Depth 10
$start = Get-Date
try {
$resp = Invoke-RestMethod -Uri "$OLLAMA_URL/api/generate" -Method Post -Body $body -ContentType "application/json" -TimeoutSec 180
$elapsed = (Get-Date - $start).TotalSeconds
$rawResponse = $resp.response
Write-Host "`n✅ Response ใน $([math]::Round($elapsed, 1))s"
Write-Host "-" * 60
Write-Host $rawResponse
Write-Host "-" * 60
$cleaned = $rawResponse -replace "```json", "" -replace "```", "" -replace "^\s+", "" -replace "\s+$", ""
try {
$parsed = $cleaned | ConvertFrom-Json
Write-Host "`n JSON parse สำเร็จ!"
$parsed | ConvertTo-Json -Depth 10
} catch {
Write-Host "`n JSON parse ล้มเหลว: $_"
Write-Host " Raw (200 chars): $($rawResponse.Substring(0, [Math]::Min(200, $rawResponse.Length)))"
}
} catch {
Write-Host "`n Error: $_"
}
Write-Host "`n🔍 ตรวจสอบ VRAM หลังรัน..."
Check-Models
@@ -0,0 +1,173 @@
"""
ทดสอบ typhoon2.5-np-dms โดยใช้ prompt template จริง + OCR text จาก test.md + master data context จาก DB
รันด้วย: python test_llm.py
"""
import json
import time
import urllib.request
import urllib.error
from pathlib import Path
OLLAMA_URL = "http://192.168.10.100:11434"
MODEL = "typhoon2.5-np-dms:latest"
OCR_TEXT_FILE = Path(__file__).parent / "test.md"
# --- Prompt Template (ดึงจาก DB: ai_prompts version=2, prompt_type=ocr_extraction) ---
TEMPLATE = """คุณคือเอนจิ้นสกัดข้อมูลอัจฉริยะ (Document Intelligence Engine)
วิเคราะห์ข้อความ OCR ที่ได้รับจากเอกสารของโครงการ Laem Chabang Port Phase 3 และสกัดข้อมูลเมตาดาต้าให้ออกมาเป็น JSON object ที่ถูกต้องตามโครงสร้างที่กำหนด
ข้อความ OCR ที่สกัดได้:
{{ocr_text}}
ข้อมูลอ้างอิงของระบบ (Master Data Context):
{{master_data_context}}
กฎการสกัดข้อมูล:
1. วิเคราะห์และจับคู่ข้อมูลจากข้อความ OCR กับข้อมูลอ้างอิงที่ระบุใน Master Data Context เสมอ
2. สำหรับโครงการ (project) ให้ค้นหาและสกัดส่งกลับเป็น UUID ของโครงการ (projectPublicId)
3. สำหรับประเภทเอกสารโต้ตอบ (correspondence type) ให้สกัดรหัสส่งกลับมา (correspondenceTypeCode) เช่น RFA, Transmittal
4. สำหรับสาขางาน (discipline) ให้ส่งคืนรหัสส่งกลับมา (disciplineCode) เช่น GEN, STR
5. สำหรับหน่วยงานผู้ส่ง (originator) ค้นหาจาก availableOrganizations และส่งกลับมาเป็น UUID (originatorOrganizationPublicId)
6. สำหรับหน่วยงานผู้รับ (recipients) ให้ส่งกลับมาเป็นรายการ Array ของออบเจกต์ ซึ่งมี UUID ขององค์กร (organizationPublicId) และประเภทผู้รับ (recipientType: "TO" หรือ "CC") เสมอ
7. สำหรับหัวข้อเอกสาร (subject) ให้สกัดหัวข้อหรือชื่อเรื่องของเอกสารภาษาไทยหรือภาษาอังกฤษ
8. วันที่ของเอกสาร (documentDate) ให้ส่งคืนในรูปแบบ YYYY-MM-DD
9. รายการแท็ก (tags) สกัดคำสำคัญหรือคำแนะนำ Tags (สอดคล้องกับ availableTags หากมี)
10. สรุปความเนื้อหา (summary) เขียนสรุปรายละเอียดเอกสารสั้นกระชับ 4-5 ประโยคเป็นภาษาไทยอย่างสละสลวย
11. confidence: ค่าความมั่นใจในการสกัดข้อมูลนี้ (ทศนิยมระหว่าง 0.0 ถึง 1.0)
ส่งคืนคำตอบเฉพาะ JSON Object ที่ถูกต้องเท่านั้น ห้ามใส่บล็อกโค้ด markdown หรือคำอธิบายเพิ่มเติมใดๆ
โครงสร้าง JSON ผลลัพธ์:
{
"projectPublicId": "string หรือ null",
"correspondenceTypeCode": "string หรือ null",
"disciplineCode": "string หรือ null",
"originatorOrganizationPublicId": "string หรือ null",
"recipients": [
{
"organizationPublicId": "string",
"recipientType": "TO หรือ CC"
}
],
"subject": "string หรือ null",
"documentDate": "string:YYYY-MM-DD หรือ null",
"tags": ["string"],
"summary": "string หรือ null",
"confidence": 0.95
}"""
# --- Master Data Context (ดึงจาก DB จริง) ---
MASTER_DATA = {
"availableProjects": [
{"code": "LCBP3", "uuid": "c957f1e3-538b-11f1-8c7d-0242ac1d0007", "name": "โครงการพัฒนาท่าเรือแหลมฉบัง ระยะที่ 3 (ส่วนที่ 1-4)"},
{"code": "LCBP3-C1", "uuid": "c957f44b-538b-11f1-8c7d-0242ac1d0007", "name": "โครงการพัฒนาท่าเรือแหลมฉบัง ระยะที่ 3 (ส่วนที่ 1) งานก่อสร้างงานทางทะเล"},
{"code": "LCBP3-C2", "uuid": "c957f523-538b-11f1-8c7d-0242ac1d0007", "name": "โครงการพัฒนาท่าเรือแหลมฉบัง ระยะที่ 3 (ส่วนที่ 2) งานก่อสร้างอาคาร ท่าเทียบเรือ ระบบถนน และระบบสาธารณูปโภค"},
{"code": "LCBP3-C3", "uuid": "c957f57c-538b-11f1-8c7d-0242ac1d0007", "name": "โครงการพัฒนาท่าเรือแหลมฉบัง ระยะที่ 3 (ส่วนที่ 3) งานก่อสร้าง"},
{"code": "LCBP3-C4", "uuid": "c957f5cc-538b-11f1-8c7d-0242ac1d0007", "name": "โครงการพัฒนาท่าเรือแหลมฉบัง ระยะที่ 3 (ส่วนที่ 4) งานก่อสร้าง"},
],
"availableOrganizations": [
{"code": "กทท.", "uuid": "c94cb0b4-538b-11f1-8c7d-0242ac1d0007", "name": "การท่าเรือแห่งประเทศไทย"},
{"code": "สคฉ.3", "uuid": "c94cb3f6-538b-11f1-8c7d-0242ac1d0007", "name": "โครงการพัฒนาท่าเรือแหลมฉบัง ระยะที่ 3"},
{"code": "สคฉ.3-01", "uuid": "c94cb532-538b-11f1-8c7d-0242ac1d0007", "name": "ตรวจรับพัสดุ ที่ปรึกษาควบคุมงาน"},
{"code": "สคฉ.3-02", "uuid": "c94cb5ab-538b-11f1-8c7d-0242ac1d0007", "name": "ตรวจรับพัสดุ งานทางทะเล"},
{"code": "สคฉ.3-03", "uuid": "c94cb616-538b-11f1-8c7d-0242ac1d0007", "name": "ตรวจรับพัสดุ อาคารและระบบสาธารณูปโภค"},
{"code": "คคง.", "uuid": "c94cb8ac-538b-11f1-8c7d-0242ac1d0007", "name": "Construction Supervision Ltd."},
{"code": "ผรม.1", "uuid": "c94cb907-538b-11f1-8c7d-0242ac1d0007", "name": "Contractor งานทางทะเล"},
{"code": "ผรม.2", "uuid": "c94cb95e-538b-11f1-8c7d-0242ac1d0007", "name": "Contractor งานก่อสร้าง"},
{"code": "ผรม.3", "uuid": "c94cb9b3-538b-11f1-8c7d-0242ac1d0007", "name": "Contractor งานก่อสร้าง ส่วนที่ 3"},
{"code": "ผรม.4", "uuid": "c94cba0c-538b-11f1-8c7d-0242ac1d0007", "name": "Contractor งานก่อสร้าง ส่วนที่ 4"},
],
"availableDisciplines": [
{"code": "GEN", "name": "งานบริหารโครงการ"},
{"code": "COD", "name": "สัญญาและข้อโต้แย้ง"},
{"code": "QSB", "name": "สำรวจปริมาณและควบคุมงบประมาณ"},
{"code": "PPG", "name": "บริหารแผนและความก้าวหน้า"},
{"code": "BST", "name": "งานโครงสร้างอาคาร"},
{"code": "UTL", "name": "งานระบบสาธารณูปโภค"},
{"code": "EPW", "name": "งานระบบไฟฟ้า"},
{"code": "SRV", "name": "งานสำรวจ"},
{"code": "ODC", "name": "สำนักงาน-ควบคุมเอกสาร"},
],
"availableCorrespondenceTypes": [
{"code": "RFA", "name": "Request for Approval"},
{"code": "RFI", "name": "Request for Information"},
{"code": "TRANSMITTAL", "name": "Transmittal"},
{"code": "LETTER", "name": "Letter"},
{"code": "MEMO", "name": "Memorandum"},
{"code": "MOM", "name": "Minutes of Meeting"},
{"code": "NOTICE", "name": "Notice"},
{"code": "OTHER", "name": "Other"},
],
"availableTags": [],
}
def check_models():
req = urllib.request.Request(f"{OLLAMA_URL}/api/ps")
with urllib.request.urlopen(req, timeout=5) as resp:
data = json.loads(resp.read())
models = data.get("models", [])
if models:
print(f" Models in VRAM: {[m['name'] for m in models]}")
else:
print(" VRAM: ไม่มี model โหลดอยู่ (ว่าง)")
def main():
print("=" * 60)
print("🔍 ตรวจสอบ VRAM ก่อนรัน...")
check_models()
ocr_text = OCR_TEXT_FILE.read_text(encoding="utf-8")
print(f"\n📄 OCR text: {len(ocr_text)} chars")
prompt = TEMPLATE.replace("{{ocr_text}}", ocr_text).replace(
"{{master_data_context}}", json.dumps(MASTER_DATA, ensure_ascii=False, indent=2)
)
print(f"📝 Total prompt: {len(prompt)} chars")
print("=" * 60)
print("⏳ กำลังส่งไปยัง Ollama...")
body = json.dumps({
"model": MODEL,
"prompt": prompt,
"stream": False,
}).encode("utf-8")
start = time.time()
req = urllib.request.Request(
f"{OLLAMA_URL}/api/generate",
data=body,
headers={"Content-Type": "application/json"},
method="POST",
)
try:
with urllib.request.urlopen(req, timeout=180) as resp:
result = json.loads(resp.read())
elapsed = time.time() - start
raw_response = result.get("response", "")
print(f"\n✅ Response ใน {elapsed:.1f}s")
print("-" * 60)
print(raw_response)
print("-" * 60)
# พยายาม parse JSON
cleaned = raw_response.replace("```json", "").replace("```", "").strip()
try:
parsed = json.loads(cleaned)
print("\n✅ JSON parse สำเร็จ!")
print(json.dumps(parsed, ensure_ascii=False, indent=2))
except json.JSONDecodeError as e:
print(f"\n❌ JSON parse ล้มเหลว: {e}")
print(f" Raw (200 chars): {raw_response[:200]!r}")
except urllib.error.URLError as e:
print(f"\n❌ Connection error: {e}")
print("\n🔍 ตรวจสอบ VRAM หลังรัน...")
check_models()
if __name__ == "__main__":
main()
Binary file not shown.