690604:0832 ADR-034-134 #03
This commit is contained in:
@@ -8,9 +8,11 @@
|
|||||||
// - 2026-05-29: ปรับปรุงการโหลด Active Prompt ให้ทนทานต่อ race conditions และรูปแบบประเภทข้อมูลที่ส่งมาจาก API (boolean, number, string)
|
// - 2026-05-29: ปรับปรุงการโหลด Active Prompt ให้ทนทานต่อ race conditions และรูปแบบประเภทข้อมูลที่ส่งมาจาก API (boolean, number, string)
|
||||||
// - 2026-05-30: Refactor เป็น 2-step flow (Step 1: OCR-only → Step 2: AI Extraction) ตาม spec 231
|
// - 2026-05-30: Refactor เป็น 2-step flow (Step 1: OCR-only → Step 2: AI Extraction) ตาม spec 231
|
||||||
// - 2026-06-02: ปรับปรุงลำดับปุ่มแท็บเริ่มต้นให้เริ่มที่ OCR Sandbox และเปลี่ยน dropdown labels ของตัวเลือกโมเดล Typhoon OCR ให้แสดงหน่วยความจำ VRAM แม่นยำ (T012, T013, ADR-033)
|
// - 2026-06-02: ปรับปรุงลำดับปุ่มแท็บเริ่มต้นให้เริ่มที่ OCR Sandbox และเปลี่ยน dropdown labels ของตัวเลือกโมเดล Typhoon OCR ให้แสดงหน่วยความจำ VRAM แม่นยำ (T012, T013, ADR-033)
|
||||||
|
// - 2026-06-04: เปลี่ยน OCR Engine dropdown จาก hardcoded เป็น dynamic โดยดึงจาก getOcrEngines() API และ map engineType → SandboxOcrEngineType
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect, useMemo } from 'react';
|
||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Textarea } from '@/components/ui/textarea';
|
import { Textarea } from '@/components/ui/textarea';
|
||||||
@@ -34,7 +36,7 @@ import { useTranslations } from '@/hooks/use-translations';
|
|||||||
import PromptVersionHistory from './PromptVersionHistory';
|
import PromptVersionHistory from './PromptVersionHistory';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { AiPrompt } from '@/types/ai-prompts';
|
import { AiPrompt } from '@/types/ai-prompts';
|
||||||
import { adminAiService } from '@/lib/services/admin-ai.service';
|
import { adminAiService, OcrEngineResponse } from '@/lib/services/admin-ai.service';
|
||||||
|
|
||||||
const DEFAULT_OCR_TEMPLATE = `คุณคือเอนจิ้นสกัดข้อมูลอัจฉริยะ (Document Intelligence Engine)
|
const DEFAULT_OCR_TEMPLATE = `คุณคือเอนจิ้นสกัดข้อมูลอัจฉริยะ (Document Intelligence Engine)
|
||||||
วิเคราะห์ข้อความ OCR ที่ได้รับจากเอกสารของโครงการ Laem Chabang Port Phase 3 และสกัดข้อมูลเมตาดาต้าให้ออกมาเป็น JSON object ที่ถูกต้องตามโครงสร้างที่กำหนด
|
วิเคราะห์ข้อความ OCR ที่ได้รับจากเอกสารของโครงการ Laem Chabang Port Phase 3 และสกัดข้อมูลเมตาดาต้าให้ออกมาเป็น JSON object ที่ถูกต้องตามโครงสร้างที่กำหนด
|
||||||
@@ -108,9 +110,31 @@ export default function OcrSandboxPromptManager() {
|
|||||||
const [activeTab, setActiveTab] = useState<'editor' | 'sandbox'>('sandbox');
|
const [activeTab, setActiveTab] = useState<'editor' | 'sandbox'>('sandbox');
|
||||||
// 2-step flow states
|
// 2-step flow states
|
||||||
const [sandboxStep, setSandboxStep] = useState<'ocr' | 'ai'>('ocr');
|
const [sandboxStep, setSandboxStep] = useState<'ocr' | 'ai'>('ocr');
|
||||||
const [selectedOcrEngine, setSelectedOcrEngine] = useState<
|
const [selectedOcrEngine, setSelectedOcrEngine] = useState<string>('auto');
|
||||||
'auto' | 'tesseract' | 'typhoon-ocr-3b' | 'typhoon-ocr1.5-3b'
|
const { data: ocrEnginesData } = useQuery<OcrEngineResponse[]>({
|
||||||
>('auto');
|
queryKey: ['ocr-engines'],
|
||||||
|
queryFn: () => adminAiService.getOcrEngines(),
|
||||||
|
staleTime: 60_000,
|
||||||
|
});
|
||||||
|
const ocrEngineOptions = useMemo(() => {
|
||||||
|
const base = [{ value: 'auto', label: 'Auto (Current Baseline)' }];
|
||||||
|
if (!ocrEnginesData) return base;
|
||||||
|
const mapped = ocrEnginesData.map((e: OcrEngineResponse) => {
|
||||||
|
const value =
|
||||||
|
e.engineType === 'tesseract'
|
||||||
|
? 'tesseract'
|
||||||
|
: e.engineType === 'typhoon_ocr'
|
||||||
|
? 'typhoon-ocr-3b'
|
||||||
|
: e.engineType;
|
||||||
|
const vramLabel =
|
||||||
|
e.vramRequirementMB > 0
|
||||||
|
? ` (${(e.vramRequirementMB / 1024).toFixed(1)} GB VRAM)`
|
||||||
|
: '';
|
||||||
|
const activeLabel = e.isCurrentActive ? ' ✓' : '';
|
||||||
|
return { value, label: `${e.engineName}${vramLabel}${activeLabel}` };
|
||||||
|
});
|
||||||
|
return [...base, ...mapped];
|
||||||
|
}, [ocrEnginesData]);
|
||||||
const [ocrResult, setOcrResult] = useState<{
|
const [ocrResult, setOcrResult] = useState<{
|
||||||
requestPublicId: string;
|
requestPublicId: string;
|
||||||
ocrText: string;
|
ocrText: string;
|
||||||
@@ -385,17 +409,14 @@ export default function OcrSandboxPromptManager() {
|
|||||||
<label className="text-xs font-medium">OCR Engine</label>
|
<label className="text-xs font-medium">OCR Engine</label>
|
||||||
<select
|
<select
|
||||||
value={selectedOcrEngine}
|
value={selectedOcrEngine}
|
||||||
onChange={(e) =>
|
onChange={(e) => setSelectedOcrEngine(e.target.value)}
|
||||||
setSelectedOcrEngine(
|
|
||||||
e.target.value as 'auto' | 'tesseract' | 'typhoon-ocr-3b' | 'typhoon-ocr1.5-3b'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
className="w-full rounded-md border border-input bg-background px-3 py-2 text-xs"
|
className="w-full rounded-md border border-input bg-background px-3 py-2 text-xs"
|
||||||
>
|
>
|
||||||
<option value="auto">Auto (Current Baseline)</option>
|
{ocrEngineOptions.map((opt) => (
|
||||||
<option value="tesseract">Tesseract OCR</option>
|
<option key={opt.value} value={opt.value}>
|
||||||
<option value="typhoon-ocr1.5-3b">typhoon-ocr1.5-3b 3.2GB</option>
|
{opt.label}
|
||||||
<option value="typhoon-ocr-3b">typhoon-ocr-3b 7.5GB</option>
|
</option>
|
||||||
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ export const adminAiService = {
|
|||||||
|
|
||||||
submitSandboxOcr: async (
|
submitSandboxOcr: async (
|
||||||
file: File,
|
file: File,
|
||||||
engineType: 'auto' | 'tesseract' | 'typhoon-ocr-3b' | 'typhoon-ocr1.5-3b' = 'auto'
|
engineType: string = 'auto'
|
||||||
): Promise<{ requestPublicId: string; jobId: string; status: string }> => {
|
): Promise<{ requestPublicId: string; jobId: string; status: string }> => {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('file', file);
|
formData.append('file', file);
|
||||||
|
|||||||
Reference in New Issue
Block a user