从图片到JSON:利用DeepSeek-OCR-WEBUI实现SpringBoot表格数据自动提取

从图片到JSON:利用DeepSeek-OCR-WEBUI实现SpringBoot表格数据自动提取

在企业级应用开发中,纸质单据、发票、采购表等结构化文档的数字化处理一直是一个高频且繁琐的任务。传统的人工录入方式不仅效率低,还容易出错。随着AI技术的发展,尤其是OCR(光学字符识别)能力的显著提升,我们已经可以借助大模型实现高精度的表格内容自动提取。

本文将带你使用DeepSeek-OCR-WEBUI这一基于国产自研大模型的高性能OCR系统,结合SpringBoot后端服务,完成一个完整的“图片→HTML表格→JSON结构化数据”的自动化流程。最终目标是:上传一张包含表格的图片,后端调用OCR接口解析内容,并以标准JSON格式返回给前端,供后续业务系统直接消费。

整个过程无需手动编写复杂的图像处理逻辑,也不需要训练模型,只需合理调用API并做好数据转换即可落地。


1. 环境准备与OCR服务部署

要实现表格数据提取,首先必须确保DeepSeek-OCR-WEBUI已正确部署并提供HTTP API服务。该镜像封装了DeepSeek开源的OCR大模型,支持多语言、复杂背景下的文本识别,尤其擅长中文场景下的表格和票据解析。

1.1 部署OCR后端服务

进入项目目录并启动Docker容器:

cd ~/DeepSeek-OCR-WebUI docker compose up -d

启动完成后,查看日志确认服务正常运行:

docker logs -f deepseek-ocr-webui

当看到类似Uvicorn running on http://0.0.0.0:8080的输出时,说明Web服务已就绪。

1.2 OCR核心接口说明

DeepSeek-OCR-WEBUI提供了一个/ocr接口,用于接收图片并返回识别结果。其定义位于web_service.py文件中:

@app.post("/ocr") async def ocr_endpoint( file: UploadFile = File(...), prompt_type: str = Form("document"), find_term: str = Form(""), custom_prompt: str = Form(""), grounding: bool = Form(False) ):

其中关键参数如下:

参数名可选值说明
prompt_typedocument,ocr,free,figure,describe,find,freeform指定识别模式
file图片文件(JPEG/PNG等)待识别的图像

对于表格识别任务,我们必须选择prompt_type=figure,因为该模式专为图表、公式、表格结构设计,能保留原始布局信息,并输出HTML格式的<table>标签。

提示:如果你希望扩展功能(如添加新参数或修改返回格式),可直接修改web_service.py,但修改后需重新构建Docker镜像才能生效。


2. SpringBoot项目集成OCR客户端

接下来,在SpringBoot应用中接入OCR服务,实现“图片上传 → 调用OCR → 解析HTML → 返回JSON”的完整链路。

2.1 定义OCR服务接口

创建OcrService接口,声明表格识别方法:

// src/main/java/com/kaifamiao/dswebui/service/OcrService.java public interface OcrService { /** * 识别表格图片并返回结构化数据 * * @param file 上传的包含表格的图片文件 * @return 包含表格数据的Map对象,将以JSON格式返回给前端 */ Map<String, Object> recognitionTable(MultipartFile file); }

2.2 实现OCR调用逻辑

使用RestTemplate发送POST请求到OCR服务,并处理响应结果。

// src/main/java/com/kaifamiao/dswebui/service/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()); try { RestTemplate restTemplate = new RestTemplate(); // 准备文件资源 ByteArrayResource resource = new ByteArrayResource(file.getBytes()) { @Override public String getFilename() { return file.getOriginalFilename(); } }; // 构建请求参数(multipart/form-data) MultiValueMap<String, Object> body = new LinkedMultiValueMap<>(); body.add("file", resource); body.add("prompt_type", "figure"); // 关键!启用表格识别模式 // 设置请求头 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA); // 创建请求实体 HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, 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 (Exception e) { log.error("OCR识别过程中发生异常", e); throw new RuntimeException("文件处理失败", e); } } /** * 将HTML表格解析为JSON格式 * * @param html 包含<table>标签的HTML字符串 * @return 转换后的JSON数据(List<Map<String, String>> 形式) */ private Map<String, Object> parseHtmlTableToJSON(String html) { Document doc = Jsoup.parse(html); Element table = doc.selectFirst("table"); List<Map<String, String>> rows = new ArrayList<>(); if (table != null) { Elements trList = table.select("tr"); boolean isFirstRow = true; List<String> headers = new ArrayList<>(); for (Element tr : trList) { Elements tds = tr.select("td"); Map<String, String> row = new HashMap<>(); for (int i = 0; i < tds.size(); i++) { String text = tds.get(i).text().trim(); if (isFirstRow) { headers.add("col_" + i); // 默认列名 if (!text.isEmpty()) headers.set(i, text); // 使用首行为表头 } else { String key = i < headers.size() ? headers.get(i) : ("col_" + i); row.put(key, text); } } if (!isFirstRow) { rows.add(row); } isFirstRow = false; } } Map<String, Object> result = new HashMap<>(); result.put("data", rows); result.put("total", rows.size()); return result; } }
核心要点说明:
  • 使用RestTemplate构造 multipart 请求上传图片。
  • 必须设置prompt_type=figure才能触发表格识别逻辑。
  • 响应体为纯HTML<table>结构,使用Jsoup解析DOM树。
  • 自动将第一行作为表头字段名,其余每行转为一个Map<String, String>对象。
  • 最终返回结构清晰的JSON:包含data数组和总数统计。

