从 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 实践!