前端 AI 应用 Demo
浏览器端图片分类/OCR、文本翻译/摘要、语音识别、实时姿态检测
前端 AI Demo 概览
随着 Web 技术的发展,JavaScript 运行时性能和 Web API 能力大幅提升,前端 AI 推理已成为现实。本文档展示的 Demo 具备以下核心优势:
- 所有推理都在浏览器端完成:利用 WebGL / WebGPU 加速,模型直接在用户浏览器中运行,不依赖任何后端服务。
- 无需服务器 API Key:模型权重通过 CDN 加载到本地,调用过程不产生 API 费用,用户隐私数据不会离开本机。
- 完全离线可用:模型权重首次加载并缓存后,即使断开网络连接,Demo 依然可以正常运行。
本文将从图片分类、OCR、文本翻译/摘要、语音识别和实时姿态检测五个方向展示具体实现。
图片分类 Demo
使用 Transformers.js 的 image-classification pipeline,实现上传图片后实时输出 Top-5 类别与概率。
流程说明
用户通过文件选择器上传图片 -> 浏览器读取图片并缩放到模型输入尺寸 (224x224) -> 调用 Transformers.js 的 image-classification pipeline 进行推理 -> 解析输出张量,提取概率最高的前 5 个类别 -> 渲染到页面 DOM。
核心代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>图片分类 Demo</title>
<script src="https://cdn.jsdelivr.net/npm/@huggingface/transformers@3"></script>
</head>
<body>
<h1>图片分类 Demo</h1>
<input type="file" id="imageInput" accept="image/*" />
<img id="preview" style="max-width: 300px; display: none;" />
<div id="result"></div>
<script>
const imageInput = document.getElementById('imageInput');
const preview = document.getElementById('preview');
const resultDiv = document.getElementById('result');
imageInput.addEventListener('change', async (e) => {
const file = e.target.files[0];
if (!file) return;
const url = URL.createObjectURL(file);
preview.src = url;
preview.style.display = 'block';
resultDiv.textContent = '模型加载中,请稍候...';
const classifier = await TransformersJs.pipeline(
'image-classification',
'Xenova/resnet-50'
);
const output = await classifier(url);
resultDiv.innerHTML = '<h3>Top-5 分类结果</h3>' +
output.slice(0, 5).map((item, i) =>
`<p>${i + 1}. ${item.label} — ${(item.score * 100).toFixed(2)}%</p>`
).join('');
});
</script>
</body>
</html>OCR(光学字符识别)Demo
使用 Transformers.js 的 TrOCR 模型,将图片中的印刷文字识别为可编辑文本。
识别流程
上传图片 -> 浏览器读取图片 -> 使用 TrOCR pipeline 进行端到端 OCR 推理 -> 输出识别文本并显示在页面中。TrOCR 是微软推出的基于 Transformer 架构的 OCR 模型,将图像编码为特征序列后由文本解码器生成文字,无需传统 OCR 的字符分割步骤。
核心代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>OCR Demo</title>
<script src="https://cdn.jsdelivr.net/npm/@huggingface/transformers@3"></script>
</head>
<body>
<h1>OCR 文字识别 Demo</h1>
<input type="file" id="ocrInput" accept="image/*" />
<img id="ocrPreview" style="max-width: 300px; display: none;" />
<div id="ocrResult"></div>
<script>
const ocrInput = document.getElementById('ocrInput');
const ocrPreview = document.getElementById('ocrPreview');
const ocrResult = document.getElementById('ocrResult');
ocrInput.addEventListener('change', async (e) => {
const file = e.target.files[0];
if (!file) return;
const url = URL.createObjectURL(file);
ocrPreview.src = url;
ocrPreview.style.display = 'block';
ocrResult.textContent = 'OCR 模型加载中...';
const processor = await TransformersJs.pipeline(
'image-to-text',
'Xenova/trocr-base-printed'
);
const result = await processor(url);
ocrResult.innerHTML = `<h3>识别结果</h3><p>${result[0].generated_text}</p>`;
});
</script>
</body>
</html>文本翻译/摘要 Demo
使用 Transformers.js 的 translation 和 summarization pipeline,在浏览器内完成文本翻译和自动摘要。
翻译流程
用户输入文本 -> 选择翻译方向(如 en->zh)-> 调用 translation pipeline 加载对应模型 -> 执行推理并输出翻译结果。
摘要流程
用户输入长文本 -> 调用 summarization pipeline -> 模型生成简洁摘要 -> 渲染输出。摘要 pipeline 内部使用编码器-解码器架构(如 BART),编码器理解全文语义,解码器逐步生成概括性文字。
核心代码
// 文本翻译
async function translate(text, sourceLang, targetLang) {
const translator = await TransformersJs.pipeline(
'translation',
`Xenova/nllb-200-distilled-600M`
);
const result = await translator(text, {
src_lang: sourceLang,
tgt_lang: targetLang,
});
return result[0].translation_text;
}
// 文本摘要
async function summarize(text) {
const summarizer = await TransformersJs.pipeline(
'summarization',
'Xenova/distilbart-cnn-6-6'
);
const result = await summarizer(text, {
max_length: 150,
min_length: 30,
});
return result[0].summary_text;
}
// 使用示例
const englishText = 'Artificial intelligence has transformed many industries...';
translate(englishText, 'eng_Latn', 'zho_Hans').then(console.log);
const longArticle = 'The rapid development of machine learning...';
summarize(longArticle).then(console.log);语音识别 Demo
使用浏览器 Web API 录制麦克风音频,再通过 Transformers.js 的 automatic-speech-recognition pipeline(Whisper 模型)将语音转为文字。
录音与识别流程
- 用户点击录音按钮,浏览器通过
MediaRecorderAPI 捕获麦克风音频流。 - 录音结束后将音频 Blob 转换为与模型输入兼容的浮点数组格式。
- 调用 Whisper pipeline 执行推理。
- 返回识别文本并显示在页面上。
核心代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>语音识别 Demo</title>
<script src="https://cdn.jsdelivr.net/npm/@huggingface/transformers@3"></script>
</head>
<body>
<h1>语音识别 Demo</h1>
<button id="recordBtn">开始录音</button>
<div id="asrResult"></div>
<script>
const recordBtn = document.getElementById('recordBtn');
const asrResult = document.getElementById('asrResult');
let mediaRecorder;
let audioChunks = [];
recordBtn.addEventListener('click', async () => {
if (mediaRecorder && mediaRecorder.state === 'recording') {
mediaRecorder.stop();
recordBtn.textContent = '开始录音';
return;
}
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
mediaRecorder = new MediaRecorder(stream);
audioChunks = [];
mediaRecorder.ondataavailable = (e) => audioChunks.push(e.data);
mediaRecorder.onstop = async () => {
const audioBlob = new Blob(audioChunks, { type: 'audio/webm' });
asrResult.textContent = '语音识别模型加载中...';
const recognizer = await TransformersJs.pipeline(
'automatic-speech-recognition',
'Xenova/whisper-tiny'
);
const audioArray = await audioBlobToFloat32Array(audioBlob);
const result = await recognizer(audioArray);
asrResult.innerHTML = `<h3>识别文本</h3><p>${result.text}</p>`;
};
mediaRecorder.start();
recordBtn.textContent = '停止录音';
});
async function audioBlobToFloat32Array(blob) {
const arrayBuffer = await blob.arrayBuffer();
const audioCtx = new AudioContext();
const audioData = await audioCtx.decodeAudioData(arrayBuffer);
return audioData.getChannelData(0);
}
</script>
</body>
</html>实时姿态检测 Demo
使用 TensorFlow.js 的 MoveNet 模型,通过摄像头视频流实时检测人体姿态关键点,并使用 Canvas 绘制骨架连线。
检测流程
- 请求摄像头权限,获取
getUserMedia视频流。 - 将视频帧传入 MoveNet 模型进行推理,输出 17 个人体关键点坐标与置信度。
- 在 Canvas 上绘制关键点(圆形)和骨架连线(线段)。
- 使用
requestAnimationFrame循环驱动连续推理,形成实时效果。
核心代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>实时姿态检测 Demo</title>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/pose-detection"></script>
</head>
<body>
<h1>实时姿态检测 Demo</h1>
<video id="video" width="640" height="480" autoplay playsinline></video>
<canvas id="canvas" width="640" height="480"></canvas>
<script>
const video = document.getElementById('video');
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
async function init() {
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
video.srcObject = stream;
await video.play();
const detector = await poseDetection.createDetector(
poseDetection.SupportedModels.MoveNet,
{ modelType: poseDetection.movenet.modelType.SINGLEPOSE_LIGHTNING }
);
detectLoop(detector);
}
async function detectLoop(detector) {
const poses = await detector.estimatePoses(video);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
if (poses.length > 0) {
const keypoints = poses[0].keypoints;
// 绘制关键点
keypoints.forEach((kp) => {
if (kp.score > 0.3) {
ctx.beginPath();
ctx.arc(kp.x, kp.y, 5, 0, 2 * Math.PI);
ctx.fillStyle = '#00FF00';
ctx.fill();
}
});
// 绘制骨架连线
const connections = [
['nose', 'left_eye'], ['nose', 'right_eye'],
['left_eye', 'left_ear'], ['right_eye', 'right_ear'],
['left_shoulder', 'right_shoulder'],
['left_shoulder', 'left_elbow'], ['left_elbow', 'left_wrist'],
['right_shoulder', 'right_elbow'], ['right_elbow', 'right_wrist'],
['left_shoulder', 'left_hip'], ['right_shoulder', 'right_hip'],
['left_hip', 'right_hip'],
['left_hip', 'left_knee'], ['left_knee', 'left_ankle'],
['right_hip', 'right_knee'], ['right_knee', 'right_ankle'],
];
const kpMap = {};
keypoints.forEach((kp) => { kpMap[kp.name] = kp; });
ctx.strokeStyle = '#00FF00';
ctx.lineWidth = 2;
connections.forEach(([a, b]) => {
if (kpMap[a] && kpMap[b] &&
kpMap[a].score > 0.3 && kpMap[b].score > 0.3) {
ctx.beginPath();
ctx.moveTo(kpMap[a].x, kpMap[a].y);
ctx.lineTo(kpMap[b].x, kpMap[b].y);
ctx.stroke();
}
});
}
requestAnimationFrame(() => detectLoop(detector));
}
init();
</script>
</body>
</html>模型与框架对比
下表总结了各 Demo 使用的模型和前端推理框架:
| Demo 项目 | 使用模型 | 框架 / 库 | 输入类型 | 输出类型 |
|---|---|---|---|---|
| 图片分类 | ResNet-50 | Transformers.js | 图片 (224x224) | Top-5 类别与概率 |
| OCR 识别 | TrOCR (base-printed) | Transformers.js | 图片 | 识别文本字符串 |
| 文本翻译 | NLLB-200 (distilled-600M) | Transformers.js | 源语言文本 | 目标语言文本 |
| 文本摘要 | DistilBART-CNN (6-6) | Transformers.js | 长文本 | 概括性摘要文本 |
| 语音识别 | Whisper (tiny) | Transformers.js + Web Audio API | 麦克风音频流 | 转录文本 |
| 姿态检测 | MoveNet (Lightning) | TensorFlow.js + pose-detection | 摄像头视频帧 | 17 个人体关键点 |
框架选择建议
- Transformers.js:适合绝大多数 NLP 和多模态任务(分类、OCR、翻译、摘要、语音识别),模型覆盖面广,API 设计与 Python Transformers 库一致,迁移成本低。模型权重首次加载需要数秒至数十秒(取决于模型大小),后续推理速度可接受。
- TensorFlow.js + pose-detection:针对实时视觉任务优化,MoveNet Lightning 模型在普通笔记本上可达 30+ FPS,适合姿态检测、手势识别等需要低延迟的场景。
- MediaPipe:Google 推出的跨平台解决方案,针对移动端和 Web 端做了深度优化,提供姿态、人脸、手部关键点检测能力,在性能上优于 TensorFlow.js 方案,但集成方式不同,需要配合 MediaPipe 的 Graph 机制。
以上 Demo 展示了浏览器端 AI 推理的完整能力覆盖。在实际项目中,可以根据具体场景选择合适的模型和框架组合,在用户隐私保护、服务端成本和实时性之间取得平衡。