diff --git a/apps/admin/src/components/ProductBomPromptModal.tsx b/apps/admin/src/components/ProductBomPromptModal.tsx new file mode 100644 index 0000000..11259a5 --- /dev/null +++ b/apps/admin/src/components/ProductBomPromptModal.tsx @@ -0,0 +1,332 @@ +import { useState, useMemo } from 'react'; +import { + X, + Copy, + Check, + Bot, + Sparkles, + FileCode, + Package, + Layers, + Code2 +} from 'lucide-react'; + +interface ProductBomPromptModalProps { + isOpen: boolean; + onClose: () => void; + productId: number | string; + productName: string; + variants: any[]; + rawMaterials: any[]; +} + +export default function ProductBomPromptModal({ + isOpen, + onClose, + productId, + productName, + variants, + rawMaterials, +}: ProductBomPromptModalProps) { + const [copied, setCopied] = useState(false); + const [activeTab, setActiveTab] = useState<'prompt' | 'context' | 'schema'>('prompt'); + + // Generate full prompt text for LLM + const generatedPrompt = useMemo(() => { + const variantLines = variants.map((v) => { + const opts = [v.option1, v.option2, v.option3].filter(Boolean).join(' / ') || 'Base Variant'; + return ` - Variant ID: ${v.id} | SKU: ${v.sku || '-'} | ตัวเลือก: "${opts}" | ราคาขาย: ฿${Number(v.price || 0).toLocaleString()}`; + }).join('\n'); + + const rawMaterialLines = rawMaterials.map((rm) => { + return ` - [ID: ${rm.id}] "${rm.name}" | หน่วย: ${rm.unit} | ต้นทุน: ฿${Number(rm.pricePerUnit || 0).toLocaleString(undefined, { minimumFractionDigits: 2 })}`; + }).join('\n'); + + return `คุณคือ Senior Manufacturing & Bill of Materials (BOM) Specialist ของระบบ E-Commerce (DBK Platform) + +[บริบทข้อมูลสินค้า]: +- รหัสสินค้า (Product ID): ${productId} +- ชื่อสินค้า: "${productName}" + +[รายการตัวเลือกสินค้า (Variants ที่ต้องกำหนดสูตร BOM)]: +${variantLines} + +[คลังรายการวัตถุดิบในระบบ (Raw Materials ที่สามารถนำมาผูกสูตรได้)]: +${rawMaterialLines} + +[ภารกิจของคุณ]: +กรุณาจัดทำสูตรการผลิต (BOM Items) ให้กับแต่ละ Variant ของสินค้า รหัส #${productId} ตามคำสั่ง/สัดส่วนที่ระบุ +และส่งคืนผลลัพธ์เป็น **Valid JSON Array** ล้วนๆ ตามข้อกำหนดดังต่อไปนี้เท่านั้น: + +[ข้อกำหนดผลลัพธ์ JSON Format ที่ต้องส่งกลับ]: +\`\`\`json +[ + { + "variantId": <ตัวเลข ID ของ Variant>, + "sku": "<รหัส SKU>", + "bomItems": [ + { + "rawMaterialId": <ตัวเลข ID ของวัตถุดิบจากคลังด้านบน>, + "name": "<ชื่อวัตถุดิบ>", + "quantity": <จำนวนปริมาณตัวเลข (ห้ามเป็น string)> + } + ] + } +] +\`\`\` +*(คำสั่ง/สูตรเฉพาะ: ระบุสัดส่วนการผสม วัตถุดิบบรรจุภัณฑ์ และปริมาณที่ต้องการต่อ 1 ชิ้น)*`; + }, [productId, productName, variants, rawMaterials]); + + // Context JSON + const contextJson = useMemo(() => { + return JSON.stringify( + { + product: { + id: Number(productId), + name: productName, + variantsCount: variants.length, + variants: variants.map((v) => ({ + id: v.id, + sku: v.sku, + option1: v.option1, + option2: v.option2, + option3: v.option3, + price: v.price, + currentBomCount: v.bomItems?.length || 0, + })), + }, + rawMaterialsCount: rawMaterials.length, + rawMaterials: rawMaterials.map((rm) => ({ + id: rm.id, + name: rm.name, + unit: rm.unit, + pricePerUnit: rm.pricePerUnit, + })), + }, + null, + 2 + ); + }, [productId, productName, variants, rawMaterials]); + + // Target schema sample + const schemaSample = useMemo(() => { + const firstVariant = variants[0]; + const sampleItem = rawMaterials[0]; + return JSON.stringify( + [ + { + variantId: firstVariant ? firstVariant.id : 1, + sku: firstVariant?.sku || 'SAMPLE-SKU', + bomItems: [ + { + rawMaterialId: sampleItem ? sampleItem.id : 1, + name: sampleItem?.name || 'ตัวอย่างวัตถุดิบ', + quantity: 1, + }, + ], + }, + ], + null, + 2 + ); + }, [variants, rawMaterials]); + + if (!isOpen) return null; + + const handleCopy = async (textToCopy: string) => { + try { + await navigator.clipboard.writeText(textToCopy); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } catch (e) { + console.error(e); + } + }; + + return ( +
+ {/* Backdrop */} +
+ + {/* Modal Container */} +
+ {/* Header */} +
+
+
+ +
+
+
+

LLM Prompt Generator for BOM

+ + Product #{productId} + +
+

+ สร้างชุดคำสั่ง Prompt พร้อมรหัสสินค้า, Variants และรายการวัตถุดิบทั้งหมดสำหรับส่งให้ LLM +

+
+
+ +
+ + {/* Quick Stats Bar */} +
+
+ + สินค้า: {productName} +
+
+ + Variants: {variants.length} ตัวเลือก +
+
+ + วัตถุดิบในคลัง: {rawMaterials.length} รายการ +
+
+ + {/* Navigation Tabs */} +
+ + + +
+ + {/* Content Body */} +
+ {activeTab === 'prompt' && ( +
+
+ + คัดลอกข้อความด้านล่างนี้ไปวางใน ChatGPT, Claude หรือ Gemini: + + +
+ +