babelbox / worker.js
malen-h's picture
Flatten frontend for Hugging Face Space
8e866b9
Raw
History Blame Contribute Delete
10.8 kB
import { pipeline, env } from 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.0.0-alpha.19';
// Memory & Performance Tuning
env.backends.onnx.wasm.numThreads = 2;
env.useBrowserCache = true;
let objectDetector = null;
let targetLanguage = 'spa_Latn';
let detectionThreshold = 0.75;
let focusMode = true;
const labelTranslations = {
spa_Latn: {
person: 'persona',
bicycle: 'bicicleta',
car: 'coche',
motorcycle: 'motocicleta',
airplane: 'avion',
bus: 'autobus',
train: 'tren',
truck: 'camion',
boat: 'barco',
'traffic light': 'semaforo',
'fire hydrant': 'hidrante',
'stop sign': 'senal de alto',
bench: 'banco',
bird: 'pajaro',
cat: 'gato',
dog: 'perro',
horse: 'caballo',
sheep: 'oveja',
cow: 'vaca',
backpack: 'mochila',
umbrella: 'paraguas',
handbag: 'bolso',
tie: 'corbata',
suitcase: 'maleta',
frisbee: 'frisbee',
skis: 'esquis',
snowboard: 'tabla de snowboard',
'sports ball': 'pelota',
kite: 'cometa',
'baseball bat': 'bate de beisbol',
skateboard: 'patineta',
surfboard: 'tabla de surf',
bottle: 'botella',
'wine glass': 'copa',
cup: 'taza',
fork: 'tenedor',
knife: 'cuchillo',
spoon: 'cuchara',
bowl: 'tazon',
banana: 'platano',
apple: 'manzana',
sandwich: 'sandwich',
orange: 'naranja',
broccoli: 'brocoli',
carrot: 'zanahoria',
pizza: 'pizza',
donut: 'dona',
cake: 'pastel',
chair: 'silla',
couch: 'sofa',
bed: 'cama',
table: 'mesa',
toilet: 'inodoro',
tv: 'televisor',
laptop: 'portatil',
mouse: 'raton',
remote: 'control remoto',
keyboard: 'teclado',
'cell phone': 'telefono movil',
microwave: 'microondas',
oven: 'horno',
toaster: 'tostadora',
sink: 'fregadero',
refrigerator: 'refrigerador',
book: 'libro',
clock: 'reloj',
vase: 'florero',
scissors: 'tijeras',
'teddy bear': 'oso de peluche',
'hair drier': 'secador de pelo',
toothbrush: 'cepillo de dientes'
},
fra_Latn: {
person: 'personne',
bicycle: 'velo',
car: 'voiture',
motorcycle: 'moto',
airplane: 'avion',
bus: 'bus',
train: 'train',
truck: 'camion',
boat: 'bateau',
'traffic light': 'feu de circulation',
'stop sign': 'panneau stop',
bench: 'banc',
bird: 'oiseau',
cat: 'chat',
dog: 'chien',
horse: 'cheval',
sheep: 'mouton',
cow: 'vache',
backpack: 'sac a dos',
umbrella: 'parapluie',
handbag: 'sac a main',
tie: 'cravate',
suitcase: 'valise',
'sports ball': 'ballon',
bottle: 'bouteille',
'wine glass': 'verre a vin',
cup: 'tasse',
fork: 'fourchette',
knife: 'couteau',
spoon: 'cuillere',
bowl: 'bol',
banana: 'banane',
apple: 'pomme',
sandwich: 'sandwich',
orange: 'orange',
broccoli: 'brocoli',
carrot: 'carotte',
pizza: 'pizza',
donut: 'beignet',
cake: 'gateau',
chair: 'chaise',
couch: 'canape',
bed: 'lit',
table: 'table',
toilet: 'toilettes',
tv: 'television',
laptop: 'ordinateur portable',
mouse: 'souris',
remote: 'telecommande',
keyboard: 'clavier',
'cell phone': 'telephone portable',
book: 'livre',
clock: 'horloge',
vase: 'vase',
scissors: 'ciseaux',
toothbrush: 'brosse a dents'
},
zho_Hans: {
person: 'ren',
car: 'qiche',
bus: 'gonggongqiche',
train: 'huoche',
truck: 'ka che',
bird: 'niao',
cat: 'mao',
dog: 'gou',
horse: 'ma',
backpack: 'beibao',
umbrella: 'yu san',
bottle: 'pingzi',
cup: 'beizi',
fork: 'chazi',
knife: 'dao',
spoon: 'shaozi',
bowl: 'wan',
banana: 'xiangjiao',
apple: 'pingguo',
orange: 'chengzi',
carrot: 'huluobo',
pizza: 'pisa',
cake: 'dangao',
chair: 'yizi',
couch: 'shafa',
bed: 'chuang',
table: 'zhuozi',
tv: 'dianshi',
laptop: 'bijibendiannao',
mouse: 'shubiao',
keyboard: 'jianpan',
'cell phone': 'shouji',
book: 'shu',
clock: 'zhong',
toothbrush: 'yashua'
},
hin_Deva: {
person: 'vyakti',
bicycle: 'saikil',
car: 'kar',
bus: 'bas',
train: 'relgadi',
truck: 'trak',
bird: 'pakshi',
cat: 'billi',
dog: 'kutta',
horse: 'ghoda',
backpack: 'basta',
umbrella: 'chhata',
bottle: 'botal',
cup: 'cup',
fork: 'kanta',
knife: 'chaku',
spoon: 'chammach',
bowl: 'katora',
banana: 'kela',
apple: 'seb',
orange: 'santra',
carrot: 'gajar',
pizza: 'pizza',
cake: 'cake',
chair: 'kursi',
couch: 'sofa',
bed: 'bistar',
table: 'mez',
tv: 'TV',
laptop: 'laptop',
mouse: 'mouse',
keyboard: 'keyboard',
'cell phone': 'mobile phone',
book: 'kitaab',
clock: 'ghadi',
toothbrush: 'toothbrush'
},
afr_Latn: {
person: 'persoon',
bicycle: 'fiets',
car: 'motor',
bus: 'bus',
train: 'trein',
truck: 'vragmotor',
bird: 'voel',
cat: 'kat',
dog: 'hond',
horse: 'perd',
backpack: 'rugsak',
umbrella: 'sambreel',
bottle: 'bottel',
cup: 'koppie',
fork: 'vurk',
knife: 'mes',
spoon: 'lepel',
bowl: 'bak',
banana: 'piesang',
apple: 'appel',
orange: 'lemoen',
carrot: 'wortel',
pizza: 'pizza',
cake: 'koek',
chair: 'stoel',
couch: 'bank',
bed: 'bed',
table: 'tafel',
tv: 'televisie',
laptop: 'skootrekenaar',
mouse: 'muis',
keyboard: 'sleutelbord',
'cell phone': 'selfoon',
book: 'boek',
clock: 'horlosie',
toothbrush: 'tandeborsel'
},
zul_Latn: {
person: 'umuntu',
bicycle: 'ibhayisikili',
car: 'imoto',
bus: 'ibhasi',
train: 'isitimela',
truck: 'iloli',
bird: 'inyoni',
cat: 'ikati',
dog: 'inja',
horse: 'ihhashi',
backpack: 'ubhaka',
umbrella: 'isambulela',
bottle: 'ibhodlela',
cup: 'inkomishi',
fork: 'imfoloko',
knife: 'ummese',
spoon: 'isipuni',
bowl: 'isitsha',
banana: 'ubhanana',
apple: 'i-apula',
orange: 'iwolintshi',
carrot: 'isanqante',
pizza: 'iphiza',
cake: 'ikhekhe',
chair: 'isitulo',
couch: 'usofa',
bed: 'umbhede',
table: 'itafula',
tv: 'ithelevishini',
laptop: 'ikhompyutha ephathwayo',
mouse: 'igundane',
keyboard: 'ikhibhodi',
'cell phone': 'umakhalekhukhwini',
book: 'incwadi',
clock: 'iwashi',
toothbrush: 'isixubho'
}
};
function translateLabel(label) {
const normalizedLabel = label.toLowerCase().replaceAll('-', ' ');
return labelTranslations[targetLanguage]?.[normalizedLabel] ?? label;
}
function getBoxArea(result) {
const box = result.box;
const xmin = Array.isArray(box) ? box[0] : box?.xmin;
const ymin = Array.isArray(box) ? box[1] : box?.ymin;
const xmax = Array.isArray(box) ? box[2] : box?.xmax;
const ymax = Array.isArray(box) ? box[3] : box?.ymax;
if (![xmin, ymin, xmax, ymax].every(Number.isFinite)) {
return 0;
}
return Math.max(0, xmax - xmin) * Math.max(0, ymax - ymin);
}
// Helper to send progress updates to UI
const progressCallback = (progress) => {
if (progress.status === 'progress') {
postMessage({
type: 'status',
data: `Downloading ${progress.file}: ${Math.round(progress.progress)}%`
});
} else if (progress.status === 'done') {
postMessage({ type: 'status', data: `Loaded ${progress.file}` });
}
};
async function initModels() {
try {
postMessage({ type: 'status', data: 'Initializing Vision Model (DETR)...' });
objectDetector = await pipeline('object-detection', 'Xenova/detr-resnet-50', {
device: 'webgpu',
progress_callback: progressCallback
});
postMessage({ type: 'status', data: 'ready' });
} catch (err) {
console.error("Model initialization failed:", err);
postMessage({ type: 'status', data: 'Error loading models: ' + err.message });
}
}
initModels();
self.addEventListener('message', async (event) => {
const { type, image, language, threshold } = event.data;
if (type === 'set-language') {
if (targetLanguage !== language) {
targetLanguage = language;
}
}
if (type === 'set-threshold') {
detectionThreshold = threshold;
}
if (type === 'set-focus-mode') {
focusMode = event.data.enabled;
}
if (type === 'detect' && objectDetector) {
let imageUrl = null;
try {
imageUrl = URL.createObjectURL(image);
const detectionResults = await objectDetector(imageUrl, {
threshold: detectionThreshold,
percentage: false
});
const translatedResults = detectionResults
.map((res) => ({
...res,
area: getBoxArea(res),
translated_label: translateLabel(res.label)
}))
.filter((res) => res.area >= 2500)
.filter((res) => !focusMode || res.label !== 'person')
.sort((a, b) => (b.score * b.area) - (a.score * a.area))
.slice(0, focusMode ? 1 : 3);
postMessage({ type: 'results', data: translatedResults });
} catch (err) {
console.error("Inference error:", err);
postMessage({ type: 'results', data: [] });
} finally {
if (imageUrl) {
URL.revokeObjectURL(imageUrl);
}
}
}
});