3. 控制器层暴露REST接口

创建控制器类,对外提供HTTP接口供前端调用。

// src/main/java/com/kaifamiao/dswebui/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) { if (file.isEmpty()) { throw new IllegalArgumentException("上传文件不能为空"); } Map<String, Object> result = ocrService.recognitionTable(file); log.info("OCR识别结果: {}", JSON.toJSONString(result)); return result; } }

该接口接受名为file的图片上传请求,调用服务层完成识别后,直接返回JSON结构化数据。

例如,输入一张采购单截图:

返回结果示例:

{ "data": [ { "序号": "1", "条码": "6949123352617", "名称": "飞科PR-5261毛球修剪器", "单位": "个", "订货数量": "0.00", "采购数量": "1.00", "赠送数量": "0.00", "采购单价": "38.5000", "金额小计": "38.5000", "备注": "" }, { "序号": "2", "条码": "6944296500049", "名称": "天香炸酱面180g*50", "单位": "个", "订货数量": "0.00", "采购数量": "1.00", "赠送数量": "0.00", "采购单价": "0.0000", "金额小计": "0.0000", "备注": "" } ], "total": 2 }

4. 编写单元测试验证功能

为了确保服务稳定性,编写JUnit测试用例验证全流程是否通畅。

// src/test/java/com/kaifamiao/dswebui/service/OcrServiceTest.java @SpringBootTest @Slf4j public 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识别结果: {}", JSON.toJSONString(result)); Assertions.assertNotNull(result); Assertions.assertTrue(((Integer) result.get("total")) > 0); } }

运行测试,观察日志输出,确认能成功解析出表格数据。


5. 前端页面集成(Vue)

项目附带了一个基于Vue的简单UI界面,用于演示图片上传与结果显示。

5.1 页面效果展示

用户点击“选择文件”上传图片,点击“开始识别”后发送请求至/api/ocr/process,后台返回JSON数据并在页面渲染成表格。

5.2 构建与部署

安装Node.js(建议v20+),执行构建命令:

npm i npm run build

生成的dist目录需复制到SpringBoot项目的静态资源路径下(如src/main/resources/static),以便内嵌Tomcat直接提供前端页面访问。


6. 打包与Docker部署

完成前后端开发后,进行整体打包并通过Docker部署。

6.1 Maven打包后端应用

mvn clean package -DskipTests

生成jar包:target/deepseek-web-ui-1.0.0.jar

6.2 编写Dockerfile

FROM openjdk:21-jdk-slim WORKDIR /app COPY target/deepseek-web-ui-1.0.0.jar /app/deepseek-web-ui.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "deepseek-web-ui.jar"]

6.3 配置docker-compose.yml

version: '3.8' services: ocr-app: build: . ports: - "8080:8080" environment: - SERVER_PORT=8080 volumes: - ./logs:/app/logs

6.4 启动服务

docker compose up -d --build

访问http://localhost:8080即可打开前端页面,开始使用表格识别功能。


7. 总结

通过本文的实践,我们完成了从“图片到JSON”的全自动表格数据提取系统搭建,核心步骤包括:

  1. 部署DeepSeek-OCR-WEBUI服务,利用其强大的表格识别能力;
  2. SpringBoot集成OCR客户端,通过HTTP调用获取HTML格式表格;
  3. 使用Jsoup解析HTML,将其转化为结构化的JSON数据;
  4. 前后端联调与Docker化部署,实现一键启动、开箱即用。

这套方案特别适用于以下场景:

  • 财务报销单自动化录入
  • 仓库入库单快速登记
  • 教育领域成绩单数字化
  • 物流运单信息抓取

