DeepSeek OCR调研

2026-04-29 10:002阅读0评论SEO资源
  • 内容介绍
  • 文章标签
  • 相关推荐
问题描述:

用户上传、拖拽图片:

用户上传图片/拖拽图片到指定位置(通过 或JavaScript 事件(如 ondrop)捕获文件),然后生成唯一的一个upload_id。前端将图片封装为multipart/form-data 格式,并且附加 upload_id 作为查询参数

Request URL:https://khang119966-deepseek-ocr-demo.hf.space/gradio_api/upload?upload_id=wbtrc1mgpde

Request Method:POST

Status Code:200 OK

同时触发上传进度监控,浏览器定时发送 GET 请求查询进度(项目中使用WebSocket实时监控),根据进度更新 UI(如显示进度条、百分比)

Request URL:https://khang119966-deepseek-ocr-demo.hf.space/gradio_api/upload_progress?upload_id=wbtrc1mgpde

Request Method:GET

Status Code:200 OK

上传图片:

1777070517004685×267 44.3 KB

选择任务类型:

可选图像分辨率和任务类型(项目中图像分辨率可能不需要,任务类型一般是转为markdown格式和json格式),点击处理图片进行OCR处理。

1777070540674297×184 16.2 KB

1777070533233293×253 12.4 KB

任务执行过程

如果处于高峰期可能会出现失败情况

Request URL: https://khang119966-deepseek-ocr-demo.hf.space/gradio_api/queue/join

Request Method: POST

Status Code: 200 OK

使用 queue/join 表示该应用启用了任务队列(用于处理长时间运行的 OCR 推理任务)。

前端传入负载:

{ "meta": { "\_type": "gradio.FileData" }, "mime_type": "image/png", "orig_name": "Pasted image 20260224140325.png", "path": "/tmp/gradio/7d982982cadb672224178077fafc1e62c9f287b8fc91a507d4af86001c6413ba/Pasted image 20260224140325.png", "size": 32892, "url": "https://khang119966-deepseek-ocr-demo.hf.space/gradio_api/file=/tmp/gradio/7d982982cadb672224178077fafc1e62c9f287b8fc91a507d4af86001c6413ba/Pasted image 20260224140325.png" }, "Large", // 图像分辨率大小选项 "📄 Convert to Markdown", // 表明用户选择了"转换为 Markdown"功能 null, null, 1, // fn_index: 指明调用的函数编号(对应后端逻辑) "aghdgjxbu4t", // session_hash: 会话唯一标识 8 // trigger_id: 触发此操作的前端子项 ID

后端响应结果:

{

“event_id”: “200ba9365b3e4bf3a939fa542dad9e30”

}

结果返回200,表示请求已成功加入任务队列,后续需通过WebSocket 或轮询接口监听该 event_id 的处理状态。

如果成功会出现解析之后的图片和解析之后的文档格式:

1777070698870663×256 66.9 KB

文本内容:

<|ref|>sub_title<|/ref|><|det|>[[48, 66, 580, 202]]<|/det|>
Welcome to nginx!

<|ref|>text<|/ref|><|det|>[[48, 300, 925, 460]]<|/det|>
If you see this page, the nginx web server is successfully installed and working. Further configuration is required.

<|ref|>text<|/ref|><|det|>[[48, 535, 848, 690]]<|/det|>
For online documentation and support please refer to nginx.org.
Commercial support is available at nginx.com.

<|ref|>text<|/ref|><|det|>[[52, 760, 386, 833]]<|/det|>
Thank you for using nginx.

其中ref标签用于目标检测,用于区分文本类型,比如sub_title,text

det标签是用于区分文检测区域,[[x1, y1, x2, y2]] 是 边界框坐标,表示文本在图像中的位置(左上角 x1,y1 到右下角 x2,y2)。

总结:

OCR 的流程主要为四个核心维度:数据输入、异步传输、排队推理、结果显示。

1777070818256376×227 4.24 KB

网友解答:
--【壹】--:

基于此流程,可以先做OCR前置任务处理DEMO系统

语言/框架:Java 17、Spring Boot 3.2、MyBatis-Plus、MySQL 8

文件处理:Apache Tika(文件类型识别)、PDFBox(PDF 转多页图片,只选取单页进行OCR)、zip4j + Commons Compress(ZIP/RAR 解压)

