Update endpoints/antibot.js
Browse files- endpoints/antibot.js +42 -142
endpoints/antibot.js
CHANGED
|
@@ -4,17 +4,19 @@ const { extractTextFromImage, uploadImageToHosting } = require('./imageProcessor
|
|
| 4 |
|
| 5 |
async function extractTextFromBuffer(imageBuffer) {
|
| 6 |
try {
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
console.log('β
DEBUG extractTextFromBuffer: Hasil ekstraksi:', result);
|
| 14 |
-
|
| 15 |
-
fs.unlinkSync(tempPath);
|
| 16 |
-
console.log('π§Ή DEBUG: File temporary dihapus');
|
| 17 |
-
|
| 18 |
return result;
|
| 19 |
} catch (error) {
|
| 20 |
console.error('β DEBUG extractTextFromBuffer Error:', error.message);
|
|
@@ -35,42 +37,22 @@ function normalizeText(text) {
|
|
| 35 |
|
| 36 |
function isValueMatch(value, targetSoal) {
|
| 37 |
console.log(`π DEBUG isValueMatch: Value="${value}", Soal="${targetSoal}"`);
|
| 38 |
-
|
| 39 |
const numberMap = {
|
| 40 |
-
'0': 'zero', '1': 'one', '2': 'two', '3': 'three', '4': 'four',
|
| 41 |
-
'
|
| 42 |
-
'zero': '0', 'one': '1', 'two': '2', 'three': '3', 'four': '4',
|
| 43 |
-
'
|
| 44 |
-
'I': '1',
|
| 45 |
-
'
|
| 46 |
-
'
|
| 47 |
-
'
|
| 48 |
-
'
|
| 49 |
-
'f0ur': '4', 'f0r': '4', 'fuor': '4',
|
| 50 |
-
'f1ve': '5', 'fiv': '5', 'f1v': '5',
|
| 51 |
-
'e1ght': '8', 'elght': '8', 'eight': '8',
|
| 52 |
-
'n1ne': '9', 'n1n': '9', 'nne': '9',
|
| 53 |
-
'se7en': '7', 'sven': '7', 'seven': '7',
|
| 54 |
-
'thre': '3', 'tree': '3', 'thr33': '3',
|
| 55 |
-
'tw0': '2', 'to': '2', 'tw': '2',
|
| 56 |
-
'0ne': '1', 'on': '1', 'oen': '1'
|
| 57 |
};
|
| 58 |
|
| 59 |
const leetMap = {
|
| 60 |
-
'O': '0',
|
| 61 |
-
'
|
| 62 |
-
'
|
| 63 |
-
'E': '3', 'e': '3',
|
| 64 |
-
'A': '4', 'a': '4',
|
| 65 |
-
'S': '5', 's': '5',
|
| 66 |
-
'G': '6', 'g': '6',
|
| 67 |
-
'T': '7', 't': '7',
|
| 68 |
-
'B': '8', 'b': '8',
|
| 69 |
-
'Q': '9', 'q': '9',
|
| 70 |
-
'U': '4', 'u': '4',
|
| 71 |
-
'R': '2', 'r': '2',
|
| 72 |
-
'N': '9', 'n': '9',
|
| 73 |
-
'V': '7', 'v': '7'
|
| 74 |
};
|
| 75 |
|
| 76 |
const normalizedValue = normalizeText(value);
|
|
@@ -81,43 +63,22 @@ function isValueMatch(value, targetSoal) {
|
|
| 81 |
return true;
|
| 82 |
}
|
| 83 |
|
| 84 |
-
const convertLeet = (text) =>
|
| 85 |
-
return text.split('').map(char => leetMap[char] || char).join('');
|
| 86 |
-
};
|
| 87 |
-
|
| 88 |
const leetValue = convertLeet(value);
|
| 89 |
const leetSoal = convertLeet(targetSoal);
|
| 90 |
-
|
| 91 |
console.log(`π’ DEBUG Leet: Value="${leetValue}", Soal="${leetSoal}"`);
|
| 92 |
|
| 93 |
-
if (leetValue === normalizedSoal) {
|
| 94 |
-
console.log('β
DEBUG: Match leet
|
| 95 |
-
return true;
|
| 96 |
-
}
|
| 97 |
-
if (normalizedValue === leetSoal) {
|
| 98 |
-
console.log('β
DEBUG: Match normalized value -> leet soal');
|
| 99 |
-
return true;
|
| 100 |
-
}
|
| 101 |
-
if (leetValue === leetSoal) {
|
| 102 |
-
console.log('β
DEBUG: Match leet value -> leet soal');
|
| 103 |
return true;
|
| 104 |
}
|
| 105 |
|
| 106 |
const mappedValue = numberMap[normalizedValue] || numberMap[value] || normalizedValue;
|
| 107 |
const mappedSoal = numberMap[normalizedSoal] || numberMap[targetSoal] || normalizedSoal;
|
| 108 |
-
|
| 109 |
console.log(`π DEBUG Number Map: Value="${mappedValue}", Soal="${mappedSoal}"`);
|
| 110 |
|
| 111 |
-
if (mappedValue === normalizedSoal) {
|
| 112 |
-
console.log('β
DEBUG: Match mapped
|
| 113 |
-
return true;
|
| 114 |
-
}
|
| 115 |
-
if (normalizedValue === mappedSoal) {
|
| 116 |
-
console.log('β
DEBUG: Match normalized value -> mapped soal');
|
| 117 |
-
return true;
|
| 118 |
-
}
|
| 119 |
-
if (mappedValue === mappedSoal) {
|
| 120 |
-
console.log('β
DEBUG: Match mapped value -> mapped soal');
|
| 121 |
return true;
|
| 122 |
}
|
| 123 |
|
|
@@ -147,17 +108,13 @@ function isValueMatch(value, targetSoal) {
|
|
| 147 |
function calculateSimilarity(str1, str2) {
|
| 148 |
if (str1 === str2) return 1;
|
| 149 |
if (str1.length === 0 || str2.length === 0) return 0;
|
| 150 |
-
|
| 151 |
const longer = str1.length > str2.length ? str1 : str2;
|
| 152 |
const shorter = str1.length > str2.length ? str2 : str1;
|
| 153 |
-
|
| 154 |
if (longer.includes(shorter)) return shorter.length / longer.length;
|
| 155 |
-
|
| 156 |
let matches = 0;
|
| 157 |
for (let i = 0; i < shorter.length; i++) {
|
| 158 |
if (shorter[i] === longer[i]) matches++;
|
| 159 |
}
|
| 160 |
-
|
| 161 |
return matches / longer.length;
|
| 162 |
}
|
| 163 |
|
|
@@ -176,30 +133,24 @@ function evaluateSimpleMath(expression) {
|
|
| 176 |
|
| 177 |
function parseSoalText(text) {
|
| 178 |
console.log(`π DEBUG parseSoalText: Input text: "${text}"`);
|
| 179 |
-
|
| 180 |
const ignoreWords = [
|
| 181 |
-
'hi',
|
| 182 |
-
'
|
| 183 |
-
'
|
| 184 |
-
'berikan', 'jangan', 'tambahkan', 'kata', 'apapun', 'seperti',
|
| 185 |
-
'atau', 'penjelasan', 'lain', 'saja'
|
| 186 |
];
|
| 187 |
-
|
| 188 |
-
const delimiters = /[.,:;\\/\s]+/;
|
| 189 |
let parts = text.split(delimiters)
|
| 190 |
.filter(part => part.trim() !== '')
|
| 191 |
.filter(part => !ignoreWords.includes(part.toLowerCase()));
|
| 192 |
-
|
| 193 |
if (parts.length === 0) {
|
| 194 |
parts = text.split(/\s+/)
|
| 195 |
.filter(part => part.trim() !== '')
|
| 196 |
.filter(part => !ignoreWords.includes(part.toLowerCase()));
|
| 197 |
}
|
| 198 |
-
|
| 199 |
parts = parts.filter(part => part.length <= 3 || !isNaN(part));
|
| 200 |
-
|
| 201 |
parts = parts.slice(0, 3);
|
| 202 |
-
|
| 203 |
console.log(`π DEBUG parseSoalText: Filtered parts (max 3):`, parts);
|
| 204 |
return parts;
|
| 205 |
}
|
|
@@ -207,30 +158,24 @@ function parseSoalText(text) {
|
|
| 207 |
async function antibot(data) {
|
| 208 |
console.log('π DEBUG antibot: Memulai proses antibot');
|
| 209 |
console.log('π DEBUG: Data received - main:', data.main ? 'β
' : 'β', 'bots:', data.bots?.length || 0);
|
| 210 |
-
|
| 211 |
try {
|
| 212 |
const { main, bots } = data;
|
| 213 |
-
|
| 214 |
console.log('πΌοΈ DEBUG: Processing main image...');
|
| 215 |
const mainBuffer = Buffer.from(main, 'base64');
|
| 216 |
const mainText = await extractTextFromBuffer(mainBuffer);
|
| 217 |
-
|
| 218 |
console.log('π DEBUG Main Text Result:', mainText);
|
| 219 |
-
|
| 220 |
if (!mainText.status) {
|
| 221 |
throw new Error('Gagal mengekstrak teks dari gambar utama: ' + mainText.response);
|
| 222 |
}
|
| 223 |
|
| 224 |
const soalArray = parseSoalText(mainText.response);
|
| 225 |
console.log(`π DEBUG: Soal array:`, soalArray);
|
| 226 |
-
|
| 227 |
if (soalArray.length === 0) {
|
| 228 |
throw new Error('Tidak ada soal yang terdeteksi');
|
| 229 |
}
|
| 230 |
|
| 231 |
const botResults = [];
|
| 232 |
console.log(`π€ DEBUG: Processing ${bots.length} bots...`);
|
| 233 |
-
|
| 234 |
for (let i = 0; i < bots.length; i++) {
|
| 235 |
const bot = bots[i];
|
| 236 |
console.log(`π€ DEBUG: Processing bot ${i+1}/${bots.length} - ID: ${bot.id}`);
|
|
@@ -238,29 +183,11 @@ async function antibot(data) {
|
|
| 238 |
const botBuffer = Buffer.from(bot.img, 'base64');
|
| 239 |
const botText = await extractTextFromBuffer(botBuffer);
|
| 240 |
const mappedValue = mapAnswer(soalArray, botText.response, i);
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
id: bot.id,
|
| 244 |
-
text: botText.response,
|
| 245 |
-
value: mappedValue,
|
| 246 |
-
normalized: normalizeText(botText.response)
|
| 247 |
-
});
|
| 248 |
-
|
| 249 |
-
console.log(`β
DEBUG Bot ${bot.id}:`, {
|
| 250 |
-
text: botText.response,
|
| 251 |
-
value: mappedValue,
|
| 252 |
-
normalized: normalizeText(botText.response)
|
| 253 |
-
});
|
| 254 |
-
|
| 255 |
} catch (error) {
|
| 256 |
console.error(`β DEBUG Bot ${bot.id} Error:`, error.message);
|
| 257 |
-
botResults.push({
|
| 258 |
-
id: bot.id,
|
| 259 |
-
text: '',
|
| 260 |
-
value: '',
|
| 261 |
-
normalized: '',
|
| 262 |
-
error: error.message
|
| 263 |
-
});
|
| 264 |
}
|
| 265 |
}
|
| 266 |
|
|
@@ -269,13 +196,10 @@ async function antibot(data) {
|
|
| 269 |
const usedIds = new Set();
|
| 270 |
let successfulMatches = 0;
|
| 271 |
|
| 272 |
-
// Step 1: Match setiap bot dengan soal yang tersedia
|
| 273 |
const availableSoal = [...soalArray];
|
| 274 |
-
|
| 275 |
for (const bot of botResults) {
|
| 276 |
let matchedSoal = null;
|
| 277 |
let matchIndex = -1;
|
| 278 |
-
|
| 279 |
if (bot.value && bot.value.trim() !== '') {
|
| 280 |
for (let i = 0; i < availableSoal.length; i++) {
|
| 281 |
if (isValueMatch(bot.value, availableSoal[i])) {
|
|
@@ -287,27 +211,17 @@ async function antibot(data) {
|
|
| 287 |
}
|
| 288 |
}
|
| 289 |
}
|
| 290 |
-
|
| 291 |
if (matchedSoal) {
|
| 292 |
-
result.push({
|
| 293 |
-
id: bot.id,
|
| 294 |
-
soal: matchedSoal,
|
| 295 |
-
matchType: 'exact'
|
| 296 |
-
});
|
| 297 |
availableSoal.splice(matchIndex, 1);
|
| 298 |
usedIds.add(bot.id);
|
| 299 |
} else {
|
| 300 |
-
result.push({
|
| 301 |
-
id: null,
|
| 302 |
-
soal: '',
|
| 303 |
-
matchType: 'none'
|
| 304 |
-
});
|
| 305 |
}
|
| 306 |
}
|
| 307 |
|
| 308 |
console.log(`π DEBUG: Successful matches: ${successfulMatches}`);
|
| 309 |
|
| 310 |
-
// Step 2: Jika minimal 2 match, isi bot yang belum match dengan soal tersisa
|
| 311 |
if (successfulMatches >= 2) {
|
| 312 |
console.log('β
DEBUG: Minimal 2 match terpenuhi, mengisi bot yang belum match');
|
| 313 |
for (let i = 0; i < result.length; i++) {
|
|
@@ -321,7 +235,6 @@ async function antibot(data) {
|
|
| 321 |
}
|
| 322 |
}
|
| 323 |
|
| 324 |
-
// Step 3: Handle remaining cases
|
| 325 |
for (let i = 0; i < result.length; i++) {
|
| 326 |
if (!result[i].id) {
|
| 327 |
if (successfulMatches >= 2) {
|
|
@@ -346,28 +259,15 @@ async function antibot(data) {
|
|
| 346 |
result: result.map(r => ({ id: r.id })),
|
| 347 |
debug: {
|
| 348 |
parsedSoal: soalArray,
|
| 349 |
-
matches: result.map(r => ({
|
| 350 |
-
id: r.id,
|
| 351 |
-
matchType: r.matchType,
|
| 352 |
-
soal: r.soal
|
| 353 |
-
})),
|
| 354 |
totalResults: result.length,
|
| 355 |
successfulMatches: successfulMatches
|
| 356 |
}
|
| 357 |
}
|
| 358 |
};
|
| 359 |
-
|
| 360 |
} catch (error) {
|
| 361 |
console.error('π₯ DEBUG antibot Error:', error.message);
|
| 362 |
-
return {
|
| 363 |
-
success: false,
|
| 364 |
-
error: error.message,
|
| 365 |
-
data: {
|
| 366 |
-
soal: [],
|
| 367 |
-
botResults: [],
|
| 368 |
-
result: []
|
| 369 |
-
}
|
| 370 |
-
};
|
| 371 |
}
|
| 372 |
}
|
| 373 |
|
|
|
|
| 4 |
|
| 5 |
async function extractTextFromBuffer(imageBuffer) {
|
| 6 |
try {
|
| 7 |
+
if (!imageBuffer) {
|
| 8 |
+
throw new Error('No image buffer provided');
|
| 9 |
+
}
|
| 10 |
+
if (!Buffer.isBuffer(imageBuffer)) {
|
| 11 |
+
throw new Error('extractTextFromBuffer expects a Buffer');
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
console.log('πΌοΈ DEBUG extractTextFromBuffer: Received buffer, size:', imageBuffer.length, 'bytes');
|
| 15 |
+
|
| 16 |
+
// Kirim buffer langsung ke extractTextFromImage (tidak perlu membuat file temporary)
|
| 17 |
+
const result = await extractTextFromImage(imageBuffer);
|
| 18 |
+
|
| 19 |
console.log('β
DEBUG extractTextFromBuffer: Hasil ekstraksi:', result);
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
return result;
|
| 21 |
} catch (error) {
|
| 22 |
console.error('β DEBUG extractTextFromBuffer Error:', error.message);
|
|
|
|
| 37 |
|
| 38 |
function isValueMatch(value, targetSoal) {
|
| 39 |
console.log(`π DEBUG isValueMatch: Value="${value}", Soal="${targetSoal}"`);
|
|
|
|
| 40 |
const numberMap = {
|
| 41 |
+
'0': 'zero', '1': 'one', '2': 'two', '3': 'three', '4': 'four', '5': 'five',
|
| 42 |
+
'6': 'six', '7': 'seven', '8': 'eight', '9': 'nine', '10': 'ten',
|
| 43 |
+
'zero': '0', 'one': '1', 'two': '2', 'three': '3', 'four': '4', 'five': '5',
|
| 44 |
+
'six': '6', 'seven': '7', 'eight': '8', 'nine': '9', 'ten': '10',
|
| 45 |
+
'I': '1','II': '2','III': '3','IV': '4','V': '5','VI': '6','VII': '7','VIII': '8','IX': '9','X': '10',
|
| 46 |
+
'i': '1','ii': '2','iii': '3','iv': '4','v': '5','vi': '6','vii': '7','viii': '8','ix': '9','x': '10',
|
| 47 |
+
'slx': '6','s1x': '6','six': '6','f0ur': '4','f0r': '4','fuor': '4','f1ve': '5','fiv': '5','f1v': '5',
|
| 48 |
+
'e1ght': '8','elght': '8','eight': '8','n1ne': '9','n1n': '9','nne': '9','se7en': '7','sven': '7','seven': '7',
|
| 49 |
+
'thre': '3','tree': '3','thr33': '3','tw0': '2','to': '2','tw': '2','0ne': '1','on': '1','oen': '1'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
};
|
| 51 |
|
| 52 |
const leetMap = {
|
| 53 |
+
'O': '0','o': '0','I': '1','i': '1','l': '1','Z': '2','z': '2','E': '3','e': '3',
|
| 54 |
+
'A': '4','a': '4','S': '5','s': '5','G': '6','g': '6','T': '7','t': '7','B': '8','b': '8',
|
| 55 |
+
'Q': '9','q': '9','U': '4','u': '4','R': '2','r': '2','N': '9','n': '9','V': '7','v': '7'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
};
|
| 57 |
|
| 58 |
const normalizedValue = normalizeText(value);
|
|
|
|
| 63 |
return true;
|
| 64 |
}
|
| 65 |
|
| 66 |
+
const convertLeet = (text) => text.split('').map(char => leetMap[char] || char).join('');
|
|
|
|
|
|
|
|
|
|
| 67 |
const leetValue = convertLeet(value);
|
| 68 |
const leetSoal = convertLeet(targetSoal);
|
|
|
|
| 69 |
console.log(`π’ DEBUG Leet: Value="${leetValue}", Soal="${leetSoal}"`);
|
| 70 |
|
| 71 |
+
if (leetValue === normalizedSoal || normalizedValue === leetSoal || leetValue === leetSoal) {
|
| 72 |
+
console.log('β
DEBUG: Match leet/normalized combination');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
return true;
|
| 74 |
}
|
| 75 |
|
| 76 |
const mappedValue = numberMap[normalizedValue] || numberMap[value] || normalizedValue;
|
| 77 |
const mappedSoal = numberMap[normalizedSoal] || numberMap[targetSoal] || normalizedSoal;
|
|
|
|
| 78 |
console.log(`π DEBUG Number Map: Value="${mappedValue}", Soal="${mappedSoal}"`);
|
| 79 |
|
| 80 |
+
if (mappedValue === normalizedSoal || normalizedValue === mappedSoal || mappedValue === mappedSoal) {
|
| 81 |
+
console.log('β
DEBUG: Match mapped combinations');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 82 |
return true;
|
| 83 |
}
|
| 84 |
|
|
|
|
| 108 |
function calculateSimilarity(str1, str2) {
|
| 109 |
if (str1 === str2) return 1;
|
| 110 |
if (str1.length === 0 || str2.length === 0) return 0;
|
|
|
|
| 111 |
const longer = str1.length > str2.length ? str1 : str2;
|
| 112 |
const shorter = str1.length > str2.length ? str2 : str1;
|
|
|
|
| 113 |
if (longer.includes(shorter)) return shorter.length / longer.length;
|
|
|
|
| 114 |
let matches = 0;
|
| 115 |
for (let i = 0; i < shorter.length; i++) {
|
| 116 |
if (shorter[i] === longer[i]) matches++;
|
| 117 |
}
|
|
|
|
| 118 |
return matches / longer.length;
|
| 119 |
}
|
| 120 |
|
|
|
|
| 133 |
|
| 134 |
function parseSoalText(text) {
|
| 135 |
console.log(`π DEBUG parseSoalText: Input text: "${text}"`);
|
|
|
|
| 136 |
const ignoreWords = [
|
| 137 |
+
'hi','how','are','you','hello','hey','tentu','berikut','adalah','teks','dari','gambar',
|
| 138 |
+
'dipisahkan','sesuai','permintaan','anda','hanya','berikan','jangan','tambahkan',
|
| 139 |
+
'kata','apapun','seperti','atau','penjelasan','lain','saja'
|
|
|
|
|
|
|
| 140 |
];
|
| 141 |
+
const delimiters = /[.,:;\\/\\s]+/;
|
|
|
|
| 142 |
let parts = text.split(delimiters)
|
| 143 |
.filter(part => part.trim() !== '')
|
| 144 |
.filter(part => !ignoreWords.includes(part.toLowerCase()));
|
| 145 |
+
|
| 146 |
if (parts.length === 0) {
|
| 147 |
parts = text.split(/\s+/)
|
| 148 |
.filter(part => part.trim() !== '')
|
| 149 |
.filter(part => !ignoreWords.includes(part.toLowerCase()));
|
| 150 |
}
|
| 151 |
+
|
| 152 |
parts = parts.filter(part => part.length <= 3 || !isNaN(part));
|
|
|
|
| 153 |
parts = parts.slice(0, 3);
|
|
|
|
| 154 |
console.log(`π DEBUG parseSoalText: Filtered parts (max 3):`, parts);
|
| 155 |
return parts;
|
| 156 |
}
|
|
|
|
| 158 |
async function antibot(data) {
|
| 159 |
console.log('π DEBUG antibot: Memulai proses antibot');
|
| 160 |
console.log('π DEBUG: Data received - main:', data.main ? 'β
' : 'β', 'bots:', data.bots?.length || 0);
|
|
|
|
| 161 |
try {
|
| 162 |
const { main, bots } = data;
|
|
|
|
| 163 |
console.log('πΌοΈ DEBUG: Processing main image...');
|
| 164 |
const mainBuffer = Buffer.from(main, 'base64');
|
| 165 |
const mainText = await extractTextFromBuffer(mainBuffer);
|
|
|
|
| 166 |
console.log('π DEBUG Main Text Result:', mainText);
|
|
|
|
| 167 |
if (!mainText.status) {
|
| 168 |
throw new Error('Gagal mengekstrak teks dari gambar utama: ' + mainText.response);
|
| 169 |
}
|
| 170 |
|
| 171 |
const soalArray = parseSoalText(mainText.response);
|
| 172 |
console.log(`π DEBUG: Soal array:`, soalArray);
|
|
|
|
| 173 |
if (soalArray.length === 0) {
|
| 174 |
throw new Error('Tidak ada soal yang terdeteksi');
|
| 175 |
}
|
| 176 |
|
| 177 |
const botResults = [];
|
| 178 |
console.log(`π€ DEBUG: Processing ${bots.length} bots...`);
|
|
|
|
| 179 |
for (let i = 0; i < bots.length; i++) {
|
| 180 |
const bot = bots[i];
|
| 181 |
console.log(`π€ DEBUG: Processing bot ${i+1}/${bots.length} - ID: ${bot.id}`);
|
|
|
|
| 183 |
const botBuffer = Buffer.from(bot.img, 'base64');
|
| 184 |
const botText = await extractTextFromBuffer(botBuffer);
|
| 185 |
const mappedValue = mapAnswer(soalArray, botText.response, i);
|
| 186 |
+
botResults.push({ id: bot.id, text: botText.response, value: mappedValue, normalized: normalizeText(botText.response) });
|
| 187 |
+
console.log(`β
DEBUG Bot ${bot.id}:`, { text: botText.response, value: mappedValue, normalized: normalizeText(botText.response) });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 188 |
} catch (error) {
|
| 189 |
console.error(`β DEBUG Bot ${bot.id} Error:`, error.message);
|
| 190 |
+
botResults.push({ id: bot.id, text: '', value: '', normalized: '', error: error.message });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 191 |
}
|
| 192 |
}
|
| 193 |
|
|
|
|
| 196 |
const usedIds = new Set();
|
| 197 |
let successfulMatches = 0;
|
| 198 |
|
|
|
|
| 199 |
const availableSoal = [...soalArray];
|
|
|
|
| 200 |
for (const bot of botResults) {
|
| 201 |
let matchedSoal = null;
|
| 202 |
let matchIndex = -1;
|
|
|
|
| 203 |
if (bot.value && bot.value.trim() !== '') {
|
| 204 |
for (let i = 0; i < availableSoal.length; i++) {
|
| 205 |
if (isValueMatch(bot.value, availableSoal[i])) {
|
|
|
|
| 211 |
}
|
| 212 |
}
|
| 213 |
}
|
|
|
|
| 214 |
if (matchedSoal) {
|
| 215 |
+
result.push({ id: bot.id, soal: matchedSoal, matchType: 'exact' });
|
|
|
|
|
|
|
|
|
|
|
|
|
| 216 |
availableSoal.splice(matchIndex, 1);
|
| 217 |
usedIds.add(bot.id);
|
| 218 |
} else {
|
| 219 |
+
result.push({ id: null, soal: '', matchType: 'none' });
|
|
|
|
|
|
|
|
|
|
|
|
|
| 220 |
}
|
| 221 |
}
|
| 222 |
|
| 223 |
console.log(`π DEBUG: Successful matches: ${successfulMatches}`);
|
| 224 |
|
|
|
|
| 225 |
if (successfulMatches >= 2) {
|
| 226 |
console.log('β
DEBUG: Minimal 2 match terpenuhi, mengisi bot yang belum match');
|
| 227 |
for (let i = 0; i < result.length; i++) {
|
|
|
|
| 235 |
}
|
| 236 |
}
|
| 237 |
|
|
|
|
| 238 |
for (let i = 0; i < result.length; i++) {
|
| 239 |
if (!result[i].id) {
|
| 240 |
if (successfulMatches >= 2) {
|
|
|
|
| 259 |
result: result.map(r => ({ id: r.id })),
|
| 260 |
debug: {
|
| 261 |
parsedSoal: soalArray,
|
| 262 |
+
matches: result.map(r => ({ id: r.id, matchType: r.matchType, soal: r.soal })),
|
|
|
|
|
|
|
|
|
|
|
|
|
| 263 |
totalResults: result.length,
|
| 264 |
successfulMatches: successfulMatches
|
| 265 |
}
|
| 266 |
}
|
| 267 |
};
|
|
|
|
| 268 |
} catch (error) {
|
| 269 |
console.error('π₯ DEBUG antibot Error:', error.message);
|
| 270 |
+
return { success: false, error: error.message, data: { soal: [], botResults: [], result: [] } };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 271 |
}
|
| 272 |
}
|
| 273 |
|