DeepSeek-OCR-WEBUI核心功能解析|附SpringBoot接入实战案例
1. DeepSeek-OCR-WEBUI是什么?为什么值得关注?
你有没有遇到过这样的场景:一堆纸质单据、发票、合同需要录入系统,手动一条条敲键盘不仅费时,还容易出错。这时候,如果有一款工具能“看懂”图片里的文字,甚至还能识别表格结构,直接把内容转成结构化数据,那该多好?
DeepSeek-OCR-WEBUI 正是为此而生。它是基于国产自研大模型的高性能OCR系统,不仅能识别中文文本,还能理解复杂版式、表格、公式,甚至支持语义级提示词控制识别行为。更关键的是——它开源、可本地部署、支持API调用,非常适合集成到企业内部系统中。
本文将带你深入解析它的核心功能机制,并手把手实现一个SpringBoot应用接入实战案例,最终完成从“拍照→上传→识别表格→结构化输出”的完整流程。
2. 核心功能深度解析
2.1 多模式识别:不只是“识字”,更是“理解内容”
传统OCR只能提取图像中的字符,但 DeepSeek-OCR-WEBUI 提供了多种prompt_type模式,让识别过程变得更智能、更有目的性。
| 模式 | 功能说明 | 典型应用场景 |
|---|---|---|
document | 转换为 Markdown 格式,保留标题、段落、列表等结构 | 合同扫描件数字化、论文归档 |
ocr | 提取所有可见文字,不做格式处理 | 快速获取图片中的全部文本 |
free | 纯文本提取,去格式化 | 简单信息抽取,如验证码识别 |
figure | 重点!解析图表、表格、数学公式 | 单据识别、报表分析、教学资料处理 |
describe | 生成图像描述,类似图文对话 | 图片语义理解、无障碍辅助 |
find | 查找特定关键词并标注位置 | 发票字段定位(如“金额”、“税号”) |
freeform | 自定义提示词,灵活控制识别逻辑 | 定制化业务需求 |
划重点:我们要识别采购单上的表格数据,所以必须使用
figure模式。这是实现结构化输出的关键!
2.2 基于提示词的精准控制(Prompt-Based OCR)
这可能是 DeepSeek-OCR 最惊艳的设计之一——你可以像和AI聊天一样告诉它:“我要识别这张图里的表格”。
比如:
{ "prompt_type": "figure", "custom_prompt": "请提取这张采购单中的商品明细表,包含序号、条码、名称、数量、单价、金额" }通过custom_prompt,你可以引导模型关注特定区域或字段,极大提升复杂文档的识别准确率。这种“语义驱动”的方式,远超传统规则匹配。
2.3 输出结构化HTML,便于二次解析
与大多数返回纯文本或JSON的OCR不同,DeepSeek-OCR 在figure模式下会返回标准的 HTML<table>结构:
<table> <tr><td>序号</td><td>条码</td><td>名称</td>...</tr> <tr><td>1</td><td>6949123352617</td><td>飞科PR-5261毛球修剪器</td>...</tr> </table>这个设计非常聪明:
- 对前端友好:可以直接渲染展示
- 对后端友好:可用成熟库(如 Jsoup)轻松解析为 JSON
- 保留原始布局:避免因空格、换行导致的数据错位
3. SpringBoot 接入全流程实战
现在我们进入实战环节。目标很明确:构建一个 Web 应用,用户上传一张含表格的单据图片,后端调用 DeepSeek-OCR 服务,返回结构化 JSON 数据。
整体架构如下:
前端 (Vue) → SpringBoot 后端 → DeepSeek-OCR-WebUI API → 返回HTML → 解析为JSON → 返回给前端3.1 准备工作:启动OCR服务
确保你已经成功部署了 DeepSeek-OCR-WebUI 镜像(建议使用 Docker Compose 方式):
cd ~/DeepSeek-OCR-WebUI docker compose up -d查看日志确认服务已启动:
docker logs -f deepseek-ocr-webui默认情况下,OCR 服务运行在http://localhost:8080,提供/ocr接口。
3.2 定义服务接口
我们先定义一个通用的 OCR 服务接口:
// src/main/java/com/example/ocr/service/OcrService.java public interface OcrService { /** * 识别表格图片并返回结构化数据 * * @param file 上传的包含表格的图片文件 * @return 包含表格数据的Map对象 */ Map<String, Object> recognitionTable(MultipartFile file); }3.3 实现OCR调用逻辑
创建具体实现类,使用RestTemplate调用远程OCR接口:
// src/main/java/com/example/ocr/service/impl/DeepSeekOcrService.java @Service @Slf4j public class DeepSeekOcrService implements OcrService { private static final String OCR_SERVICE_URL = "http://localhost:8080/ocr"; @Override public Map<String, Object> recognitionTable(MultipartFile file) { log.info("开始识别表格,文件名:{}", file.getOriginalFilename()); RestTemplate restTemplate = new RestTemplate(); try { // 构建 multipart 请求体 LinkedMultiValueMap<String, Object> requestBody = new LinkedMultiValueMap<>(); requestBody.add("file", new ByteArrayResource(file.getBytes()) { @Override public String getFilename() { return file.getOriginalFilename(); } }); requestBody.add("prompt_type", "figure"); // 关键:使用 figure 模式识别表格 requestBody.add("grounding", false); // 设置请求头 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA); // 发送请求 HttpEntity<LinkedMultiValueMap<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers); ResponseEntity<String> response = restTemplate.postForEntity(OCR_SERVICE_URL, requestEntity, String.class); if (response.getStatusCode().is2xxSuccessful()) { String htmlContent = response.getBody(); return parseHtmlTableToJSON(htmlContent); } else { log.error("OCR服务调用失败,状态码:{}", response.getStatusCode()); throw new RuntimeException("OCR识别失败"); } } catch (IOException e) { log.error("文件读取异常", e); throw new RuntimeException("文件处理失败", e); } } /** * 将HTML表格解析为JSON格式 */ private Map<String, Object> parseHtmlTableToJSON(String html) { Document doc = Jsoup.parse(html); Elements tables = doc.select("table"); if (tables.isEmpty()) { return Collections.singletonMap("data", Collections.emptyList()); } Element table = tables.first(); Elements rows = table.select("tr"); List<Map<String, String>> result = new ArrayList<>(); List<String> headers = null; for (int i = 0; i < rows.size(); i++) { Element row = rows.get(i); Elements cells = row.select("td,th"); List<String> cellValues = cells.stream() .map(Element::text) .map(String::trim) .collect(Collectors.toList()); if (i == 0) { // 第一行作为表头 headers = cellValues; } else { // 其余行为数据行 Map<String, String> rowData = new HashMap<>(); for (int j = 0; j < headers.size() && j < cellValues.size(); j++) { String key = headers.get(j); String value = cellValues.get(j); rowData.put(key, value); } result.add(rowData); } } Map<String, Object> resultMap = new HashMap<>(); resultMap.put("headers", headers); resultMap.put("data", result); return resultMap; } }注意事项:
- 添加依赖:
spring-web,jsoup- 使用
ByteArrayResource包装文件流prompt_type=figure是识别表格的核心参数
3.4 编写测试用例验证功能
在src/test/resources/下放一张测试图片voucher.jpg,编写单元测试:
// src/test/java/com/example/ocr/service/OcrServiceTest.java @SpringBootTest @Slf4j class OcrServiceTest { @Autowired private OcrService ocrService; @Test void testRecognitionTableSuccess() throws Exception { ClassPathResource resource = new ClassPathResource("voucher.jpg"); MockMultipartFile file = new MockMultipartFile( "file", "voucher.jpg", "image/jpeg", resource.getInputStream() ); Map<String, Object> result = ocrService.recognitionTable(file); log.info("OCR识别结果: \n{}", JSON.toJSONString(result, true)); Assertions.assertNotNull(result.get("data")); Assertions.assertTrue(((List<?>) result.get("data")).size() > 0); } }运行测试,你会看到类似以下输出:
{ "headers": ["序号","条码","名称","单位","订货数量","采购数量","赠送数量","采购单价","金额小计","备注"], "data": [ {"序号":"1","条码":"6949123352617","名称":"飞科PR-5261毛球修剪器",...}, {"序号":"2","条码":"6944296500049","名称":"天香炸酱面180g*50",...} ] }成功!表格已被正确解析为结构化 JSON。
3.5 暴露HTTP接口供前端调用
最后,添加 Controller 层接口:
// src/main/java/com/example/ocr/controller/OcrController.java @RestController @RequestMapping("/api/ocr") @Slf4j public class OcrController { @Autowired private OcrService ocrService; @PostMapping("/process") public Map<String, Object> processFile(@RequestParam("file") MultipartFile file) { return ocrService.recognitionTable(file); } }启动 SpringBoot 项目,默认监听8080端口(注意与OCR服务区分端口,可通过server.port=9090修改)。
4. 前后端联调与打包部署
4.1 前端页面集成(Vue)
项目自带ui目录,使用 Vue 实现上传界面:
<template> <div> <input type="file" @change="handleFileUpload" accept="image/*" /> <button @click="submit">识别表格</button> <table v-if="tableData.length"> <thead> <tr><th v-for="h in headers">{{ h }}</th></tr> </thead> <tbody> <tr v-for="row in tableData"><td v-for="cell in Object.values(row)">{{ cell }}</td></tr> </tbody> </table> </div> </template> <script> export default { data() { return { file: null, headers: [], tableData: [] }; }, methods: { handleFileUpload(e) { this.file = e.target.files[0]; }, async submit() { const formData = new FormData(); formData.append('file', this.file); const res = await fetch('http://localhost:9090/api/ocr/process', { method: 'POST', body: formData }); const result = await res.json(); this.headers = result.headers; this.tableData = result.data; } } } </script>构建前端资源:
npm install npm run build将dist目录下的静态文件复制到 SpringBoot 的src/main/resources/static下即可访问。
4.2 打包为Docker镜像统一部署
根目录创建Dockerfile:
FROM openjdk:21-jdk-slim WORKDIR /app COPY target/deepseek-web-ui.jar /app/app.jar EXPOSE 9090 ENTRYPOINT ["java", "-jar", "app.jar"]配套docker-compose.yml:
version: '3.8' services: ocr-backend: build: . ports: - "9090:9090" environment: - SERVER_PORT=9090 volumes: - ./logs:/app/logs一键启动:
docker compose up -d --build访问http://localhost:9090即可使用完整应用。
5. 总结
通过本文,我们完成了对DeepSeek-OCR-WEBUI的一次深度实践:
- 理解了其核心能力:多模式识别、提示词驱动、结构化输出
- 掌握了接入方法:SpringBoot + RestTemplate 调用 API
- 实现了表格识别闭环:图片上传 → OCR识别 → HTML解析 → JSON输出
- 完成了工程化落地:前后端分离、Docker容器化部署
这套方案特别适合用于:
- 企业报销单自动化处理
- 物流运单信息提取
- 教育领域试卷/作业数字化
- 档案馆老旧文档电子化
更重要的是,整个技术栈完全自主可控,无需依赖第三方云服务,保障数据安全。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。