news 2026/5/1 15:33:03

用 Vue3 #x2B; fetch-event-source 打造流式 AI 翻译平台:OCR #x2B; 大模型 #x2B; SSE 全链路实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用 Vue3 #x2B; fetch-event-source 打造流式 AI 翻译平台:OCR #x2B; 大模型 #x2B; SSE 全链路实战

从 UI 工程师到 AI 应用架构者

13 年前,我的工作是让按钮在 IE6 上对齐;
13 年后,我用fetch-event-source订阅大模型的“思维流”,用 OCR 解锁图片中的文字——前端,正在成为 AI 产品的第一道体验防线

最近,我基于Vue 3 + Vite + TypeScript + Ant Design Vue开发了一款企业级 AI 多语翻译平台。它支持:

    • ✅ 文本/图片/文档多模态输入
    • ✅ 大模型动态切换(通义千问、DeepSeek 等)
    • ✅ 行业领域定制(医疗、法律、金融)
    • SSE 流式输出(使用fetch-event-source

今天,我将逐行拆解核心代码,带你复现这一高价值 AI 应用的前端架构。


一、技术选型:为什么是fetch-event-source

虽然浏览器原生支持EventSource,但在现代前端工程中,我们更倾向使用@microsoft/fetch-event-source

    • ✅ 基于fetch,天然支持AbortController(可取消请求)
    • ✅ 支持自定义 headers(用于鉴权)
    • ✅ 更好的TypeScript 类型支持
    • ✅ 与 Axios/Vite 生态无缝集成

安装:

/* by 01022.hk - online tools website : 01022.hk/zh/checkweixin.html */ npm install @microsoft/fetch-event-source

二、OCR 图片识别:前端只管“传”和“显”

用户上传一张英文菜单截图,系统自动提取文字并翻译。前端不碰 OCR 算法,但要管理全流程状态

🔧 真实代码实现(来自文本_r9uv.txt

1.系统配置加载(含文件大小限制)
/* by 01022.hk - online tools website : 01022.hk/zh/checkweixin.html */ // src/views/translation/index.vue const loadSystemPublicConfig = async () => { try { const response = await findSystemPublicConfig({ configKey: 'upload_file_max_limit_mb' }); const config = response.data[0]; systemConfig.value.uploadFileMaxLimit = parseInt(config.value) || 10; // 默认10MB } catch (error) { ElMessage.error('加载系统配置失败'); } };
2.文件选择与校验
const handleFileSelect = (event: Event) => { const input = event.target as HTMLInputElement; if (input.files && input.files.length > 0) { const file = input.files[0]; const maxSize = systemConfig.value.uploadFileMaxLimit * 1024 * 1024; if (file.size > maxSize) { message.error(`文件不能超过 ${systemConfig.value.uploadFileMaxLimit} MB`); return; } currentFile.value = file; startParsing(file); } };
3.调用 OCR 接口(Ant Design Vue 组件反馈)
const handleObtainFileContentText = async () => { if (!currentFile.value) return; const formData = new FormData(); formData.append('file', currentFile.value); try { const response = await obtainFileContentText(formData); if (response.success) { sourceLanguageText.value = response.data.contentText; currentUploadStatus.value = 'success'; } else { currentUploadStatus.value = 'failed'; message.error(response.message || '解析失败'); } } catch (error) { currentUploadStatus.value = 'failed'; message.error('网络错误,请重试'); } };

💡关键设计:状态分为'idle' | 'parsing' | 'success' | 'failed',对应四个 UI 区块,避免用户困惑。


三、大模型动态集成:让选择“无感而智能”

AI 模型不是越多越好,而是要默认最优 + 动态适配

🔧 真实代码实现

1.加载模型与语种字典
// 加载大模型列表 const loadLargeModelDictionary = async () => { const response = await findLargeModelDictionary({ keyword: '' }); largeModelList.value = response.data; if (largeModelList.value.length > 0) { const firstModel = largeModelList.value[0]; selectedModelId.value = firstModel.id; await loadLargeModelLanguageSupport(firstModel.id); // 关键:联动语种 } }; // 加载某模型支持的语种 const loadLargeModelLanguageSupport = async (modelId: string) => { const response = await findLargeModelLanguageSupport({ largeModelId: modelId }); languageSupportList.value = response.data; };
2.行业领域初始化
const loadIndustrySectorDictionary = async () => { const response = await findIndustrySectorDictionary({ keyword: '' }); industrySectorList.value = response.data; // 业务逻辑:若默认为 'general',则跳过 if (defaultIndustrySector.value === 'general' && industrySectorList.value.length > 1) { defaultIndustrySector.value = industrySectorList.value[1].code; } };
3.Ant Design Vue 下拉框绑定
<!-- 模型选择 --> <a-select v-model:value="selectedModelId" style="width: 100%" @change="handleModelChange" > <a-select-option v-for="item in largeModelList" :key="item.id" :value="item.id" > {{ item.name }} </a-select-option> </a-select>

四、SSE 流式翻译:用fetch-event-source实现“打字机效果”

这是体验升级的核心!我们使用@microsoft/fetch-event-source替代原生EventSource

🔧 完整流式翻译实现(结合你的项目结构)

import { fetchEventSource } from '@microsoft/fetch-event-source'; // 存储控制器,用于取消请求 let abortController: AbortController | null = null; const handleTranslate = async () => { if (isTranslating.value) return; // 重置结果 translationResult.value = ''; isTranslating.value = true; // 创建 AbortController abortController = new AbortController(); const params = new URLSearchParams({ largeModelId: selectedModelId.value, sourceLangCode: selectedSourceLangCode.value, targetLangCode: selectedTargetLangCode.value, industrySector: defaultIndustrySector.value, enableDeepThinking: String(enableDeepThinking.value), content: sourceLanguageText.value.trim(), }); try { await fetchEventSource(`/api/v1/large-model/translate/stream?${params}`, { method: 'GET', headers: { 'Authorization': `Bearer ${getToken()}`, // 从 Pinia 或 localStorage 获取 }, signal: abortAssistant.signal, // 支持取消 onmessage(event) { if (event.data) { translationResult.value += event.data; nextTick(() => { scrollToBottom(); }); } }, onclose() { isTranslating.value = false; }, onerror(err) { console.error('SSE Error:', err); message.error('翻译服务异常,请稍后重试'); isTranslating.value = false; abortController?.abort(); // 主动关闭 }, }); } catch (error) { if (abortController?.signal.aborted) { console.log('翻译已取消'); } else { message.error('连接失败'); } isTranslating.value = false; } }; // 取消翻译 const cancelTranslation = () => { if (abortController) { abortController.abort(); isTranslating.value = false; message.info('翻译已取消'); } };

🔧 自动滚动到底部

const scrollToBottom = () => { const container = document.querySelector('.translation-result-content'); if (container) { container.scrollTop = container.scrollHeight; } };

💡为什么不用 WebSocket?

    • SSE 是单向流(服务端 → 客户端),完美匹配“AI 生成文本”场景
    • fetch-event-source提供Promise 风格 API,更符合现代前端习惯

五、工程化亮点:13年经验的沉淀

✅ 1.响应式布局(PC/Mobile 适配)

const updateMainHeight = () => { const mainEl = document.querySelector('.main') as HTMLElement; if (!mainEl) return; if (isMobile.value) { mainEl.style.minHeight = '100vh'; mainEl.style.height = 'auto'; } else { mainEl.style.height = '100vh'; mainEl.style.minHeight = 'auto'; } };

✅ 2.内存清理(防止泄漏)

onUnmounted(() => { if (abortController) { abortController.abort(); } window.removeEventListener('resize', checkIsMobile); });

✅ 3.防重复提交 + 加载状态

<a-button type="primary" :loading="isTranslating" @click="handleTranslate" :disabled="!sourceLanguageText.trim()" > {{ isTranslating ? '翻译中...' : '开始翻译' }} </a-button>

结语:前端的价值,在“AI 与人之间”

这个项目让我确信:AI 时代,前端工程师的不可替代性在于“体验设计”

    • 我们用fetch-event-source把冰冷的 token 流变成温暖的“打字机”;
    • 我们用 Ant Design Vue 让复杂配置变得简单;
    • 我们用状态机管理 OCR 的每一步,不让用户迷失。

如果你也想从“切图仔”转型为“AI 应用架构者”,不妨从一个流式翻译工具开始。技术会过时,但解决问题的能力永远稀缺

项目技术栈:Vue 3.4 + Vite 5 + TypeScript + Ant Design Vue 4 + fetch-event-source
代码来源:本文所有逻辑均来自实际生产项目(已脱敏)
互动:你用过fetch-event-source吗?欢迎分享你的 SSE 实践!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/1 7:25:06

2026年,Agent与APP必有一战

旧钥匙打不开新大门&#xff0c;旧地图找不到新大陆。 刚过去的2025年&#xff0c;AI炙手可热&#xff0c;人工智能第一次走进人类日常生活——前所未有地通过手机AI甚至AI手机。 但颠覆与创新&#xff0c;也总是伴随“争议”。 从近年手机厂运用AI算法辅助&#xff0c;让更多人…

作者头像 李华
网站建设 2026/5/1 10:31:48

基于PLC的立体车库管理系统设计

基于PLC的立体车库管理系统设计与实现 第一章 绪论 随着城市汽车保有量激增&#xff0c;停车难已成为城市交通治理的核心痛点&#xff0c;立体车库凭借空间利用率高&#xff08;较传统平面车库提升3-5倍&#xff09;的优势成为主流解决方案&#xff0c;但传统立体车库多仅具备…

作者头像 李华
网站建设 2026/4/18 21:43:49

DDD 架构演进,单层、三层,四层,工程分层演进过程!

定义接口、创建方法、调用展示,其实编程写代码说到底也就这3步,人人都是程序员👨🏻‍💻。公司老板都觉得,它有个AI工具,它都能写代码。 但现在的系统工程的分层结构,可不只是一层就写个 Controller,甚至是3层(Model-View-Controller),也有可能是4层(DDD)架构。…

作者头像 李华
网站建设 2026/4/28 13:50:01

Python 的 with 语句:把「资源管理」这件事交给语法

文章目录一、with 语句是干什么的&#xff1f;二、不用 with 会发生什么&#xff1f;三、传统解法&#xff1a;try / finally四、with 的本质&#xff1a;语法级 try / finally五、上下文管理器&#xff08;Context Manager&#xff09;5.1 一个最简单的例子5.2 __enter__ 和 _…

作者头像 李华