news 2026/5/1 22:15:11

美团面试:为什么要用分布式缓存?本地缓存呢?多级缓存一致性如何保证?只

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
美团面试:为什么要用分布式缓存?本地缓存呢?多级缓存一致性如何保证?只

从 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 生态无缝集成

安装:

npm install @microsoft/fetch-event-source

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

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

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

1. 系统配置加载(含文件大小限制)

// 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 下拉框绑定

v-model:value="selectedModelId"

style="width: 100%"

@change="handleModelChange"

>

v-for="item in largeModelList"

:key="item.id"

:value="item.id"

>

{{ item.name }}

四、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. 防重复提交 + 加载状态

type="primary"

:loading="isTranslating"

@click="handleTranslate"

:disabled="!sourceLanguageText.trim()"

>

{{ isTranslating '翻译中...' : '开始翻译' }}

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

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

我们用 fetch-event-source 把冰冷的 token 流变成温暖的“打字机”;

我们用 Ant Design Vue 让复杂配置变得简单;

我们用状态机管理 OCR 的每一步,不让用户迷失。匈窗讨柯

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

如何快速上手Kyutai STT:10分钟实现实时语音转文本

如何快速上手Kyutai STT:10分钟实现实时语音转文本 【免费下载链接】delayed-streams-modeling Kyutais Speech-To-Text and Text-To-Speech models based on the Delayed Streams Modeling framework. 项目地址: https://gitcode.com/gh_mirrors/de/delayed-stre…

作者头像 李华
网站建设 2026/4/12 19:02:52

SQL高效合并多维度报表的数据方案_利用JOIN连接汇总

应根据数据完整性需求选择:需保留主表所有维度时用LEFT JOIN,仅关注匹配事实时用INNER JOIN;注意ON条件字段类型一致、NULL处理及索引优化,避免行数膨胀。用 LEFT JOIN 还是 INNER JOIN 合并报表?看数据完整性需求合并…

作者头像 李华
网站建设 2026/4/10 22:54:13

如何用QtScrcpy实现Android设备零延迟投屏:完整指南与实战技巧

如何用QtScrcpy实现Android设备零延迟投屏:完整指南与实战技巧 【免费下载链接】QtScrcpy Android实时投屏软件,此应用程序提供USB(或通过TCP/IP)连接的Android设备的显示和控制。它不需要任何root访问权限 项目地址: https://gitcode.com/barry-ran/Q…

作者头像 李华
网站建设 2026/4/10 22:53:16

如何免费创建防关联浏览器:VirtualBrowser终极指南

如何免费创建防关联浏览器:VirtualBrowser终极指南 【免费下载链接】VirtualBrowser Free anti fingerprint browser, 指纹浏览器, 隐私浏览器, 防识别浏览器, 反识别浏览器, 防关联浏览器, 免费的web3空投专用指纹浏览器 https://virtualbrowser.cc/?srcgithub …

作者头像 李华
网站建设 2026/4/12 1:38:43

别再乱用@property了!Python属性装饰器的5个常见误区与正确姿势

别再乱用property了!Python属性装饰器的5个常见误区与正确姿势 在Python开发中,property装饰器常被误认为是简单的"方法转属性"工具,但它的真正价值远不止于此。许多开发者在使用时容易陷入表面理解的陷阱,导致代码出现…

作者头像 李华