相比传统OCR工具,DeepSeek-OCR-WEBUI的优势在于:

  • 中文识别准确率高
  • 支持复杂表格结构还原
  • 易于集成、无需训练
  • 开源可控、可本地部署

未来还可以在此基础上增加人工校验界面、批量处理队列、错误重试机制等功能,进一步提升系统的实用性与健壮性。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1198600.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

为何DeepSeek-R1推理更稳定?基于强化学习的数据蒸馏解析

为何DeepSeek-R1推理更稳定&#xff1f;基于强化学习的数据蒸馏解析 1. 模型背景与核心优势 你可能已经注意到&#xff0c;最近一款名为 DeepSeek-R1-Distill-Qwen-1.5B 的模型在多个推理任务中表现异常稳健——无论是解数学题、写代码&#xff0c;还是处理复杂逻辑链&#x…

Qwen1.5-0.5B训练后微调?原生Transformers接入指南

Qwen1.5-0.5B训练后微调&#xff1f;原生Transformers接入指南 1. 背景与目标&#xff1a;为什么用一个模型做两件事&#xff1f; 你有没有遇到过这种情况&#xff1a;想做个情感分析功能&#xff0c;得加载BERT&#xff1b;再加个对话机器人&#xff0c;又得上LLM。结果显存…

Sambert语音服务日志分析:错误排查与性能监控

Sambert语音服务日志分析&#xff1a;错误排查与性能监控 1. 引言&#xff1a;为什么日志分析是语音服务稳定运行的关键 你有没有遇到过这种情况&#xff1a;用户反馈语音合成突然变慢&#xff0c;甚至返回空白音频&#xff0c;而服务进程却显示正常运行&#xff1f;或者在高…

测试镜像优化建议:小而美,适合入门和测试场景

测试镜像优化建议&#xff1a;小而美&#xff0c;适合入门和测试场景 1. 引言&#xff1a;为什么需要轻量化的测试镜像&#xff1f; 在开发和测试过程中&#xff0c;我们常常需要快速验证某个功能、服务或脚本的可行性。这时候&#xff0c;一个启动快、结构简单、易于调试的测…

GPT-OSS-20B推理延迟优化:批处理参数调整案例

GPT-OSS-20B推理延迟优化&#xff1a;批处理参数调整案例 1. 背景与目标&#xff1a;为什么需要优化GPT-OSS-20B的推理延迟&#xff1f; 你有没有遇到过这样的情况&#xff1a;模型部署好了&#xff0c;界面也打开了&#xff0c;但每次提问都要等好几秒才出结果&#xff1f;尤…

Qwen3-Embedding-4B启动报错?环境配置问题解决案例

Qwen3-Embedding-4B启动报错&#xff1f;环境配置问题解决案例 在部署大模型服务时&#xff0c;即使使用了官方推荐的框架和镜像&#xff0c;也常常会遇到意想不到的启动问题。本文聚焦一个真实场景&#xff1a;基于SGlang部署Qwen3-Embedding-4B向量服务时出现启动失败的情况…

PyTorch-2.x Universal镜像实测:科学计算库调用指南

PyTorch-2.x Universal镜像实测&#xff1a;科学计算库调用指南 1. 镜像简介与核心价值 你是不是也经历过这样的场景&#xff1a;刚搭好一个深度学习环境&#xff0c;结果跑代码时发现少装了pandas&#xff0c;画图又缺了matplotlib&#xff0c;调试半天才发现jupyter内核没配…

MinerU环境部署全攻略:Conda+CUDA+Python3.10参数详解

MinerU环境部署全攻略&#xff1a;CondaCUDAPython3.10参数详解 1. 引言&#xff1a;为什么选择这款MinerU镜像&#xff1f; 你是否还在为PDF文档中复杂的排版头疼&#xff1f;多栏文字、嵌套表格、数学公式、插图混杂在一起&#xff0c;手动提取不仅耗时还容易出错。现在&am…

浅谈CPU中的SIMD

目录 1.简介 2.如何检查CPU是否支持SIMD 2.1.命令行快速查询&#xff08;手动检查&#xff09; 2.2.C 代码动态检测&#xff08;程序运行时判断&#xff09; 2.3.各自系统判断 3.C 中利用 SIMD 的方式 3.1.编译器自动向量化 3.2.SIMD Intrinsics 3.3.C 标准并行算法 …

Qwen3-4B推理性能瓶颈?GPU算力深度调优部署实战教程

Qwen3-4B推理性能瓶颈&#xff1f;GPU算力深度调优部署实战教程 1. 为什么你的Qwen3-4B跑不满算力&#xff1f; 你是不是也遇到过这种情况&#xff1a;明明用的是RTX 4090D&#xff0c;显存带宽拉满&#xff0c;CUDA核心数也不少&#xff0c;但部署Qwen3-4B-Instruct-2507时&…

