เชื่อมต่อ OIE API
คู่มือสำหรับเรียกบริการอ่านเอกสาร แชตคู่มือ และวิเคราะห์ข้อมูลโครงการจากระบบของทีม
1. ค่าที่ใช้เชื่อมต่อ
ใช้ access token ที่ทีมได้รับจากผู้ดูแล คู่มือออนไลน์ไม่แสดง token
Authorization: Bearer ACCESS_TOKEN ใช้ token เดียวกันสำหรับทั้ง 3 บริการ ไม่ต้องใส่ค่าการเชื่อมต่ออื่นAuthorization: Bearer YOUR_ACCESS_TOKEN
ส่งคำถามเป็น application/json และส่งเอกสารเป็น multipart/form-data ช่อง file รับผลลัพธ์ผ่าน HTTPS
2. API endpoints
| Method | Path ต่อจาก Base URL | บริการ |
|---|---|---|
| POST | /api/v2/extract | อ่าน PDF / DOCX · JSON รูปแบบเดียวกันทุกไฟล์ |
| POST | /api/extract | อ่านเอกสาร · รองรับรูปแบบเดิม |
| GET | /api/schema?view=response | JSON Schema ของผลลัพธ์ v2 |
| GET | /api/health | สถานะบริการอ่านเอกสาร |
| POST | /api/chat | แชตคู่มือ · JSON response |
| POST | /api/chat/stream | แชตคู่มือ · stream |
| POST | /api/admin/chat/stream | วิเคราะห์ข้อมูลโครงการ · stream |
| GET | /api/admin/status | สถานะและจำนวนแถวข้อมูลโครงการ |
| GET | /api/admin/healthz | สถานะบริการวิเคราะห์ข้อมูล |
3. อ่านเอกสาร PDF / DOCX
แนะนำ POST /api/v2/extract สำหรับระบบใหม่ รองรับ PDF และ DOCX หนึ่งไฟล์ต่อคำขอ สูงสุด 30 MB / 80 หน้า ประมวลผลทุกหน้าและคืน JSON โดยไม่ตัดหน้าทิ้ง
ส่ง include_ocr=true หากต้องการข้อความและตารางที่อ่านได้รายหน้าด้วย ผลลัพธ์จะมีขนาดใหญ่ขึ้น ตั้ง timeout ฝั่ง client สูงสุด 1,800 วินาทีสำหรับเอกสารยาว
cURL · PDF
curl --fail-with-body --max-time 1800 \ 'https://oie.thinkv.app/api/v2/extract' \ -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \ -F 'file=@project.pdf'
cURL · DOCX พร้อมข้อมูลรายหน้า
curl --fail-with-body --max-time 1800 \ 'https://oie.thinkv.app/api/v2/extract?include_ocr=true' \ -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \ -F 'file=@project.docx'
Python · ใช้ requests
from pathlib import Path
import requests
BASE_URL = "https://oie.thinkv.app"
ACCESS_TOKEN = "YOUR_ACCESS_TOKEN"
with Path("project.pdf").open("rb") as document:
response = requests.post(
BASE_URL + "/api/v2/extract",
headers={"Authorization": "Bearer " + ACCESS_TOKEN},
files={"file": ("project.pdf", document, "application/pdf")},
timeout=(15, 1800),
)
response.raise_for_status()
result = response.json()
if not result["document"]["complete"]:
raise RuntimeError("อ่านเอกสารไม่ครบ")
project_name = result["data"]["project_name"]
budget_baht = result["budget"]["amount_baht"]
needs_review = result["quality"]["needs_review"]
budget_items = result["structured"]["budget_items"]
print(project_name, budget_baht, needs_review)JavaScript · ใช้ fetch
const BASE_URL = "https://oie.thinkv.app";
const ACCESS_TOKEN = "YOUR_ACCESS_TOKEN";
const form = new FormData();
form.append("file", fileInput.files[0]);
const response = await fetch(BASE_URL + "/api/v2/extract", {
method: "POST",
headers: { Authorization: "Bearer " + ACCESS_TOKEN },
body: form,
signal: AbortSignal.timeout(1800_000),
});
const result = await response.json();
if (!response.ok) throw new Error(result.code + ": " + result.error);
console.log(result.data, result.structured, result.quality);
// FormData กำหนด multipart boundary ให้เอง ไม่ตั้ง Content-Type เอง4. ผลลัพธ์ที่ระบบปลายทางควรใช้
| Field | การใช้งาน |
|---|---|
data | ข้อมูลโครงการ 24 ช่อง ชนิดเหมือนกันทั้ง PDF และ DOCX |
summary | สรุปเนื้อหาโครงการเป็นภาษาไทย |
budget.amount_baht | งบประมาณเป็นบาทแบบ decimal string เมื่อยืนยันหน่วยได้; null เมื่อไม่ทราบหรือขัดแย้ง |
structured | project_info, budget_items, kpi_items, schedule, additional_sections, conflicts |
tables | ตารางรายหน้า พร้อม columns, rows, id, page และ shape_valid |
evidence | ข้อความอ้างอิงและเลขหน้าแบบ 1-based ต่อ field |
quality.needs_review | true เมื่อควรตรวจเอกสารต้นฉบับก่อนนำข้อมูลไปใช้ |
quality.field_status | missing / supported / unverified |
document | page_count, pages_processed, complete, page_numbering สำหรับตรวจว่าครบทุกหน้าและอ้างอิงหน้าต้นฉบับ |
scalar ที่ไม่พบเป็น null; รายการที่ไม่พบเป็น [] ใช้ budget.amount_baht สำหรับยอดเป็นบาท อย่าถือว่า data.budget เป็นบาทเสมอ เพราะอาจเป็นพันบาทหรือล้านบาทตามต้นฉบับ
ตรวจ document.complete และ quality.needs_review ก่อนบันทึกข้อมูลอัตโนมัติ การอ้างอิงที่ตรวจพบยังควรตรวจความหมายของข้อมูลสำคัญจากต้นฉบับ
ข้อมูลโครงการ 24 ช่อง
| Field | Type | ความหมาย |
|---|---|---|
data.budget | string | null | งบประมาณตามหน่วยในต้นฉบับ |
data.project_name | string | null | ชื่อโครงการ |
data.kpi | string | null | ตัวชี้วัดและเป้าหมาย |
data.how | string | null | วิธีดำเนินงานและกิจกรรม |
data.methodology | string | null | หลักการและเหตุผล |
data.result | string | null | มูลค่าทางเศรษฐกิจและวิธีคำนวณ |
data.flagship | string | null | ชื่อโครงการหลัก / ผลผลิต |
data.focus | string | null | ประเด็นที่เลือก |
data.plan | string | null | แผนดำเนินงานและช่วงเวลา |
data.target | string | null | เป้าหมายแผนงานบูรณาการ |
data.strategic | string | null | ยุทธศาสตร์และแผนที่เกี่ยวข้อง |
data.target_industry | string | null | อุตสาหกรรมเป้าหมาย |
data.place | string | null | สถานที่ดำเนินงาน |
data.integration_goal | string | null | เป้าหมายแผนงานบูรณาการ |
data.integration_target_kpi | string | null | ตัวชี้วัดเป้าหมายแผนงานบูรณาการ |
data.integration_approach | string | null | แนวทางดำเนินงานแผนงานบูรณาการ |
data.integration_approach_kpi | string | null | ตัวชี้วัดแนวทางดำเนินงาน |
data.responsible_department | string | null | หน่วยงานรับผิดชอบ |
data.exp_benefit | string[] | ผลประโยชน์ที่คาดว่าจะได้รับ |
data.objective | string[] | วัตถุประสงค์ |
data.target_group | string[] | กลุ่มเป้าหมาย |
data.link | string[] | ประเด็นเชื่อมโยง |
data.is_flagship | 0 | 1 | null | 1 = ใช่, 0 = ไม่ใช่, null = ไม่พบ / ไม่ชัดเจน |
data.responsible_details | object[] | ผู้รับผิดชอบ: first_name, last_name, email, phone, department |
ตัวอย่าง JSON · คัดเฉพาะ fields ที่ใช้บ่อย
{
"document_type": "proposal",
"data": {
"budget": "2.50",
"exp_benefit": [
"ลดต้นทุนการตรวจคุณภาพ",
"เพิ่มรายได้ของวิสาหกิจชุมชน"
],
"flagship": "โครงการยกระดับอุตสาหกรรมอาหารแห่งอนาคต",
"focus": null,
"how": "สำรวจ 12 ชุมชน พัฒนาระบบ และอบรม 24 คน",
"integration_approach": "พัฒนามาตรฐานอาหาร",
"integration_approach_kpi": "ผู้ประกอบการผ่านมาตรฐาน 12 ราย",
"integration_goal": "เพิ่มมูลค่าอาหารปลอดภัย",
"integration_target_kpi": "รายได้เพิ่มร้อยละ 5",
"is_flagship": 1,
"kpi": "ระบบตรวจคุณภาพ 1 ระบบ; ผู้ผ่านการอบรม 24 คน",
"link": [
"อุตสาหกรรมอาหารแห่งอนาคต"
],
"methodology": "ผู้ประกอบการชุมชนขาดเครื่องมือตรวจคุณภาพอาหาร",
"objective": [
"เพื่อพัฒนาระบบตรวจคุณภาพอาหารชุมชน",
"เพื่อฝึกอบรมผู้ประกอบการ 24 คน"
],
"place": "ระดับจังหวัด ขอนแก่น",
"plan": "ตุลาคม 2568: สำรวจ; พฤศจิกายน 2568: พัฒนาระบบ; ธันวาคม 2568: อบรม",
"project_name": "โครงการทดสอบระบบอาหารปลอดภัยชุมชน",
"responsible_department": "ศูนย์ทดสอบอาหารชุมชน",
"responsible_details": [
{
"department": "",
"email": "somchai@example.org",
"first_name": "สมชาย",
"last_name": "ใจดี",
"phone": "02-1234567 ต่อ 89"
}
],
"result": "ประมาณการมูลค่าทางเศรษฐกิจที่เพิ่มขึ้นจากการดำเนินโครงการ 5 ล้านบาทต่อปี",
"strategic": "การสร้างความสามารถในการแข่งขัน",
"target": "เพิ่มมูลค่าอาหารปลอดภัย",
"target_group": [
"วิสาหกิจชุมชน 12 แห่ง",
"บุคลากรห้องปฏิบัติการ 24 คน"
],
"target_industry": "อุตสาหกรรมอาหารแห่งอนาคต"
},
"summary": "โครงการทดสอบระบบอาหารปลอดภัยชุมชน ประจำปีงบประมาณ พ.ศ. 2569 มีโครงการเทียบเท่าผลผลิตคือโครงการยกระดับอุตสาหกรรมอาหารแห่งอนาคต และระบุว่าเป็นโครงการสำคัญ เชื่อมโยงกับอุตสาหกรรมอาหารแห่งอนาคตและเป้าหมายเพิ่มมูลค่าอาหารปลอดภัย โดยมีตัวชี้วัดเป้าหมายรายได้เพิ่มร้อยละ 5 และผู้ประกอบการผ่านมาตรฐาน 12 ราย เหตุผลคือผู้ประกอบการชุมชนขาดเครื่องมือตรวจคุณภาพอาหาร มีวัตถุประสงค์เพื่อพัฒนาระบบตรวจคุณภาพอาหารชุมชนและฝึกอบรมผู้ประกอบการ 24 คน กลุ่มเป้าหมายคือวิสาหกิจชุมชน 12 แห่งและบุคลากรห้องปฏิบัติการ 24 คน กิจกรรมประกอบด้วยสำรวจ 12 ชุมชน พัฒนาระบบ และอบรม 24 คน ในเดือนตุลาคม พฤศจิกายน และธันวาคม 2568 ตามลำดับ ตัวชี้วัดโครงการคือระบบตรวจคุณภาพ 1 ระบบและผู้ผ่านการอบรม 24 คน งบประมาณ 2.50 ล้านบาท ดำเนินการระดับจังหวัดที่ขอนแก่น คาดว่าจะลดต้นทุนการตรวจคุณภาพและเพิ่มรายได้ของวิสาหกิจชุมชน โดยประมาณมูลค่าทางเศรษฐกิจที่เพิ่มขึ้น 5 ล้านบาทต่อปี หน่วยงานรับผิดชอบคือศูนย์ทดสอบอาหารชุมชน",
"budget": {
"ambiguous": false,
"amount": "2.50",
"amount_baht": "2500000.00",
"raw_text": "2.50 ล้านบาท (สองล้านห้าแสนบาทถ้วน)",
"unit": "ล้านบาท"
},
"structured": {
"additional_sections": [
{
"heading": "ประมาณการมูลค่าทางเศรษฐกิจที่เพิ่มขึ้นจากการดำเนินโครงการ",
"source_verified": true,
"sources": [
{
"page": 3,
"quote": "12. ประมาณการมูลค่าทางเศรษฐกิจที่เพิ่มขึ้นจากการดำเนินโครงการ: 5 ล้านบาทต่อปี",
"row": null,
"table_id": null,
"verified": true
}
],
"text": "5 ล้านบาทต่อปี"
}
],
"budget_items": [
{
"amount": "2.50",
"amount_baht": "2500000.00",
"arithmetic_status": "not_checked",
"calculation": "unspecified",
"currency_unit": "ล้านบาท",
"item": "งบประมาณโครงการ",
"quantity": null,
"quantity_unit": null,
"row_type": "grand_total",
"source_verified": true,
"sources": [
{
"page": 3,
"quote": "9. งบประมาณ 2.50 ล้านบาท (สองล้านห้าแสนบาทถ้วน)",
"row": null,
"table_id": null,
"verified": true
}
],
"unit_price": null
}
],
"conflicts": [],
"kpi_items": [
{
"indicator": "ระบบตรวจคุณภาพ",
"level": "output",
"period": null,
"source_verified": true,
"sources": [
{
"page": 2,
"quote": "6. ตัวชี้วัดโครงการ: ระบบตรวจคุณภาพ 1 ระบบ; ผู้ผ่านการอบรม 24 คน",
"row": null,
"table_id": null,
"verified": true
}
],
"target": "1",
"target_text": "1 ระบบ",
"unit": "ระบบ"
},
{
"indicator": "ผู้ผ่านการอบรม",
"level": "output",
"period": null,
"source_verified": true,
"sources": [
{
"page": 2,
"quote": "6. ตัวชี้วัดโครงการ: ระบบตรวจคุณภาพ 1 ระบบ; ผู้ผ่านการอบรม 24 คน",
"row": null,
"table_id": null,
"verified": true
}
],
"target": "24",
"target_text": "24 คน",
"unit": "คน"
}
],
"project_info": {
"duration": null,
"fiscal_year": "2569",
"project_code": null,
"project_type": null,
"source_verified": true,
"sources": [
{
"page": 1,
"quote": "ข้อเสนอโครงการ ประจำปีงบประมาณ พ.ศ. 2569",
"row": null,
"table_id": null,
"verified": true
}
]
},
"schedule": [
{
"activity": "สำรวจ",
"deliverable": null,
"months": [
"ตุลาคม 2568"
],
"period": "ตุลาคม 2568",
"source_verified": true,
"sources": [
{
"page": 2,
"quote": "ตุลาคม 2568 สำรวจ",
"row": null,
"table_id": null,
"verified": true
}
],
"target": null,
"unit": null,
"unverified_months": [],
"unverified_period": null
},
{
"activity": "พัฒนาระบบ",
"deliverable": null,
"months": [
"พฤศจิกายน 2568"
],
"period": "พฤศจิกายน 2568",
"source_verified": true,
"sources": [
{
"page": 2,
"quote": "พฤศจิกายน 2568 พัฒนาระบบ",
"row": null,
"table_id": null,
"verified": true
}
],
"target": null,
"unit": null,
"unverified_months": [],
"unverified_period": null
},
{
"activity": "อบรม",
"deliverable": null,
"months": [
"ธันวาคม 2568"
],
"period": "ธันวาคม 2568",
"source_verified": true,
"sources": [
{
"page": 2,
"quote": "ธันวาคม 2568 อบรม",
"row": null,
"table_id": null,
"verified": true
}
],
"target": null,
"unit": null,
"unverified_months": [],
"unverified_period": null
}
]
},
"quality": {
"evidence_validation": "quote_occurrence_only_not_semantic_verification",
"field_status": {
"budget": "supported",
"exp_benefit": "supported",
"flagship": "supported",
"focus": "missing",
"how": "supported",
"integration_approach": "supported",
"integration_approach_kpi": "supported",
"integration_goal": "supported",
"integration_target_kpi": "supported",
"is_flagship": "supported",
"kpi": "supported",
"link": "supported",
"methodology": "supported",
"objective": "supported",
"place": "supported",
"plan": "supported",
"project_name": "supported",
"responsible_department": "supported",
"responsible_details": "supported",
"result": "supported",
"strategic": "supported",
"target": "supported",
"target_group": "supported",
"target_industry": "supported"
},
"missing_fields": [
"focus"
],
"needs_review": false,
"unverified_fields": [],
"validation_issues": [],
"warnings": []
},
"document": {
"page_count": 3,
"pages_processed": 3,
"complete": true,
"page_numbering": "source_pdf"
}
}JSON Schema ของ response v2 ฉบับเต็ม
{
"$defs": {
"OutputBudget": {
"additionalProperties": false,
"properties": {
"amount": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Amount"
},
"unit": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Unit"
},
"amount_baht": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Amount Baht"
},
"raw_text": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Raw Text"
},
"ambiguous": {
"title": "Ambiguous",
"type": "boolean"
}
},
"required": [
"amount",
"unit",
"amount_baht",
"raw_text",
"ambiguous"
],
"title": "OutputBudget",
"type": "object"
},
"OutputBudgetItem": {
"additionalProperties": false,
"properties": {
"item": {
"title": "Item",
"type": "string"
},
"row_type": {
"enum": [
"item",
"subtotal",
"grand_total"
],
"title": "Row Type",
"type": "string"
},
"quantity": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Quantity"
},
"quantity_unit": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Quantity Unit"
},
"unit_price": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Unit Price"
},
"amount": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Amount"
},
"currency_unit": {
"anyOf": [
{
"enum": [
"บาท",
"พันบาท",
"ล้านบาท"
],
"type": "string"
},
{
"type": "null"
}
],
"title": "Currency Unit"
},
"calculation": {
"enum": [
"quantity_times_unit_price",
"other",
"unspecified"
],
"title": "Calculation",
"type": "string"
},
"sources": {
"items": {
"$ref": "#/$defs/VerifiedSource"
},
"title": "Sources",
"type": "array"
},
"source_verified": {
"title": "Source Verified",
"type": "boolean"
},
"amount_baht": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Amount Baht"
},
"arithmetic_status": {
"enum": [
"not_checked",
"matched",
"mismatch"
],
"title": "Arithmetic Status",
"type": "string"
}
},
"required": [
"item",
"row_type",
"quantity",
"quantity_unit",
"unit_price",
"amount",
"currency_unit",
"calculation",
"sources",
"source_verified",
"amount_baht",
"arithmetic_status"
],
"title": "OutputBudgetItem",
"type": "object"
},
"OutputConflict": {
"additionalProperties": false,
"properties": {
"field": {
"title": "Field",
"type": "string"
},
"description": {
"title": "Description",
"type": "string"
},
"sources": {
"items": {
"$ref": "#/$defs/VerifiedSource"
},
"title": "Sources",
"type": "array"
},
"source_verified": {
"title": "Source Verified",
"type": "boolean"
}
},
"required": [
"field",
"description",
"sources",
"source_verified"
],
"title": "OutputConflict",
"type": "object"
},
"OutputDocument": {
"additionalProperties": false,
"properties": {
"page_count": {
"title": "Page Count",
"type": "integer"
},
"pages_processed": {
"title": "Pages Processed",
"type": "integer"
},
"complete": {
"title": "Complete",
"type": "boolean"
},
"page_numbering": {
"enum": [
"rendered_pdf",
"source_pdf"
],
"title": "Page Numbering",
"type": "string"
}
},
"required": [
"page_count",
"pages_processed",
"complete",
"page_numbering"
],
"title": "OutputDocument",
"type": "object"
},
"OutputInfo": {
"additionalProperties": false,
"properties": {
"project_code": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Project Code"
},
"fiscal_year": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Preserve Buddhist/Gregorian year as written; do not convert.",
"title": "Fiscal Year"
},
"project_type": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Project Type"
},
"duration": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Duration"
},
"sources": {
"items": {
"$ref": "#/$defs/VerifiedSource"
},
"title": "Sources",
"type": "array"
},
"source_verified": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"title": "Source Verified"
}
},
"required": [
"project_code",
"fiscal_year",
"project_type",
"duration",
"sources",
"source_verified"
],
"title": "OutputInfo",
"type": "object"
},
"OutputKPI": {
"additionalProperties": false,
"properties": {
"indicator": {
"title": "Indicator",
"type": "string"
},
"level": {
"enum": [
"output",
"outcome",
"impact",
"unspecified"
],
"title": "Level",
"type": "string"
},
"target": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Numeric target only; null if not a single number.",
"title": "Target"
},
"target_text": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Original comparator/range and target, e.g. ไม่น้อยกว่าร้อยละ 80.",
"title": "Target Text"
},
"unit": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Unit"
},
"period": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Period"
},
"sources": {
"items": {
"$ref": "#/$defs/VerifiedSource"
},
"title": "Sources",
"type": "array"
},
"source_verified": {
"title": "Source Verified",
"type": "boolean"
}
},
"required": [
"indicator",
"level",
"target",
"target_text",
"unit",
"period",
"sources",
"source_verified"
],
"title": "OutputKPI",
"type": "object"
},
"OutputQuality": {
"additionalProperties": false,
"properties": {
"needs_review": {
"title": "Needs Review",
"type": "boolean"
},
"field_status": {
"additionalProperties": {
"enum": [
"missing",
"supported",
"unverified"
],
"type": "string"
},
"title": "Field Status",
"type": "object"
},
"missing_fields": {
"items": {
"type": "string"
},
"title": "Missing Fields",
"type": "array"
},
"unverified_fields": {
"items": {
"type": "string"
},
"title": "Unverified Fields",
"type": "array"
},
"warnings": {
"items": {
"type": "string"
},
"title": "Warnings",
"type": "array"
},
"validation_issues": {
"items": {
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"title": "Validation Issues",
"type": "array"
},
"evidence_validation": {
"title": "Evidence Validation",
"type": "string"
}
},
"required": [
"needs_review",
"field_status",
"missing_fields",
"unverified_fields",
"warnings",
"validation_issues",
"evidence_validation"
],
"title": "OutputQuality",
"type": "object"
},
"OutputSchedule": {
"additionalProperties": false,
"properties": {
"activity": {
"title": "Activity",
"type": "string"
},
"period": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Period"
},
"months": {
"description": "Explicitly active month/quarter column labels only; do not convert fiscal month numbers to calendar months. Ambiguous marks=[] and report conflict.",
"items": {
"type": "string"
},
"title": "Months",
"type": "array"
},
"deliverable": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Deliverable"
},
"target": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Target"
},
"unit": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Unit"
},
"sources": {
"items": {
"$ref": "#/$defs/VerifiedSource"
},
"title": "Sources",
"type": "array"
},
"source_verified": {
"title": "Source Verified",
"type": "boolean"
},
"unverified_months": {
"description": "Model-read month labels withheld from months when source references cannot be verified; review the original before using.",
"items": {
"type": "string"
},
"title": "Unverified Months",
"type": "array"
},
"unverified_period": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Model-read period withheld from period when source references cannot be verified.",
"title": "Unverified Period"
}
},
"required": [
"activity",
"period",
"months",
"deliverable",
"target",
"unit",
"sources",
"source_verified",
"unverified_months",
"unverified_period"
],
"title": "OutputSchedule",
"type": "object"
},
"OutputSection": {
"additionalProperties": false,
"properties": {
"heading": {
"title": "Heading",
"type": "string"
},
"text": {
"title": "Text",
"type": "string"
},
"sources": {
"items": {
"$ref": "#/$defs/VerifiedSource"
},
"title": "Sources",
"type": "array"
},
"source_verified": {
"title": "Source Verified",
"type": "boolean"
}
},
"required": [
"heading",
"text",
"sources",
"source_verified"
],
"title": "OutputSection",
"type": "object"
},
"OutputStructured": {
"additionalProperties": false,
"properties": {
"project_info": {
"$ref": "#/$defs/OutputInfo"
},
"budget_items": {
"items": {
"$ref": "#/$defs/OutputBudgetItem"
},
"title": "Budget Items",
"type": "array"
},
"kpi_items": {
"items": {
"$ref": "#/$defs/OutputKPI"
},
"title": "Kpi Items",
"type": "array"
},
"schedule": {
"items": {
"$ref": "#/$defs/OutputSchedule"
},
"title": "Schedule",
"type": "array"
},
"additional_sections": {
"items": {
"$ref": "#/$defs/OutputSection"
},
"title": "Additional Sections",
"type": "array"
},
"conflicts": {
"items": {
"$ref": "#/$defs/OutputConflict"
},
"title": "Conflicts",
"type": "array"
}
},
"required": [
"project_info",
"budget_items",
"kpi_items",
"schedule",
"additional_sections",
"conflicts"
],
"title": "OutputStructured",
"type": "object"
},
"OutputTable": {
"additionalProperties": false,
"properties": {
"title": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Title"
},
"kind": {
"enum": [
"budget",
"kpi",
"timeline",
"strategy",
"history",
"other"
],
"title": "Kind",
"type": "string"
},
"columns": {
"description": "Column labels in visual order, including multi-level header context. Unlabelled column = empty string.",
"items": {
"type": "string"
},
"title": "Columns",
"type": "array"
},
"rows": {
"description": "Every visible data row, same width as columns. Preserve text, units, marks and amounts verbatim; empty/merged continuation cells=null. Do not drop totals or sparse rows.",
"items": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"type": "array"
},
"title": "Rows",
"type": "array"
},
"notes": {
"items": {
"type": "string"
},
"title": "Notes",
"type": "array"
},
"id": {
"title": "Id",
"type": "string"
},
"page": {
"title": "Page",
"type": "integer"
},
"shape_valid": {
"title": "Shape Valid",
"type": "boolean"
}
},
"required": [
"title",
"kind",
"columns",
"rows",
"notes",
"id",
"page",
"shape_valid"
],
"title": "OutputTable",
"type": "object"
},
"Person": {
"additionalProperties": false,
"properties": {
"first_name": {
"title": "First Name",
"type": "string"
},
"last_name": {
"title": "Last Name",
"type": "string"
},
"email": {
"title": "Email",
"type": "string"
},
"phone": {
"title": "Phone",
"type": "string"
},
"department": {
"title": "Department",
"type": "string"
}
},
"required": [
"first_name",
"last_name",
"email",
"phone",
"department"
],
"title": "Person",
"type": "object"
},
"ProjectData": {
"additionalProperties": false,
"properties": {
"budget": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Numeric total budget exactly as stated, without commas, in the stated unit. Do not scale. Null if no explicit total.",
"title": "Budget"
},
"project_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Actual project title, not parent output/program title. If both โครงการ/ผลผลิต and โครงการ appear choose the latter.",
"title": "Project Name"
},
"kpi": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "All project output/outcome indicators with numeric targets and units; preserve table associations.",
"title": "Kpi"
},
"how": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Implementation activities/methods. Preserve all numbered activities and substantive details.",
"title": "How"
},
"methodology": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "หลักการและเหตุผล: rationale and problem statement, NOT implementation methods.",
"title": "Methodology"
},
"result": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Estimated economic value/impact and its calculation, not generic expected benefits.",
"title": "Result"
},
"flagship": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "ชื่อโครงการเทียบเท่าผลผลิต or parent โครงการ/ผลผลิต title; not the yes/no checkbox.",
"title": "Flagship"
},
"focus": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Explicitly selected Focus issues only; null if absent.",
"title": "Focus"
},
"plan": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Implementation timeline, activities and months/quarters/durations; keep table relationships.",
"title": "Plan"
},
"target": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Integrated program goal, same as integration_goal when supplied.",
"title": "Target"
},
"strategic": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "National strategies/master plans and selected subplans, codes and targets.",
"title": "Strategic"
},
"target_industry": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Explicit target industries only.",
"title": "Target Industry"
},
"place": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Selected/explicit implementation locations only; omit unchecked alternatives.",
"title": "Place"
},
"integration_goal": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "เป้าหมายแผนงานบูรณาการฯ, regardless of numbering.",
"title": "Integration Goal"
},
"integration_target_kpi": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "ตัวชี้วัดเป้าหมายแผนงานบูรณาการฯ, including units/targets.",
"title": "Integration Target Kpi"
},
"integration_approach": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "แนวทางการดำเนินงานแผนงานบูรณาการฯ.",
"title": "Integration Approach"
},
"integration_approach_kpi": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "ตัวชี้วัดแนวทางแผนงานบูรณาการฯ, including units/targets.",
"title": "Integration Approach Kpi"
},
"responsible_department": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Actual department/agency responsible for this project, not the template publisher.",
"title": "Responsible Department"
},
"exp_benefit": {
"description": "Expected benefits (ผลประโยชน์ที่คาดว่าจะได้รับ), one complete item per entry.",
"items": {
"type": "string"
},
"title": "Exp Benefit",
"type": "array"
},
"objective": {
"description": "All stated objectives, one complete objective per entry. Do not invent or merge items.",
"items": {
"type": "string"
},
"title": "Objective",
"type": "array"
},
"target_group": {
"description": "Target beneficiary groups, one complete group per entry, including quantities.",
"items": {
"type": "string"
},
"title": "Target Group",
"type": "array"
},
"link": {
"description": "Only selected related integration issues in checkbox forms, or explicit integration linkage in other forms.",
"items": {
"type": "string"
},
"title": "Link",
"type": "array"
},
"is_flagship": {
"anyOf": [
{
"enum": [
0,
1
],
"type": "integer"
},
{
"type": "null"
}
],
"description": "1 if explicitly checked ใช่, 0 if explicitly checked ไม่ใช่; null if absent/ambiguous.",
"title": "Is Flagship"
},
"responsible_details": {
"description": "All named project contacts. No invented name splits/contact information. Empty string for absent components.",
"items": {
"$ref": "#/$defs/Person"
},
"title": "Responsible Details",
"type": "array"
}
},
"required": [
"budget",
"project_name",
"kpi",
"how",
"methodology",
"result",
"flagship",
"focus",
"plan",
"target",
"strategic",
"target_industry",
"place",
"integration_goal",
"integration_target_kpi",
"integration_approach",
"integration_approach_kpi",
"responsible_department",
"exp_benefit",
"objective",
"target_group",
"link",
"is_flagship",
"responsible_details"
],
"title": "ProjectData",
"type": "object"
},
"VerifiedSource": {
"additionalProperties": false,
"properties": {
"page": {
"title": "Page",
"type": "integer"
},
"quote": {
"title": "Quote",
"type": "string"
},
"table_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Server-assigned pN-tM id if source is a table, otherwise null.",
"title": "Table Id"
},
"row": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"description": "1-based data row of source table, otherwise null. Headers are not data rows.",
"title": "Row"
},
"verified": {
"title": "Verified",
"type": "boolean"
}
},
"required": [
"page",
"quote",
"table_id",
"row",
"verified"
],
"title": "VerifiedSource",
"type": "object"
}
},
"additionalProperties": false,
"properties": {
"document_type": {
"title": "Document Type",
"type": "string"
},
"document": {
"$ref": "#/$defs/OutputDocument"
},
"data": {
"$ref": "#/$defs/ProjectData"
},
"summary": {
"title": "Summary",
"type": "string"
},
"budget": {
"$ref": "#/$defs/OutputBudget"
},
"structured": {
"$ref": "#/$defs/OutputStructured"
},
"tables": {
"items": {
"$ref": "#/$defs/OutputTable"
},
"title": "Tables",
"type": "array"
},
"quality": {
"$ref": "#/$defs/OutputQuality"
},
"evidence": {
"additionalProperties": {
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
"title": "Evidence",
"type": "object"
},
"ocr_pages": {
"items": {
"additionalProperties": true,
"type": "object"
},
"title": "Ocr Pages",
"type": "array"
}
},
"required": [
"document_type",
"document",
"data",
"summary",
"budget",
"structured",
"tables",
"quality",
"evidence"
],
"title": "CanonicalResponse",
"type": "object"
}endpoint เดิม POST /api/extract ยังใช้งานได้ โดยผลใหม่อยู่ใต้ _extraction; ระบบใหม่ควรใช้ v2
5. Chat API
ส่ง message เป็นข้อความที่ไม่ว่าง และ session_id เป็น string ยาวไม่เกิน 128 ตัวอักษร ใช้ค่าเดิมในบทสนทนาเดิม และสร้างค่าใหม่เมื่อเริ่มบทสนทนาใหม่ เช่น UUID ของแต่ละผู้ใช้
แชตคู่มือ · รับ JSON
curl --fail-with-body 'https://oie.thinkv.app/api/chat' \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"message":"ขั้นตอนการยื่นข้อเสนอโครงการมีอะไรบ้าง?","session_id":"your-app-user-session-001"}'{"response":"ข้อความคำตอบภาษาไทย"}แชตแบบ streaming ทั้ง 2 บริการ
# แชตคู่มือ
curl -N --fail-with-body 'https://oie.thinkv.app/api/chat/stream' \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"message":"การติดตามผลโครงการทำอย่างไร?","session_id":"your-app-user-session-001"}'
# แชตวิเคราะห์ข้อมูลโครงการ
curl -N --fail-with-body 'https://oie.thinkv.app/api/admin/chat/stream' \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"message":"มีโครงการทั้งหมดกี่โครงการ?","session_id":"your-app-user-session-001"}'Streaming เป็นรายการ data: JSON คั่นด้วยบรรทัดว่าง และสิ้นสุดเมื่อพบ done หรือ complete:
# แชตคู่มือ
data: {"content":"ข้อความส่วนหนึ่ง", "done":false}
data: {"content":"", "done":true}
# วิเคราะห์ข้อมูลโครงการ
data: {"chunk":"ข้อความส่วนหนึ่ง"}
data: {"complete":true}หนึ่ง network chunk อาจมีครึ่งรายการหรือหลายรายการ ให้เก็บ buffer ก่อนแยกด้วยบรรทัดว่าง
JavaScript · อ่าน stream พร้อม buffer
async function readChat(message, sessionId, onChunk) {
const response = await fetch("https://oie.thinkv.app/api/chat/stream", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_ACCESS_TOKEN",
"Content-Type": "application/json",
},
body: JSON.stringify({ message, session_id: sessionId }),
});
if (!response.ok) throw new Error("HTTP " + response.status);
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
while (true) {
const { value, done } = await reader.read();
buffer += decoder.decode(value, { stream: !done });
let boundary;
while ((boundary = buffer.indexOf("\n\n")) >= 0) {
const event = buffer.slice(0, boundary);
buffer = buffer.slice(boundary + 2);
const line = event.split("\n").find(line => line.startsWith("data: "));
if (!line) continue;
const item = JSON.parse(line.slice(6));
if (item.error) throw new Error(item.error);
if (item.content || item.chunk) onChunk(item.content || item.chunk);
if (item.done || item.complete) return;
}
if (done) break;
}
}6. ข้อผิดพลาดและการลองใหม่
{"error":"รายละเอียดข้อผิดพลาด", "code":"missing_file"}| HTTP | สาเหตุ / วิธีรับมือ |
|---|---|
| 400 | ไม่มี file หรือ message; แก้ request ก่อนส่งใหม่ |
| 401 | ไม่ได้ส่ง access token หรือ token ไม่ถูกต้อง; ตรวจ Authorization header |
| 413 | ไฟล์เกินขนาด จำนวนหน้า หรือข้อความเกินขีดจำกัด |
| 415 | รองรับเฉพาะ PDF / DOCX |
| 422 | เอกสารเสียหาย มีรหัสผ่าน ไม่มีข้อความ หรือไม่ใช่เอกสารโครงการที่รองรับ |
| 502 | ผลประมวลผลไม่ครบหรือไม่ผ่านการตรวจรูปแบบ |
| 503 | ระบบไม่พร้อมหรือ busy; สำหรับ busy / provider_rate_limit ให้รอตาม Retry-After แล้วลองใหม่แบบเพิ่มระยะห่าง |
| 504 | คำขอหมดเวลา; ลองใหม่และส่งค่า X-Request-ID จาก response header ให้ผู้ดูแลหากเกิดซ้ำ |
งานเอกสารที่อ่านไม่สำเร็จจะไม่ส่งข้อมูลบางส่วนเป็นผลสำเร็จ สำหรับ streaming ให้ตรวจ error ในรายการด้วย แม้ HTTP response จะเป็น 200
7. ทดลองเรียก API จากไฟล์คู่มือนี้
ค่าการเชื่อมต่อใช้ Base URL และ access token ด้านบน เลือกเอกสารแล้วกดส่งเพื่ออ่านจริง