DeepSeek OCR调研
- 内容介绍
- 文章标签
- 相关推荐
用户上传、拖拽图片:
用户上传图片/拖拽图片到指定位置(通过 或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做过一套类似的系统

