|
|
@@ -2,6 +2,8 @@ package com.lingyue.parse.service;
|
|
|
|
|
|
import com.lingyue.common.exception.ServiceException;
|
|
|
import com.lingyue.parse.config.PaddleOcrProperties;
|
|
|
+import com.lingyue.parse.util.ErrorCategory;
|
|
|
+import com.lingyue.parse.util.RetryUtil;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.core.io.ByteArrayResource;
|
|
|
@@ -13,6 +15,7 @@ import org.springframework.http.ResponseEntity;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.util.LinkedMultiValueMap;
|
|
|
import org.springframework.util.MultiValueMap;
|
|
|
+import org.springframework.web.client.RestClientException;
|
|
|
import org.springframework.web.client.RestTemplate;
|
|
|
|
|
|
import java.io.IOException;
|
|
|
@@ -31,6 +34,7 @@ public class PaddleOcrClient {
|
|
|
|
|
|
/**
|
|
|
* 对本地文件执行 OCR 识别,返回原始 JSON 字符串
|
|
|
+ * 带重试机制和错误分类
|
|
|
*
|
|
|
* @param filePath 待识别的文件路径
|
|
|
* @return OCR 结果 JSON 字符串
|
|
|
@@ -41,31 +45,54 @@ public class PaddleOcrClient {
|
|
|
throw new ServiceException("待识别文件不存在: " + filePath);
|
|
|
}
|
|
|
|
|
|
- try {
|
|
|
- byte[] bytes = Files.readAllBytes(path);
|
|
|
-
|
|
|
- // 构造 multipart/form-data 请求体,字段名为 file(可根据实际服务调整)
|
|
|
- ByteArrayResource fileResource = new ByteArrayResource(bytes) {
|
|
|
- @Override
|
|
|
- public String getFilename() {
|
|
|
- return path.getFileName().toString();
|
|
|
+ // 使用重试机制调用OCR服务
|
|
|
+ return RetryUtil.executeWithRetry(() -> {
|
|
|
+ try {
|
|
|
+ return doOcrFile(path, filePath);
|
|
|
+ } catch (Exception e) {
|
|
|
+ ErrorCategory category = ErrorCategory.categorize(e);
|
|
|
+ log.error("OCR调用失败 [{}]: {}", category.getDescription(), e.getMessage());
|
|
|
+
|
|
|
+ // 如果错误不可重试,直接抛出
|
|
|
+ if (!category.isRetryable()) {
|
|
|
+ throw new ServiceException("OCR调用失败: " + e.getMessage(), e);
|
|
|
}
|
|
|
- };
|
|
|
+
|
|
|
+ // 可重试的错误,抛出异常以便重试
|
|
|
+ throw new RuntimeException("OCR调用失败: " + e.getMessage(), e);
|
|
|
+ }
|
|
|
+ }, "OCR识别", 3, 1000);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 执行OCR调用的实际逻辑
|
|
|
+ */
|
|
|
+ private String doOcrFile(Path path, String filePath) throws IOException {
|
|
|
+ byte[] bytes = Files.readAllBytes(path);
|
|
|
+
|
|
|
+ // 构造 multipart/form-data 请求体,字段名为 file(可根据实际服务调整)
|
|
|
+ ByteArrayResource fileResource = new ByteArrayResource(bytes) {
|
|
|
+ @Override
|
|
|
+ public String getFilename() {
|
|
|
+ return path.getFileName().toString();
|
|
|
+ }
|
|
|
+ };
|
|
|
|
|
|
- MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
|
|
- body.add("file", fileResource);
|
|
|
+ MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
|
|
+ body.add("file", fileResource);
|
|
|
|
|
|
- HttpHeaders headers = new HttpHeaders();
|
|
|
- headers.setContentType(MediaType.MULTIPART_FORM_DATA);
|
|
|
+ HttpHeaders headers = new HttpHeaders();
|
|
|
+ headers.setContentType(MediaType.MULTIPART_FORM_DATA);
|
|
|
|
|
|
- HttpEntity<MultiValueMap<String, Object>> requestEntity =
|
|
|
- new HttpEntity<>(body, headers);
|
|
|
+ HttpEntity<MultiValueMap<String, Object>> requestEntity =
|
|
|
+ new HttpEntity<>(body, headers);
|
|
|
|
|
|
- RestTemplate restTemplate = new RestTemplate();
|
|
|
- String url = ocrProperties.getServerUrl();
|
|
|
+ RestTemplate restTemplate = new RestTemplate();
|
|
|
+ String url = ocrProperties.getServerUrl();
|
|
|
|
|
|
- log.info("调用 PaddleOCR 服务, url={}, file={}", url, filePath);
|
|
|
+ log.info("调用 PaddleOCR 服务, url={}, file={}", url, filePath);
|
|
|
|
|
|
+ try {
|
|
|
ResponseEntity<String> response = restTemplate.exchange(
|
|
|
url,
|
|
|
HttpMethod.POST,
|
|
|
@@ -80,12 +107,10 @@ public class PaddleOcrClient {
|
|
|
String bodyStr = response.getBody();
|
|
|
log.debug("PaddleOCR 响应: {}", bodyStr);
|
|
|
return bodyStr;
|
|
|
- } catch (IOException e) {
|
|
|
- log.error("读取待 OCR 文件失败: {}", filePath, e);
|
|
|
- throw new ServiceException("读取待 OCR 文件失败: " + e.getMessage());
|
|
|
- } catch (Exception e) {
|
|
|
- log.error("调用 PaddleOCR 服务异常", e);
|
|
|
- throw new ServiceException("调用 PaddleOCR 服务异常: " + e.getMessage());
|
|
|
+ } catch (RestClientException e) {
|
|
|
+ // 网络相关异常,会被重试机制处理
|
|
|
+ log.warn("OCR服务调用异常: {}", e.getMessage());
|
|
|
+ throw e;
|
|
|
}
|
|
|
}
|
|
|
}
|