XORE21 commited on
Commit
41ae39b
·
verified ·
1 Parent(s): 8b8af64

Create endpoints/antibot.js

Browse files
Files changed (1) hide show
  1. endpoints/antibot.js +229 -0
endpoints/antibot.js ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const Tesseract = require("tesseract.js");
2
+ const sharp = require("sharp");
3
+ const levenshtein = require("levenshtein-edit-distance");
4
+
5
+ const DICTIONARIES = {
6
+ wordnumber: { ONE: '1', TWO: '2', THREE: '3', FOUR: '4', FIVE: '5', SIX: '6', SEVEN: '7', EIGHT: '8', NINE: '9', TEN: '10' },
7
+ numberword: { '1': 'ONE', '2': 'TWO', '3': 'THREE', '4': 'FOUR', '5': 'FIVE', '6': 'SIX', '7': 'SEVEN', '8': 'EIGHT', '9': 'NINE', '10': 'TEN' },
8
+ numberroman: { '1': 'I', '2': 'II', '3': 'III', '4': 'IV', '5': 'V', '6': 'VI', '7': 'VII', '8': 'VIII', '9': 'IX', '10': 'X' },
9
+ romannumber: { I: '1', II: '2', III: '3', IV: '4', V: '5', VI: '6', VII: '7', VIII: '8', IX: '9', X: '10', VILL: '7' },
10
+ mathans: { '2-1': '1', '1+1': '2', '141': '2', '1+2': '3', '2+2': '4', '242': '4', '3+2': '5', '342': '5', '2+4': '6', '244': '6', '3+4': '7', '344': '7', '4+4': '8', '444': '8', '1+8': '9', '148': '9', '5+6': '11' },
11
+ ansmath: { '1': '3-2', '2': '8-6', '3': '1+2', '4': '3+1', '5': '9-4', '6': '3+3', '7': '6+1', '8': '2*4', '9': '3+6', '10': '2+8' },
12
+ oox: { '--X': 'OOX', '-X-': 'OXO', 'X--': 'XOO', 'XX-': 'XXO', '-XX': 'OXX', 'X-X': 'XOX', '---': 'OOO', 'XXX': 'XXX', 'X-X-': 'XOXO', '-X-X': 'OXOX' },
13
+ xxx: { '--X': '--+', '-X-': '-+-', 'X--': '+--', 'XX-': '++-', '-XX': '-++', 'X-X': '+-+', '---': '---', 'XXX': '+++', 'X-X-': '+-+-', '-X-X': '-+-+' },
14
+ xox: { '--X': 'OO+', '-X-': 'O+O', 'X--': '+OO', 'XX-': '++O', '-XX': 'O++', 'X-X': '+O+', '---': 'OOO', 'XXX': '+++', 'X-X-': '+O+O', '-X-X': 'O+O+' },
15
+ oxo: { OOX: '--+', OXO: '-+-', XOO: '+--', XXO: '++-', OXX: '-++', XOX: '+-+', OOO: '---', XXX: '+++', XOXO: '+-+-', OXOX: '-+-+' },
16
+ zoo: { ZOO: '200', OZO: '020', OOZ: '002', SOO: '500', OSO: '050', OOS: '005', LOL: '101', SOS: '505', ZOZ: '202', LLL: '111' },
17
+ ooz: { '200': 'ZOO', '020': 'OZO', '002': 'OOZ', '500': 'SOO', '050': 'OSO', '005': 'OOS', '101': 'LOL', '505': 'SOS', '202': 'ZOZ', '111': 'LLL' },
18
+ animals: { CAT: 'C@T', DOG: 'D0G', LION: '1!0N', TIGER: 'T!G3R', MONKEY: 'M0NK3Y', ELEPHANT: '31EPH@NT', COW: 'C0W', FOX: 'F0X', MOUSE: 'M0US3', ANT: '@NT' }
19
+ };
20
+
21
+ const LEET_GENERAL = {
22
+ '0': 'O', '1': 'I', '3': 'E', '4': 'A', '5': 'S', '7': 'T', '8': 'B', '@': 'A', '$': 'S', '!': 'I'
23
+ };
24
+
25
+ function applyVariations(word, type) {
26
+ let w = word.toUpperCase();
27
+
28
+ if (['numberword', 'mathans', 'ansmath'].includes(type)) {
29
+ w = w.replace(/[LIF\|\}]/g, '1').replace(/¢/g, '6').replace(/T/g, '+').replace(/Z/g, '2')
30
+ .replace(/Q/g, '7').replace(/\(/g, '6').replace(/#/g, '1+')
31
+ .replace(/FEN/g, 'TEN').replace(/4NREE/g, 'THREE')
32
+ .replace(/142|W2/g, '1+2').replace(/343/g, '3+3').replace(/SVEN/g, 'SEVEN')
33
+ .replace(/GIVE/g, 'FIVE').replace(/341/g, '3+1').replace(/1\+7/g, '1+1');
34
+ }
35
+
36
+ if (['romannumber', 'numberroman'].includes(type)) {
37
+ w = w.replace(/U/g, 'V').replace(/R/g, 'X').replace(/1/g, 'I')
38
+ .replace(/\\\\/g, 'VI').replace(/[\\\|]/g, 'I').replace(/™/g, 'III').replace(/XX/g, 'X');
39
+ }
40
+
41
+ if (['oxo', 'xox', 'xxx', 'oox'].includes(type)) {
42
+ w = w.replace(/[0D]/g, 'O').replace(/[TF]/g, '+');
43
+ }
44
+
45
+ if (type === 'zoo') {
46
+ w = w.replace(/0/g, 'O').replace(/[I\|]/g, 'L').replace(/8/g, 'S')
47
+ .replace(/\$/g, '5').replace(/S°S/g, 'SOS');
48
+ }
49
+
50
+ if (type === 'ooz') {
51
+ w = w.replace(/O/g, '0');
52
+ }
53
+
54
+ if (type === 'animals') {
55
+ w = w.replace(/ENT|@RT|ONT/g, 'ANT').replace(/TLG3R/g, 'TIGER').replace(/MOUSS/g, 'MOUSE')
56
+ .replace(/CET/g, 'CAT').replace(/10/g, 'LION')
57
+ .replace(/0/g, 'O').replace(/3/g, 'E').replace(/!/g, 'I').replace(/1/g, 'L').replace(/@/g, 'A');
58
+ }
59
+
60
+ return w;
61
+ }
62
+
63
+ function normalize(text) {
64
+ return text.replace(/[^a-zA-Z0-9+\-*@!]/g, "").toUpperCase();
65
+ }
66
+
67
+ function findBestMatch(scannedText) {
68
+ const cleanScanned = normalize(scannedText);
69
+ let bestMatch = { type: 'unknown', value: cleanScanned, score: 0 };
70
+
71
+ for (const [type, dict] of Object.entries(DICTIONARIES)) {
72
+ const variedText = applyVariations(cleanScanned, type);
73
+
74
+ if (dict[variedText]) return { type, value: dict[variedText], original: variedText };
75
+
76
+ for (const [key, val] of Object.entries(dict)) {
77
+ if (val === variedText) return { type, value: key, original: variedText };
78
+
79
+ const distKey = levenshtein(variedText, key);
80
+ const distVal = levenshtein(variedText, val);
81
+
82
+ if (distKey <= 1) return { type, value: val, original: key };
83
+ if (distVal <= 1) return { type, value: key, original: val };
84
+ }
85
+ }
86
+
87
+ return bestMatch;
88
+ }
89
+
90
+ const buf = b => Buffer.from(b.replace(/^data:image\/\w+;base64,/, ""), "base64");
91
+
92
+ async function preprocessImage(imageBuffer, type = 'main') {
93
+ let pipeline = sharp(imageBuffer)
94
+ .grayscale()
95
+ .normalize();
96
+
97
+ if (type === 'main') {
98
+ pipeline = pipeline
99
+ .resize({ width: 800 })
100
+ .sharpen({ sigma: 1.5 })
101
+ .threshold(140);
102
+ } else {
103
+ pipeline = pipeline
104
+ .resize({ height: 100 })
105
+ .sharpen({ sigma: 2.0 })
106
+ .median(1)
107
+ .threshold(128);
108
+ }
109
+
110
+ return await pipeline.toBuffer();
111
+ }
112
+
113
+ async function ocr(imageBuffer, psmMode = '6') {
114
+ try {
115
+ const result = await Tesseract.recognize(imageBuffer, "eng", {
116
+ tessedit_char_whitelist: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-*=@!$",
117
+ tessedit_pageseg_mode: psmMode
118
+ });
119
+ return result.data.text.trim();
120
+ } catch (e) {
121
+ console.error("OCR Failed: ", e);
122
+ return "";
123
+ }
124
+ }
125
+
126
+ module.exports = async (data) => {
127
+ try {
128
+ console.log("🚀 Starting AntiBot Analysis...");
129
+
130
+ const mainBuffer = buf(data.main);
131
+ const processedMain = await preprocessImage(mainBuffer, 'main');
132
+ const rawMainText = await ocr(processedMain, '7');
133
+
134
+ const mainWords = rawMainText.split(/\s+/).filter(w => w.length > 0);
135
+ console.log("📝 Raw Main Text: ", rawMainText);
136
+ console.log("📝 Parsed Words: ", mainWords);
137
+
138
+ let targetConcepts = [];
139
+ for (const word of mainWords) {
140
+ const match = findBestMatch(word);
141
+ if (match.type !== 'unknown') {
142
+ targetConcepts.push(match);
143
+ }
144
+ }
145
+
146
+ if (targetConcepts.length === 0) {
147
+ targetConcepts = mainWords.map(w => ({ type: 'raw', value: normalize(w) }));
148
+ }
149
+
150
+ console.log("🎯 Target Concepts: ", targetConcepts);
151
+
152
+ const botResults = [];
153
+ for (const bot of data.bots) {
154
+ const botBuffer = buf(bot.img);
155
+ const processedBot = await preprocessImage(botBuffer, 'bot');
156
+ const rawBotText = await ocr(processedBot, '6');
157
+ const cleanBotText = normalize(rawBotText);
158
+
159
+ const botAnalysis = findBestMatch(cleanBotText);
160
+
161
+ botResults.push({
162
+ id: bot.id,
163
+ raw: rawBotText,
164
+ clean: cleanBotText,
165
+ analysis: botAnalysis
166
+ });
167
+ }
168
+
169
+ const finalResult = [];
170
+ const usedBots = new Set();
171
+
172
+ for (const target of targetConcepts) {
173
+ let bestBotId = null;
174
+ let minDistance = 999;
175
+
176
+ for (const bot of botResults) {
177
+ if (usedBots.has(bot.id)) continue;
178
+
179
+ if (target.value === bot.analysis.value || target.value === bot.clean) {
180
+ bestBotId = bot.id;
181
+ minDistance = 0;
182
+ break;
183
+ }
184
+
185
+ const dist = levenshtein(target.value, bot.clean);
186
+ if (dist < minDistance && dist <= 2) {
187
+ minDistance = dist;
188
+ bestBotId = bot.id;
189
+ }
190
+ }
191
+
192
+ if (bestBotId) {
193
+ finalResult.push(bestBotId);
194
+ usedBots.add(bestBotId);
195
+ } else {
196
+ finalResult.push(null);
197
+ }
198
+ }
199
+
200
+ for (let i = 0; i < finalResult.length; i++) {
201
+ if (finalResult[i] === null) {
202
+ for (const bot of botResults) {
203
+ if (!usedBots.has(bot.id)) {
204
+ finalResult[i] = bot.id;
205
+ usedBots.add(bot.id);
206
+ break;
207
+ }
208
+ }
209
+ }
210
+ }
211
+
212
+ console.log("✅ Final Result IDs: ", finalResult);
213
+
214
+ return {
215
+ success: true,
216
+ soal: mainWords,
217
+ bots_analysis: botResults.map(b => ({ id: b.id, text: b.clean })),
218
+ result: finalResult.filter(x => x !== null)
219
+ };
220
+
221
+ } catch (error) {
222
+ console.error("💥 Antibot Error: ", error);
223
+ return {
224
+ success: false,
225
+ error: error.message,
226
+ result: []
227
+ };
228
+ }
229
+ };