Spaces:
Sleeping
Sleeping
File size: 5,214 Bytes
eeb307d 6a25ae8 eeb307d 6a25ae8 eeb307d 73e67e0 6a25ae8 f86ee93 6a25ae8 eeb307d 6a25ae8 eeb307d 6a25ae8 eeb307d 6a25ae8 eeb307d 6a25ae8 eeb307d 6323066 66b7865 73e67e0 04cb628 6a25ae8 ae54989 f86ee93 524fa3e 6a25ae8 f86ee93 6a25ae8 505c8e4 f86ee93 eeb307d f86ee93 6a25ae8 eeb307d f86ee93 6a25ae8 eeb307d f86ee93 04cb628 6a25ae8 f86ee93 ed54f93 6a25ae8 73e67e0 04cb628 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | /** engine/validator.js V94.1 - Syntax Fixed */
const fs = require('fs');
const path = require('path');
let productsDB = {};
try {
productsDB = JSON.parse(fs.readFileSync(path.join(__dirname, '../db/products.json'), 'utf8'));
} catch (e) {
console.error("Failed loading products.json in validator");
}
const VALID_PRODUCTS = new Set(Object.keys(productsDB));
const PRODUCT_KEYWORDS_MAP = {
'ืคืืกืืจ': 'poster', 'poster': 'poster',
'ืคืืืืจ': 'flyer', 'flyer': 'flyer',
'ืืืืจ': 'booklet', 'ืกืคืจ': 'booklet', 'ืงืืืื': 'booklet', 'booklet': 'booklet',
'ืืืืง': 'sticker', 'sticker': 'sticker',
'ืกืงืืืืงืก': 'scodix', 'scodix': 'scodix', 'ืคืืื': 'scodix',
'ืืืืงืืืื ื': 'alucobond', 'alucobond': 'alucobond', 'ืฉืื': 'alucobond',
'ืืืื': 'roll_stickers', 'roll_stickers': 'roll_stickers'
};
function validateLLMResult(llmResult, userText, session) {
let result = { ...llmResult };
const text = userText.toLowerCase();
if (!result.mapped_params) result.mapped_params = {};
// Product Detection Override
const detectedProductsSet = new Set();
Object.keys(PRODUCT_KEYWORDS_MAP).forEach(keyword => {
if (text.includes(keyword)) {
detectedProductsSet.add(PRODUCT_KEYWORDS_MAP[keyword]);
}
});
const detectedProducts = Array.from(detectedProductsSet);
const hasNumber = /\d/.test(text);
if (detectedProducts.length > 0 && hasNumber) {
if (result.intent !== 'quote' || !result.product) {
console.log(`๐ก๏ธ [VALIDATOR] Force-Switching to QUOTE. Found: ${detectedProducts.join(', ')}`); // โ
ืชืืงื!
result.intent = 'quote';
if (!result.product) {
result.product = detectedProducts[0];
}
}
result.allDetectedProducts = detectedProducts;
}
// ืฉืืจ ืืงืื ื ืฉืืจ ืืืชื ืืืจ...
const updateKeywords = ["ืชืฉื ื", "ืชืืืืฃ", "ืขืืื", "ืืืืช", "ื-", "ืืืขืื", "ืืืื", "ืืืงืื", "update", "qty", "change", "replace", "fix"];
if (updateKeywords.some(k => text.includes(k))) {
result.intent = 'update';
}
const sizeMatch = text.match(/(\d+\.\d+|\d+)\s*(?:x|X|\*|ืขื)\s*(\d+\.\d+|\d+)/);
if (sizeMatch) {
result.mapped_params.size = `${sizeMatch[1]}x${sizeMatch[2]}`;
console.log(`๐ก๏ธ [VALIDATOR] Detected Size with Decimals: ${result.mapped_params.size}`);
if (result.intent === 'chat') result.intent = 'update';
}
// --- PHASE 1.3 UAT Hotfix: Alucobond vs Office Intercept ---
if (text.includes('ืืืืงืืืื ื') || text.includes('alucobond')) {
if (result.product === 'office') {
console.log(`\x1b[33m๐ก๏ธ [X-RAY VALIDATOR] Intercepted LLM hallucination: Swapped 'office' for 'alucobond'\x1b[0m`);
result.product = 'alucobond';
result.intent = 'quote';
}
}
if (text.includes('ืืจืืื')) {
if (text.includes('300')) result.mapped_params.paper_type = 'chromo_300';
else result.mapped_params.paper_type = 'chromo_130';
if (result.intent === 'chat') result.intent = 'update';
}
if (text.includes('ืื')) {
result.mapped_params.paper_type = 'matte_350';
if (result.intent === 'chat') result.intent = 'update';
}
if (text.includes("ืืื") || text.includes("ืืื")) {
if (result.intent === 'chat') result.intent = 'update';
}
if (/^\d+$/.test(text.trim()) && result.intent === 'chat') {
result.intent = 'update';
}
// --- PHASE 1.3 Anti-Hallucination: Confidence Gate ---
if (result.confidence !== undefined && result.confidence < 0.85) {
console.log(`\x1b[31m๐ก๏ธ [X-RAY VALIDATOR] Confidence Gate Blocked: ${result.confidence} is below 0.85 threshold.\x1b[0m`);
result.intent = 'chat';
result.product = null;
result.answer_text = "ืื ื ืื ืืืืจื ืืืื ืืืืื ืชื, ืืคืฉืจ ืื ืกื ืฉืื?";
}
// --- PHASE 1.3 Anti-Hallucination: Product Whitelist ---
if (result.product && !VALID_PRODUCTS.has(result.product)) {
console.log(`\x1b[31m๐ก๏ธ [X-RAY VALIDATOR] Product Whitelist Blocked: '${result.product}' does not exist in DB.\x1b[0m`);
result.intent = 'chat';
result.product = null;
result.answer_text = "ืืฆืขืจื ืืื ืื ื ืืช ืืืืฆืจ ืืื ืืจืืข ืืืขืจืืช. ืืืืืจ ืืชืคืจืื?";
}
// --- PHASE 1.3 Anti-Hallucination: Quantity Clamp ---
if (result.mapped_params && result.mapped_params.qty !== undefined) {
const rawQty = parseInt(result.mapped_params.qty);
if (!isNaN(rawQty)) {
// ืืืืืช ืืื ืืืื ืืืงืกืืืื ืืืจืกืืืืช (1 ืขื 100,000)
const clampedQty = Math.max(1, Math.min(rawQty, 100000));
if (rawQty !== clampedQty) {
console.log(`\x1b[33m๐ก๏ธ [X-RAY VALIDATOR] Quantity Clamped from ${rawQty} to ${clampedQty}.\x1b[0m`);
}
result.mapped_params.qty = clampedQty;
}
}
return result;
}
module.exports = { validateLLMResult }; |