用Qwen-Image-Layered处理老照片,逐层修复更精细

用Qwen-Image-Layered处理老照片&#xff0c;逐层修复更精细 你有没有这样的经历&#xff1a;翻出一张泛黄的老照片&#xff0c;想修复它&#xff0c;却发现划痕、褪色、模糊交织在一起&#xff0c;根本无从下手&#xff1f;传统修图工具要么整体调整&#xff0c;失真严重&…

OCR技术新突破|DeepSeek-OCR-WEBUI多场景应用解析

OCR技术新突破&#xff5c;DeepSeek-OCR-WEBUI多场景应用解析 1. OCR技术的现实挑战与DeepSeek-OCR-WEBUI的破局之道 你有没有遇到过这样的情况&#xff1a;一堆纸质发票、合同、身份证需要录入系统&#xff0c;手动打字不仅慢&#xff0c;还容易出错&#xff1f;或者扫描的P…

NewBie-image-Exp0.1 vs LlamaGen对比:开源动漫大模型生成质量与效率评测

NewBie-image-Exp0.1 vs LlamaGen对比&#xff1a;开源动漫大模型生成质量与效率评测 1. 引言&#xff1a;为什么我们需要对比这两款模型&#xff1f; 如果你正在寻找一款能稳定生成高质量动漫图像的开源模型&#xff0c;那么你很可能已经听说过 NewBie-image-Exp0.1 和 Llam…

Z-Image-Turbo部署教程:SSH隧道映射7860端口详细步骤

Z-Image-Turbo部署教程&#xff1a;SSH隧道映射7860端口详细步骤 Z-Image-Turbo是阿里巴巴通义实验室开源的高效AI图像生成模型&#xff0c;作为Z-Image的蒸馏版本&#xff0c;它在保持高质量输出的同时大幅提升了推理速度。该模型仅需8步即可生成照片级真实感图像&#xff0c…

AI中小企业落地指南:Qwen3-4B开源部署一文详解

AI中小企业落地指南&#xff1a;Qwen3-4B开源部署一文详解 1. Qwen3-4B-Instruct-2507 是什么&#xff1f;中小企业为何要关注它&#xff1f; 你可能已经听说过很多大模型&#xff0c;但真正适合中小企业低成本、高效率落地的并不多。今天我们要聊的 Qwen3-4B-Instruct-2507&…

下一代代码模型趋势:IQuest-Coder-V1训练范式解析

下一代代码模型趋势&#xff1a;IQuest-Coder-V1训练范式解析 1. 引言&#xff1a;当代码不再静态&#xff0c;智能如何演进&#xff1f; 你有没有想过&#xff0c;为什么大多数代码大模型在面对真实项目迭代时总是“力不从心”&#xff1f;它们能写函数、补全代码&#xff0…

YOLOv9镜像避坑指南:常见问题与解决方案

YOLOv9镜像避坑指南&#xff1a;常见问题与解决方案 YOLOv9发布后&#xff0c;不少开发者在首次使用官方训练与推理镜像时遭遇了“能启动、跑不通、训不出、结果错”的典型困境。这不是模型能力的问题&#xff0c;而是环境、路径、参数和认知偏差共同导致的工程断点。本文不讲…

Sambert会议纪要生成:语音转录+摘要全流程实战

Sambert会议纪要生成&#xff1a;语音转录摘要全流程实战 在日常工作中&#xff0c;会议记录是一项繁琐但必不可少的任务。传统方式依赖人工听写和整理&#xff0c;耗时耗力且容易遗漏关键信息。随着语音识别与自然语言处理技术的发展&#xff0c;我们完全可以借助AI实现从语音…

Sambert部署需要多少存储?10GB空间规划建议指南

Sambert部署需要多少存储&#xff1f;10GB空间规划建议指南 1. Sambert语音合成镜像简介与核心价值 你是不是也遇到过这种情况&#xff1a;想快速搭建一个中文语音合成服务&#xff0c;结果卡在环境依赖、模型下载和路径配置上&#xff0c;折腾半天还跑不起来&#xff1f;尤其…

Qwen-Image-2512实测报告:语义与外观双重编辑能力解析

Qwen-Image-2512实测报告&#xff1a;语义与外观双重编辑能力解析 1. 引言&#xff1a;为什么这次升级值得关注&#xff1f; 如果你经常处理图片编辑任务&#xff0c;一定遇到过这样的难题&#xff1a;想改一张宣传图上的文字&#xff0c;结果字体、颜色对不上&#xff1b;想…