| 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<string, number>(); | |
| 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<string> { | |
| 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; | |