应用页面
App.jsx

- import { useEffect, useRef, useState } from 'react';
- import LanguageSelector from './components/LanguageSelector'; // 语言选择器组件
- import Progress from './components/Progress'; // 进度条组件
- import './App.css'; // 应用样式
- function App() {
- // 状态管理
- const [ready, setReady] = useState(null); // 模型准备状态
- const [disabled, setDisabled] = useState(false); // 翻译按钮是否禁用
- const [progressItems, setProgressItems] = useState([]); // 进度条
- // 输入输出状态管理
- const [input, setInput] = useState('I love walking my dog.'); // 输入文本
- const [sourceLanguage, setSourceLanguage] = useState('eng_Latn'); // 源语言
- const [targetLanguage, setTargetLanguage] = useState('fra_Latn'); // 目标语言
- const [output, setOutput] = useState(''); // 输出文本
- // 创建一个对worker对象的引用
- const worker = useRef(null);
- // 使用`useEffect`钩子在组件挂载时设置worker
- useEffect(() => {
- if (!worker.current) {
- // 如果worker不存在,则创建一个新的Worker实例
- worker.current = new Worker(new URL('./worker.js', import.meta.url), {
- type: 'module' // 指定worker脚本类型为ES模块
- });
- }
- // 给worker添加消息事件监听器
- worker.current.addEventListener('message', onMessageReceived);
-
- // 定义从worker接收消息后的回调处理函数
- const onMessageReceived = (e) => {
- switch (e.data.status) {
- case 'initiate': // 开始加载模型文件时,更新状态并添加进度项
- setReady(false);
- setProgressItems(prev => [...prev, e.data]);
- break;
- case 'progress': // 更新模型文件加载进度
- setProgressItems(prev => prev.map(item => item.file === e.data.file ? { ...item, progress: e.data.progress } : item));
- break;
- case 'done': // 模型文件加载完成,从进度列表中移除该项目
- setProgressItems(prev => prev.filter(item => item.file !== e.data.file));
- break;
- case 'ready': // 工作线程准备好接受消息
- setReady(true);
- break;
- case 'update': // 更新输出文本
- setOutput(e.data.output);
- break;
- case 'complete': // 翻译完成,启用“翻译”按钮
- setDisabled(false);
- break;
- }
- };
- // 返回一个清理函数,在组件卸载时移除事件监听器
- return () => worker.current.removeEventListener('message', onMessageReceived);
- });
- // 翻译函数
- const translate = () => {
- setDisabled(true); // 禁用翻译按钮
- worker.current.postMessage({ // 发送消息给worker开始翻译
- text: input,
- src_lang: sourceLanguage,
- tgt_lang: targetLanguage,
- });
- }
- // 渲染UI
- return (
- <>
- <h1>Transformers.js</h1>
- <h2>ML-powered multilingual translation in React!</h2>
- {/* UI布局,关键在于调用translate函数 */}
- <div className='container'>
- <div className='language-container'>
- <LanguageSelector type={"Source"} defaultLanguage={"eng_Latn"} onChange={x => setSourceLanguage(x.target.value)} />
- <LanguageSelector type={"Target"} defaultLanguage={"fra_Latn"} onChange={x => setTargetLanguage(x.target.value)} />
- </div>
- <div className='textbox-container'>
- <textarea value={input} rows={3} onChange={e => setInput(e.target.value)}></textarea>
- <textarea value={output} rows={3} readOnly></textarea>
- </div>
- </div>
- <button disabled={disabled} onClick={translate}>Translate</button>
- <div className='progress-bars-container'>
- {ready === false && <label>Loading models... (only run once)</label>}
- {progressItems.map(data => (
- <div key={data.file}>
- <Progress text={data.file} percentage={data.progress} />
- </div>
- ))}
- </div>
- </>
- );
- }
- export default App; // 导出默认组件
复制代码 worker.js
- 代码定义了一个使用单例模式的MyTranslationPipeline,并通过Web Worker监听主线程的消息来实行翻译任务(Worker线程消息通报):
- import { pipeline } from '@xenova/transformers'; // 导入pipeline函数用于加载模型
- // 使用单例模式确保仅加载一次翻译管道实例。由于加载管道是一个昂贵的操作,我们不希望每次翻译句子时都重新加载。
- class MyTranslationPipeline {
- static task = 'translation'; // 任务类型
- static model = 'Xenova/nllb-200-distilled-600M'; // 模型名称
- static instance = null; // 静态变量:存储单例实例
- /**
- * 获取或创建一个翻译管道的实例。
- * @param progress_callback - 进度回调函数,用于追踪模型加载进度。@returns {Promise<*>} - 返回已加载的翻译管道实例。
- */
- static async getInstance(progress_callback = null) {
- if (this.instance === null) { // 如果尚未创建实例,则加载新的翻译管道并保存
- // 1. pipeline函数transformers.js模型加载:默认情况下,模型将从 Hugging Face Hub 下载并存储在 浏览器缓存 中,有关更多信息,请参见https://hugging-face.cn/docs/transformers.js/custom_usage。
- this.instance = await pipeline(this.task, this.model, { progress_callback });
- }
- return this.instance; // 返回实例
- }
- }
- // 监听来自主线程的消息事件
- self.addEventListener('message', async (event) => {
- // 获取翻译管道实例,首次调用时将加载管道并保存以备将来使用
- let translator = await MyTranslationPipeline.getInstance(x => {
- // 添加进度回调函数,以便跟踪模型加载进度
- self.postMessage(x);
- });
- // 2. transformers.js模型执行实际的翻译操作
- let output = await translator(event.data.text, {
- tgt_lang: event.data.tgt_lang, // 目标语言
- src_lang: event.data.src_lang, // 源语言
- // 允许部分输出,并通过回调函数发送更新
- callback_function: x => {
- self.postMessage({
- status: 'update', // 状态更新
- output: translator.tokenizer.decode(x[0].output_token_ids, { skip_special_tokens: true }) // 解码输出文本
- });
- }
- });
- // 将翻译结果发送回主线程
- self.postMessage({
- status: 'complete', // 完成状态
- output: output, // 最终的翻译输出
- });
- });
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |