import { pipeline, DataType } from "@huggingface/transformers"; class Translator { private static instance: Translator | null = null; private pipeline: any = null; private static modelId: string = "onnx-community/translategemma-text-4b-it-ONNX"; private static dtype: DataType = "q4"; public static size: number = 3111894696; private constructor() {} public static getInstance(): Translator { if (!Translator.instance) { Translator.instance = new Translator(); } return Translator.instance; } public async init(onProgress?: (progress: number) => void) { if (this.pipeline) return; const loaded = new Map(); let newProgress = 0; this.pipeline = await pipeline("text-generation", Translator.modelId, { progress_callback: (e) => { if (e.status === "progress") { loaded.set(e.file, e.loaded); const allLoaded = Array.from(loaded.values()).reduce( (acc: number, curr: number) => acc + curr, 0 ); const percentLoaded = Math.round((100 / Translator.size) * allLoaded * 100) / 100; if (newProgress !== percentLoaded) { newProgress = percentLoaded; onProgress(newProgress); } } }, device: "webgpu", dtype: Translator.dtype, }); } public async translate( text: string, sourceLang: string, targetLang: string ): Promise { if (!this.pipeline) { throw new Error("Translator not initialized. Call init() first."); } const messages = [ { role: "user", content: [ { type: "text", source_lang_code: sourceLang, target_lang_code: targetLang, text, }, ], }, ]; const output = await this.pipeline(messages, { max_new_tokens: 1024, }); return output[0].generated_text.pop().content; } } export default Translator;