网络:OkHttp(文件下载,支持HTTP和HTTPS,但是不支持SFTP

工具:Hutool(辅助)、SLF4J(日志)

17770712843241007×145 9.12 KB

Demo主要实现OCR识别的前置功能,用户输入URL,通过Apache Tika进行文件类型识别,统一存储到临时目录(这里我放在项目的upload目录下,实际可放在阿里云OSS中),然后生成DocumentItem结构(包括任务id,创建时间等等)推送到调度队列中等待OCR引擎进行识别。支持立即执行OCR和异步等待执行OCR。

调度队列暂时未实现

该Demo主要实现了下载文件、识别类型、PDF 转图片、压缩包解压、生成任务明细、更新任务状态等功能。

17770713471431131×279 16.6 KB

其中比较有意思两个内容:

1、Apeach Tika实现文件类型检测

使用Tika的detect()方法检测文件的真实MIME类型,而不只是检测文件扩展名,这种方式可以防止通过伪造文件扩展名来绕过检测,检测到MIME类型后,将其转换为项目定义的文件类型枚举(比如jpg → JPG),如果MIME类型无法识别文件类型或实际路径不存在,返回UNKNOWN,则降级使用文件扩展名进行判断。

流程图:

1777071474182515×797 41.2 KB

使用 JUnit 5 来创建单元测试,来测试可能遇到的全部情况。

● JPEG 图片检测

@Test

void testDetectJpegImage() throws IOException {

// 创建JPEG测试文件

byte[] jpegHeader = {(byte) 0xFF, (byte) 0xD8, (byte) 0xFF, (byte) 0xE0};

Path jpegFile = tempDir.resolve(“D:\\Test_project\\OCR前置处理\\图片类型\\test.jpeg”);

Files.write(jpegFile, jpegHeader);

FileTypeEnum type = fileTypeDetector.detect(jpegFile.toFile());

assertEquals(FileTypeEnum.JPEG, type);

}

● PNG 图片检测

@Test void testDetectPngImage() throws IOException { // 创建PNG测试文件 byte\[\] pngHeader = {(byte) 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}; Path pngFile = tempDir.resolve("D:\\\\Test_project\\\\OCR前置处理\\\\图片类型\\\\test_png.png"); Files.write(pngFile, pngHeader); FileTypeEnum type = fileTypeDetector.detect(pngFile.toFile()); assertEquals(FileTypeEnum.PNG, type); }

● PDF 文件检测

@Test void testDetectPdfFile() throws IOException { // 创建PDF测试文件 byte\[\] pdfHeader = {0x25, 0x50, 0x44, 0x46, 0x2D, 0x31, 0x2E, 0x34}; // %PDF-1.4 Path pdfFile = tempDir.resolve("D:/edge_download/补卡申请流程操作指引.pdf"); Files.write(pdfFile, pdfHeader); FileTypeEnum type = fileTypeDetector.detect(pdfFile.toFile()); assertEquals(FileTypeEnum.PDF, type); }

● ZIP 压缩包检测

@Test void testDetectZipArchive() throws IOException { // 创建ZIP测试文件 byte\[\] zipHeader = {0x50, 0x4B, 0x03, 0x04}; Path zipFile = tempDir.resolve("D:/edge_download/sample-1.zip"); Files.write(zipFile, zipHeader); FileTypeEnum type = fileTypeDetector.detect(zipFile.toFile()); assertEquals(FileTypeEnum.ZIP, type); }

● 未知类型文件检测

2、PDFBox实现PDF转图片

该DEMO对于多页PDF来说,暂时实现保留第一页进行OCR识别,之后再考虑进行多页PDF识别

具体实现:

1. 首先创建File对象并检查PDF文件是否存在,如果文件不存在,抛出RuntimeException异常,文件存在则进入PDF文档加载阶段

2. 使用PDFBox的Loader加载PDF文档,使用try-with-resources确保文档资源自动释放,获取文档总页数并验证请求的页码是否有效

3. 创建PDFRenderer对象用于渲染PDF页面,从配置中获取PDF转换参数,使用renderImageWithDPI方法将指定页面渲染为BufferedImage

pageNum-1:PDFBox的页码从0开始计数

pdfConfig.getDpi():使用配置的DPI值,影响图片清晰度

ImageType.RGB:指定输出图片为RGB色彩模式

4. 提取原PDF文件名的基础部分,生成格式化的输出文件名,格式为:原文件名_page页码.扩展名。比如test.pdf ------> test.png。然后推送到OCR引擎。

实现的PDF转图片功能:

单页转换

指定页码转换

批量转换

全部页面转换

返回结果包含所有页面信息的PageInfo列表,包含页码、图片路径和尺寸信息

错误处理:对文件不存在、页码越界等异常情况进行了处理

1777071678987473×738 36.8 KB

单元测试:

@Test
void testConvertPageToImageWithValidPdf() throws IOException {
// 创建测试PDF文件
Path pdfPath = tempDir.resolve(“test.pdf”);
try (PDDocument document = new PDDocument()) {
document.addPage(new PDPage());
document.save(pdfPath.toFile());
}

// 模拟存储服务 Path tempImageFile = tempDir.resolve("temp_image.png"); Files.createFile(tempImageFile); when(fileStorageService.createTempFile(eq("pdf_"), eq(".png"))) .thenReturn(tempImageFile); when(fileStorageService.moveToStorage(any(), eq("test_page1.png"), eq("test-task"))) .thenReturn("storage/test_page1.png"); // 执行转换 String result = pdfConverter.convertPageToImage( pdfPath.toString(), 1, "test-task" ); // 验证结果 assertNotNull(result); assertEquals("storage/test_page1.png", result); // 验证存储服务被调用 verify(fileStorageService).createTempFile("pdf_", ".png"); verify(fileStorageService).moveToStorage(any(), eq("test_page1.png"), eq("test-task")); }

测试结果: 11:24:26.797 [main] INFO com.example.ocr.service.PdfConverter – PDF第1页转换完成: test.pdf → storage/test_page1.png, 尺寸: 1275x1649

对于压缩包处理,支持zip和rar格式,运行多层解压处理,将压缩包中的内容当作子任务进行OCR解析处理。

具体实现:

1. 创建ZIP文件对象并验证文件是否存在,创建临时解压目录,使用任务ID和随机UUID确保目录唯一性

2. 使用ZipFile打开ZIP文件,检查ZIP是否加密,如果加密则从配置中获取密码,然后获取ZIP内所有文件头信息并验证文件数量是否超过限制

3. 遍历ZIP中的每个文件条目,对每个文件条目进行安全检查:验证文件名安全性,防止Zip Slip路径穿越攻击,清理文件名中的非法字符,解压单个文件到临时目录

4. 检查解压后文件大小是否超过限制,使用FileTypeDetector检测文件类型,判断文件类型是否为支持的格式,对于压缩包中的文件创建子任务进行OCR前置处理,然后推入OCR引擎。


--【贰】--: yymanw:

暂时还没有压测哦,个人用的话应该是够用的。


--【叁】--:

有压测过吗?我之前用paddleocr做过一套类似的系统

问题描述:

用户上传、拖拽图片:

用户上传图片/拖拽图片到指定位置(通过 或JavaScript 事件(如 ondrop)捕获文件),然后生成唯一的一个upload_id。前端将图片封装为multipart/form-data 格式,并且附加 upload_id 作为查询参数

Request URL:https://khang119966-deepseek-ocr-demo.hf.space/gradio_api/upload?upload_id=wbtrc1mgpde

Request Method:POST

Status Code:200 OK

同时触发上传进度监控,浏览器定时发送 GET 请求查询进度(项目中使用WebSocket实时监控),根据进度更新 UI(如显示进度条、百分比)

Request URL:https://khang119966-deepseek-ocr-demo.hf.space/gradio_api/upload_progress?upload_id=wbtrc1mgpde

Request Method:GET

Status Code:200 OK

上传图片:

1777070517004685×267 44.3 KB

选择任务类型:

可选图像分辨率和任务类型(项目中图像分辨率可能不需要,任务类型一般是转为markdown格式和json格式),点击处理图片进行OCR处理。

1777070540674297×184 16.2 KB

1777070533233293×253 12.4 KB

任务执行过程

如果处于高峰期可能会出现失败情况

Request URL: https://khang119966-deepseek-ocr-demo.hf.space/gradio_api/queue/join

Request Method: POST

Status Code: 200 OK

使用 queue/join 表示该应用启用了任务队列(用于处理长时间运行的 OCR 推理任务)。

前端传入负载:

{ "meta": { "\_type": "gradio.FileData" }, "mime_type": "image/png", "orig_name": "Pasted image 20260224140325.png", "path": "/tmp/gradio/7d982982cadb672224178077fafc1e62c9f287b8fc91a507d4af86001c6413ba/Pasted image 20260224140325.png", "size": 32892, "url": "https://khang119966-deepseek-ocr-demo.hf.space/gradio_api/file=/tmp/gradio/7d982982cadb672224178077fafc1e62c9f287b8fc91a507d4af86001c6413ba/Pasted image 20260224140325.png" }, "Large", // 图像分辨率大小选项 "📄 Convert to Markdown", // 表明用户选择了"转换为 Markdown"功能 null, null, 1, // fn_index: 指明调用的函数编号(对应后端逻辑) "aghdgjxbu4t", // session_hash: 会话唯一标识 8 // trigger_id: 触发此操作的前端子项 ID

后端响应结果:

{

“event_id”: “200ba9365b3e4bf3a939fa542dad9e30”

}

结果返回200,表示请求已成功加入任务队列,后续需通过WebSocket 或轮询接口监听该 event_id 的处理状态。

如果成功会出现解析之后的图片和解析之后的文档格式:

1777070698870663×256 66.9 KB

文本内容:

<|ref|>sub_title<|/ref|><|det|>[[48, 66, 580, 202]]<|/det|>
Welcome to nginx!

<|ref|>text<|/ref|><|det|>[[48, 300, 925, 460]]<|/det|>
If you see this page, the nginx web server is successfully installed and working. Further configuration is required.

<|ref|>text<|/ref|><|det|>[[48, 535, 848, 690]]<|/det|>
For online documentation and support please refer to nginx.org.
Commercial support is available at nginx.com.

<|ref|>text<|/ref|><|det|>[[52, 760, 386, 833]]<|/det|>
Thank you for using nginx.

其中ref标签用于目标检测,用于区分文本类型,比如sub_title,text

det标签是用于区分文检测区域,[[x1, y1, x2, y2]] 是 边界框坐标,表示文本在图像中的位置(左上角 x1,y1 到右下角 x2,y2)。

总结:

OCR 的流程主要为四个核心维度:数据输入、异步传输、排队推理、结果显示。

1777070818256376×227 4.24 KB

网友解答:
--【壹】--:

基于此流程,可以先做OCR前置任务处理DEMO系统

语言/框架:Java 17、Spring Boot 3.2、MyBatis-Plus、MySQL 8

文件处理:Apache Tika(文件类型识别)、PDFBox(PDF 转多页图片,只选取单页进行OCR)、zip4j + Commons Compress(ZIP/RAR 解压)

网络:OkHttp(文件下载,支持HTTP和HTTPS,但是不支持SFTP

工具:Hutool(辅助)、SLF4J(日志)

17770712843241007×145 9.12 KB

Demo主要实现OCR识别的前置功能,用户输入URL,通过Apache Tika进行文件类型识别,统一存储到临时目录(这里我放在项目的upload目录下,实际可放在阿里云OSS中),然后生成DocumentItem结构(包括任务id,创建时间等等)推送到调度队列中等待OCR引擎进行识别。支持立即执行OCR和异步等待执行OCR。

调度队列暂时未实现

该Demo主要实现了下载文件、识别类型、PDF 转图片、压缩包解压、生成任务明细、更新任务状态等功能。

17770713471431131×279 16.6 KB

其中比较有意思两个内容:

1、Apeach Tika实现文件类型检测

使用Tika的detect()方法检测文件的真实MIME类型,而不只是检测文件扩展名,这种方式可以防止通过伪造文件扩展名来绕过检测,检测到MIME类型后,将其转换为项目定义的文件类型枚举(比如jpg → JPG),如果MIME类型无法识别文件类型或实际路径不存在,返回UNKNOWN,则降级使用文件扩展名进行判断。

流程图:

1777071474182515×797 41.2 KB

使用 JUnit 5 来创建单元测试,来测试可能遇到的全部情况。

● JPEG 图片检测

@Test

void testDetectJpegImage() throws IOException {

// 创建JPEG测试文件

byte[] jpegHeader = {(byte) 0xFF, (byte) 0xD8, (byte) 0xFF, (byte) 0xE0};

Path jpegFile = tempDir.resolve(“D:\\Test_project\\OCR前置处理\\图片类型\\test.jpeg”);

Files.write(jpegFile, jpegHeader);

FileTypeEnum type = fileTypeDetector.detect(jpegFile.toFile());

assertEquals(FileTypeEnum.JPEG, type);

}

● PNG 图片检测

@Test void testDetectPngImage() throws IOException { // 创建PNG测试文件 byte\[\] pngHeader = {(byte) 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}; Path pngFile = tempDir.resolve("D:\\\\Test_project\\\\OCR前置处理\\\\图片类型\\\\test_png.png"); Files.write(pngFile, pngHeader); FileTypeEnum type = fileTypeDetector.detect(pngFile.toFile()); assertEquals(FileTypeEnum.PNG, type); }

● PDF 文件检测

@Test void testDetectPdfFile() throws IOException { // 创建PDF测试文件 byte\[\] pdfHeader = {0x25, 0x50, 0x44, 0x46, 0x2D, 0x31, 0x2E, 0x34}; // %PDF-1.4 Path pdfFile = tempDir.resolve("D:/edge_download/补卡申请流程操作指引.pdf"); Files.write(pdfFile, pdfHeader); FileTypeEnum type = fileTypeDetector.detect(pdfFile.toFile()); assertEquals(FileTypeEnum.PDF, type); }

● ZIP 压缩包检测

@Test void testDetectZipArchive() throws IOException { // 创建ZIP测试文件 byte\[\] zipHeader = {0x50, 0x4B, 0x03, 0x04}; Path zipFile = tempDir.resolve("D:/edge_download/sample-1.zip"); Files.write(zipFile, zipHeader); FileTypeEnum type = fileTypeDetector.detect(zipFile.toFile()); assertEquals(FileTypeEnum.ZIP, type); }

● 未知类型文件检测

2、PDFBox实现PDF转图片

该DEMO对于多页PDF来说,暂时实现保留第一页进行OCR识别,之后再考虑进行多页PDF识别

具体实现:

1. 首先创建File对象并检查PDF文件是否存在,如果文件不存在,抛出RuntimeException异常,文件存在则进入PDF文档加载阶段

2. 使用PDFBox的Loader加载PDF文档,使用try-with-resources确保文档资源自动释放,获取文档总页数并验证请求的页码是否有效

3. 创建PDFRenderer对象用于渲染PDF页面,从配置中获取PDF转换参数,使用renderImageWithDPI方法将指定页面渲染为BufferedImage

pageNum-1:PDFBox的页码从0开始计数

pdfConfig.getDpi():使用配置的DPI值,影响图片清晰度

ImageType.RGB:指定输出图片为RGB色彩模式

4. 提取原PDF文件名的基础部分,生成格式化的输出文件名,格式为:原文件名_page页码.扩展名。比如test.pdf ------> test.png。然后推送到OCR引擎。

实现的PDF转图片功能:

单页转换

指定页码转换

批量转换

全部页面转换

返回结果包含所有页面信息的PageInfo列表,包含页码、图片路径和尺寸信息

错误处理:对文件不存在、页码越界等异常情况进行了处理

1777071678987473×738 36.8 KB

单元测试:

@Test
void testConvertPageToImageWithValidPdf() throws IOException {
// 创建测试PDF文件
Path pdfPath = tempDir.resolve(“test.pdf”);
try (PDDocument document = new PDDocument()) {
document.addPage(new PDPage());
document.save(pdfPath.toFile());
}

// 模拟存储服务 Path tempImageFile = tempDir.resolve("temp_image.png"); Files.createFile(tempImageFile); when(fileStorageService.createTempFile(eq("pdf_"), eq(".png"))) .thenReturn(tempImageFile); when(fileStorageService.moveToStorage(any(), eq("test_page1.png"), eq("test-task"))) .thenReturn("storage/test_page1.png"); // 执行转换 String result = pdfConverter.convertPageToImage( pdfPath.toString(), 1, "test-task" ); // 验证结果 assertNotNull(result); assertEquals("storage/test_page1.png", result); // 验证存储服务被调用 verify(fileStorageService).createTempFile("pdf_", ".png"); verify(fileStorageService).moveToStorage(any(), eq("test_page1.png"), eq("test-task")); }

测试结果: 11:24:26.797 [main] INFO com.example.ocr.service.PdfConverter – PDF第1页转换完成: test.pdf → storage/test_page1.png, 尺寸: 1275x1649

对于压缩包处理,支持zip和rar格式,运行多层解压处理,将压缩包中的内容当作子任务进行OCR解析处理。

具体实现:

1. 创建ZIP文件对象并验证文件是否存在,创建临时解压目录,使用任务ID和随机UUID确保目录唯一性

2. 使用ZipFile打开ZIP文件,检查ZIP是否加密,如果加密则从配置中获取密码,然后获取ZIP内所有文件头信息并验证文件数量是否超过限制

3. 遍历ZIP中的每个文件条目,对每个文件条目进行安全检查:验证文件名安全性,防止Zip Slip路径穿越攻击,清理文件名中的非法字符,解压单个文件到临时目录

4. 检查解压后文件大小是否超过限制,使用FileTypeDetector检测文件类型,判断文件类型是否为支持的格式,对于压缩包中的文件创建子任务进行OCR前置处理,然后推入OCR引擎。


--【贰】--: yymanw:

暂时还没有压测哦,个人用的话应该是够用的。


--【叁】--:

有压测过吗?我之前用paddleocr做过一套类似的系统