✨ 身份证OCR改接ShenFenZheng,回填有效期与长期有效
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+3
@@ -418,6 +418,9 @@ public class DriverServiceImpl extends BaseServiceImpl<DriverMapper, Driver> imp
|
||||
driver.setDrivingLicenseBack(trimToNull(driver.getDrivingLicenseBack()));
|
||||
driver.setQualificationFront(trimToNull(driver.getQualificationFront()));
|
||||
driver.setQualificationBack(trimToNull(driver.getQualificationBack()));
|
||||
if (driver.getIdCardLongTerm() == null) {
|
||||
driver.setIdCardLongTerm(DEFAULT_FALSE);
|
||||
}
|
||||
if (driver.getDrivingLicenseLongTerm() == null) {
|
||||
driver.setDrivingLicenseLongTerm(DEFAULT_FALSE);
|
||||
}
|
||||
|
||||
+13
@@ -38,9 +38,22 @@ public class IDCardVO implements Serializable {
|
||||
*/
|
||||
@JsonFormat(pattern = DateUtil.PATTERN_DATE, timezone = "GMT+8")
|
||||
private Date birthday;
|
||||
/**
|
||||
* 住址
|
||||
*/
|
||||
private String address;
|
||||
/**
|
||||
* 有效期起
|
||||
*/
|
||||
@JsonFormat(pattern = DateUtil.PATTERN_DATE, timezone = "GMT+8")
|
||||
private Date validDateStart;
|
||||
/**
|
||||
* 有效期止
|
||||
*/
|
||||
@JsonFormat(pattern = DateUtil.PATTERN_DATE, timezone = "GMT+8")
|
||||
private Date validDateEnd;
|
||||
/**
|
||||
* 长期有效:1-是,0-否
|
||||
*/
|
||||
private Integer longTerm;
|
||||
}
|
||||
|
||||
+67
-28
@@ -1,6 +1,9 @@
|
||||
package org.springblade.thirdparty.ocr.service.impl;
|
||||
|
||||
import cn.hutool.core.lang.TypeReference;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -13,10 +16,10 @@ import org.springblade.thirdparty.ocr.constant.OCRImageType;
|
||||
import org.springblade.thirdparty.ocr.convert.AttachmentIndexConvert;
|
||||
import org.springblade.thirdparty.ocr.exception.OCRException;
|
||||
import org.springblade.thirdparty.ocr.feign.IOCRClient;
|
||||
import org.springblade.thirdparty.ocr.feign.IOCROtherClient;
|
||||
import org.springblade.thirdparty.ocr.pojo.dto.*;
|
||||
import org.springblade.thirdparty.ocr.pojo.vo.*;
|
||||
import org.springblade.thirdparty.ocr.service.IOCRService;
|
||||
import org.springblade.thirdparty.ocr.support.ShenFenZhengIdCardSupport;
|
||||
import org.springblade.thirdparty.ocr.util.ConvertUtil;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -43,10 +46,12 @@ public class OCRServiceImpl implements IOCRService {
|
||||
private static final BigDecimal WEIGHT_LIMIT = BigDecimal.valueOf(200);
|
||||
|
||||
private final IOCRClient client;
|
||||
private final IOCROtherClient otherClient;
|
||||
|
||||
@Value("${thirdParty.ocr.baseOtherUrl}")
|
||||
private String ocrBaseOtherUrl;
|
||||
/**
|
||||
* 身份证 OCR 服务地址,Nacos:thirdParty.ocr.idCardBaseUrl
|
||||
*/
|
||||
@Value("${thirdParty.ocr.idCardBaseUrl:${thirdParty.ocr.baseOtherUrl}}")
|
||||
private String idCardBaseUrl;
|
||||
|
||||
@Override
|
||||
public TransportCertificateVO recognitionTransportCertificate(CertificateBatchRecognitionDTO param) {
|
||||
@@ -339,45 +344,79 @@ public class OCRServiceImpl implements IOCRService {
|
||||
if (CollectionUtils.isEmpty(urls)) {
|
||||
throw new OCRException("图像链接不能为空");
|
||||
}
|
||||
if (StringUtil.isBlank(idCardBaseUrl)) {
|
||||
throw new OCRException("身份证OCR服务地址未配置(thirdParty.ocr.idCardBaseUrl)");
|
||||
}
|
||||
IDCardVO result = new IDCardVO();
|
||||
try {
|
||||
for (String url : urls) {
|
||||
OCRCardBankDetRecDTO param = new OCRCardBankDetRecDTO(url);
|
||||
// param.setDataType("IDCard-Main");
|
||||
log.info("调用ocr证件定位+结构化信息提取接口,请求地址:{},请求参数:{}",
|
||||
getCardBankDetRecUrl(), JSONUtil.toJsonStr(param));
|
||||
OCRResultVO<OCRBigCommonCardVO> resultVO = otherClient.cardBankDetRec(param);
|
||||
if (resultVO != null && OCRConstant.SUCCESS_CODE.equals(resultVO.getCode())) {
|
||||
// 成功
|
||||
OCRBigCommonCardVO card = resultVO.getResult();
|
||||
convertIDCard(result, card);
|
||||
if (StringUtil.isBlank(url)) {
|
||||
continue;
|
||||
}
|
||||
log.error("调用ocr接口证件定位+结构化信息提取异常响应参数:{}", JSONUtil.toJsonStr(resultVO));
|
||||
String message = getMessage(resultVO);
|
||||
throw new OCRException("调用ocr接口证件定位+结构化信息提取异常 " + message);
|
||||
ShenFenZhengIdCardSupport.merge(result, recognizeIdCardByShenFenZheng(url.trim()));
|
||||
}
|
||||
} catch (OCRException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
log.error("调用ocr接口证件定位+结构化信息提取异常", e);
|
||||
throw new OCRException("调用ocr接口证件定位+结构化信息提取异常");
|
||||
log.error("调用身份证OCR接口异常", e);
|
||||
throw new OCRException("调用身份证OCR接口异常");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String getCardBankDetRecUrl() {
|
||||
return ocrBaseOtherUrl.replaceAll("/+$", "") + "/CardBankDetRec";
|
||||
/**
|
||||
* 下载图片后以 formData.image_file 调用 ShenFenZheng
|
||||
*
|
||||
* @param imageUrl 可访问的图片地址
|
||||
* @return 单张识别结果
|
||||
*/
|
||||
private IDCardVO recognizeIdCardByShenFenZheng(String imageUrl) {
|
||||
String requestUrl = idCardBaseUrl.replaceAll("/+$", "") + ShenFenZhengIdCardSupport.PATH;
|
||||
byte[] imageBytes;
|
||||
try {
|
||||
imageBytes = HttpUtil.downloadBytes(imageUrl);
|
||||
} catch (Exception exception) {
|
||||
log.error("下载身份证图片失败,url={}", imageUrl, exception);
|
||||
throw new OCRException("下载身份证图片失败");
|
||||
}
|
||||
if (imageBytes == null || imageBytes.length == 0) {
|
||||
throw new OCRException("身份证图片内容为空");
|
||||
}
|
||||
String fileName = resolveImageFileName(imageUrl);
|
||||
log.info("调用身份证OCR接口,请求地址:{},文件名:{},大小:{}", requestUrl, fileName, imageBytes.length);
|
||||
try (HttpResponse response = HttpRequest.post(requestUrl)
|
||||
.form(ShenFenZhengIdCardSupport.FILE_FIELD, imageBytes, fileName)
|
||||
.timeout(60000)
|
||||
.execute()) {
|
||||
String body = response.body();
|
||||
log.info("调用身份证OCR接口响应,status={},body={}", response.getStatus(), body);
|
||||
if (!response.isOk()) {
|
||||
throw new OCRException("调用身份证OCR接口失败,HTTP状态码:" + response.getStatus());
|
||||
}
|
||||
if (!ShenFenZhengIdCardSupport.isSuccess(body)) {
|
||||
throw new OCRException("身份证OCR识别失败");
|
||||
}
|
||||
return ShenFenZhengIdCardSupport.parse(body);
|
||||
} catch (OCRException exception) {
|
||||
throw exception;
|
||||
} catch (Exception exception) {
|
||||
log.error("调用身份证OCR接口异常,url={}", requestUrl, exception);
|
||||
throw new OCRException("调用身份证OCR接口异常");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换身份证
|
||||
* @param result
|
||||
* @param card
|
||||
* @return
|
||||
*/
|
||||
private void convertIDCard(IDCardVO result, OCRBigCommonCardVO card) {
|
||||
convert(result, card, ConvertUtil::getIDCardSetter, null);
|
||||
private String resolveImageFileName(String imageUrl) {
|
||||
String path = imageUrl;
|
||||
int queryIndex = path.indexOf('?');
|
||||
if (queryIndex >= 0) {
|
||||
path = path.substring(0, queryIndex);
|
||||
}
|
||||
int slashIndex = path.lastIndexOf('/');
|
||||
String name = slashIndex >= 0 ? path.substring(slashIndex + 1) : path;
|
||||
if (StringUtil.isBlank(name) || !name.contains(".")) {
|
||||
return "id-card.jpg";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+301
@@ -0,0 +1,301 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.thirdparty.ocr.support;
|
||||
|
||||
import cn.hutool.json.JSONArray;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import org.springblade.core.tool.utils.DateUtil;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springblade.thirdparty.ocr.pojo.vo.IDCardVO;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 身份证 OCR(ShenFenZheng)响应解析
|
||||
* <p>
|
||||
* 第三方返回形如:
|
||||
* {@code result."0" = [[{"label":"身份证_姓名"}], [{"result":"张三"}], {"r":[...]}]},
|
||||
* 这里抽成「标签 → 文本」后再回填 {@link IDCardVO}。
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public final class ShenFenZhengIdCardSupport {
|
||||
|
||||
/**
|
||||
* 接口路径
|
||||
*/
|
||||
public static final String PATH = "/ShenFenZheng";
|
||||
|
||||
/**
|
||||
* formData 文件字段名
|
||||
*/
|
||||
public static final String FILE_FIELD = "image_file";
|
||||
|
||||
private static final String LONG_TERM_TEXT = "长期";
|
||||
|
||||
private static final Pattern DATE_PATTERN = Pattern.compile("(\\d{4})\\D+(\\d{1,2})\\D+(\\d{1,2})");
|
||||
|
||||
private static final Map<String, BiConsumer<IDCardVO, String>> FIELD_SETTERS = initFieldSetters();
|
||||
|
||||
private ShenFenZhengIdCardSupport() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析第三方原始 JSON 为身份证 VO
|
||||
*
|
||||
* @param responseBody 响应原文
|
||||
* @return 识别结果;结构异常时返回空对象
|
||||
*/
|
||||
public static IDCardVO parse(String responseBody) {
|
||||
IDCardVO result = new IDCardVO();
|
||||
if (StringUtil.isBlank(responseBody)) {
|
||||
return result;
|
||||
}
|
||||
JSONObject root = JSONUtil.parseObj(responseBody);
|
||||
Map<String, String> fields = readLabelValues(root.getJSONObject("result"));
|
||||
for (Map.Entry<String, String> entry : fields.entrySet()) {
|
||||
BiConsumer<IDCardVO, String> setter = FIELD_SETTERS.get(normalizeLabel(entry.getKey()));
|
||||
if (setter != null && StringUtil.isNotBlank(entry.getValue())) {
|
||||
setter.accept(result, entry.getValue().trim());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断第三方是否识别成功
|
||||
*
|
||||
* @param responseBody 响应原文
|
||||
* @return true 表示成功
|
||||
*/
|
||||
public static boolean isSuccess(String responseBody) {
|
||||
if (StringUtil.isBlank(responseBody)) {
|
||||
return false;
|
||||
}
|
||||
JSONObject root = JSONUtil.parseObj(responseBody);
|
||||
Boolean status = root.getBool("status");
|
||||
if (Boolean.TRUE.equals(status)) {
|
||||
return true;
|
||||
}
|
||||
// 个别版本只给 identifyCode,1001 视为成功
|
||||
Integer identifyCode = root.getInt("identifyCode");
|
||||
return identifyCode != null && identifyCode == 1001;
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并多张图的识别结果:后写的非空值覆盖先写的,方便正反面各识别一次后汇总
|
||||
*
|
||||
* @param target 汇总目标
|
||||
* @param source 本次识别结果
|
||||
*/
|
||||
public static void merge(IDCardVO target, IDCardVO source) {
|
||||
if (target == null || source == null) {
|
||||
return;
|
||||
}
|
||||
if (StringUtil.isNotBlank(source.getName())) {
|
||||
target.setName(source.getName());
|
||||
}
|
||||
if (StringUtil.isNotBlank(source.getIdNo())) {
|
||||
target.setIdNo(source.getIdNo());
|
||||
}
|
||||
if (StringUtil.isNotBlank(source.getGender())) {
|
||||
target.setGender(source.getGender());
|
||||
}
|
||||
if (StringUtil.isNotBlank(source.getNation())) {
|
||||
target.setNation(source.getNation());
|
||||
}
|
||||
if (source.getBirthday() != null) {
|
||||
target.setBirthday(source.getBirthday());
|
||||
}
|
||||
if (StringUtil.isNotBlank(source.getAddress())) {
|
||||
target.setAddress(source.getAddress());
|
||||
}
|
||||
if (source.getValidDateStart() != null) {
|
||||
target.setValidDateStart(source.getValidDateStart());
|
||||
}
|
||||
if (source.getValidDateEnd() != null) {
|
||||
target.setValidDateEnd(source.getValidDateEnd());
|
||||
}
|
||||
if (source.getLongTerm() != null) {
|
||||
target.setLongTerm(source.getLongTerm());
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<String, String> readLabelValues(JSONObject result) {
|
||||
Map<String, String> fields = new LinkedHashMap<>();
|
||||
if (result == null || result.isEmpty()) {
|
||||
return fields;
|
||||
}
|
||||
for (String key : result.keySet()) {
|
||||
JSONArray item = result.getJSONArray(key);
|
||||
if (item == null || item.size() < 2) {
|
||||
continue;
|
||||
}
|
||||
String label = readNestedText(item.get(0), "label");
|
||||
String value = readNestedText(item.get(1), "result");
|
||||
if (StringUtil.isNotBlank(label) && StringUtil.isNotBlank(value)) {
|
||||
fields.put(label, value);
|
||||
}
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
private static String readNestedText(Object node, String fieldName) {
|
||||
if (node instanceof JSONArray array) {
|
||||
if (array.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
Object first = array.get(0);
|
||||
if (first instanceof JSONObject object) {
|
||||
return object.getStr(fieldName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (node instanceof JSONObject object) {
|
||||
return object.getStr(fieldName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String normalizeLabel(String label) {
|
||||
return StringUtil.isBlank(label) ? "" : label.trim();
|
||||
}
|
||||
|
||||
private static Map<String, BiConsumer<IDCardVO, String>> initFieldSetters() {
|
||||
Map<String, BiConsumer<IDCardVO, String>> setters = new LinkedHashMap<>();
|
||||
setters.put("身份证_姓名", IDCardVO::setName);
|
||||
setters.put("姓名", IDCardVO::setName);
|
||||
setters.put("身份证_公民身份号码", IDCardVO::setIdNo);
|
||||
setters.put("公民身份号码", IDCardVO::setIdNo);
|
||||
setters.put("公民身份证号码", IDCardVO::setIdNo);
|
||||
setters.put("身份证_性别", IDCardVO::setGender);
|
||||
setters.put("性别", IDCardVO::setGender);
|
||||
setters.put("身份证_民族", (card, value) -> card.setNation(normalizeNation(value)));
|
||||
setters.put("民族", (card, value) -> card.setNation(normalizeNation(value)));
|
||||
setters.put("身份证_出生", (card, value) -> card.setBirthday(parseDate(value)));
|
||||
setters.put("出生", (card, value) -> card.setBirthday(parseDate(value)));
|
||||
setters.put("身份证_住址", IDCardVO::setAddress);
|
||||
setters.put("住址", IDCardVO::setAddress);
|
||||
setters.put("身份证_有效期限", ShenFenZhengIdCardSupport::applyValidity);
|
||||
setters.put("有效期限", ShenFenZhengIdCardSupport::applyValidity);
|
||||
setters.put("身份证_签发日期", (card, value) -> card.setValidDateStart(parseDate(value)));
|
||||
setters.put("签发日期", (card, value) -> card.setValidDateStart(parseDate(value)));
|
||||
setters.put("身份证_失效日期", ShenFenZhengIdCardSupport::applyEndDate);
|
||||
setters.put("失效日期", ShenFenZhengIdCardSupport::applyEndDate);
|
||||
return setters;
|
||||
}
|
||||
|
||||
private static String normalizeNation(String value) {
|
||||
String nation = value == null ? "" : value.trim();
|
||||
if (nation.isEmpty()) {
|
||||
return nation;
|
||||
}
|
||||
return nation.endsWith("族") ? nation : nation + "族";
|
||||
}
|
||||
|
||||
private static void applyValidity(IDCardVO card, String value) {
|
||||
if (StringUtil.isBlank(value)) {
|
||||
return;
|
||||
}
|
||||
if (value.contains(LONG_TERM_TEXT)) {
|
||||
card.setLongTerm(1);
|
||||
card.setValidDateEnd(null);
|
||||
Date start = parseFirstDate(value);
|
||||
if (start != null) {
|
||||
card.setValidDateStart(start);
|
||||
}
|
||||
return;
|
||||
}
|
||||
card.setLongTerm(0);
|
||||
Date start = parseFirstDate(value);
|
||||
Date end = parseLastDate(value);
|
||||
if (start != null) {
|
||||
card.setValidDateStart(start);
|
||||
}
|
||||
if (end != null) {
|
||||
card.setValidDateEnd(end);
|
||||
}
|
||||
}
|
||||
|
||||
private static void applyEndDate(IDCardVO card, String value) {
|
||||
if (StringUtil.isBlank(value)) {
|
||||
return;
|
||||
}
|
||||
if (value.contains(LONG_TERM_TEXT)) {
|
||||
card.setLongTerm(1);
|
||||
card.setValidDateEnd(null);
|
||||
return;
|
||||
}
|
||||
Date end = parseDate(value);
|
||||
if (end != null) {
|
||||
card.setLongTerm(0);
|
||||
card.setValidDateEnd(end);
|
||||
}
|
||||
}
|
||||
|
||||
private static Date parseDate(String text) {
|
||||
return parseFirstDate(text);
|
||||
}
|
||||
|
||||
private static Date parseFirstDate(String text) {
|
||||
Matcher matcher = DATE_PATTERN.matcher(text);
|
||||
if (!matcher.find()) {
|
||||
return null;
|
||||
}
|
||||
return toDate(matcher.group(1), matcher.group(2), matcher.group(3));
|
||||
}
|
||||
|
||||
private static Date parseLastDate(String text) {
|
||||
Matcher matcher = DATE_PATTERN.matcher(text);
|
||||
String year = null;
|
||||
String month = null;
|
||||
String day = null;
|
||||
while (matcher.find()) {
|
||||
year = matcher.group(1);
|
||||
month = matcher.group(2);
|
||||
day = matcher.group(3);
|
||||
}
|
||||
if (year == null) {
|
||||
return null;
|
||||
}
|
||||
return toDate(year, month, day);
|
||||
}
|
||||
|
||||
private static Date toDate(String year, String month, String day) {
|
||||
try {
|
||||
String formatted = String.format("%s-%02d-%02d", year, Integer.parseInt(month), Integer.parseInt(day));
|
||||
return DateUtil.parse(formatted, DateUtil.PATTERN_DATE);
|
||||
} catch (Exception ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,8 +92,10 @@ thirdParty:
|
||||
ocr:
|
||||
# OCR磅单、车牌识别接口地址
|
||||
baseUrl: http://127.0.0.1:8080
|
||||
# OCR证件识别接口地址
|
||||
# OCR证件识别接口地址(银行卡等通用证件)
|
||||
baseOtherUrl: http://127.0.0.1:8080
|
||||
# 身份证 OCR 服务地址(POST /ShenFenZheng,formData 字段 image_file)
|
||||
idCardBaseUrl: http://124.71.22.123:8500
|
||||
wps:
|
||||
# WPS开放接口地址
|
||||
baseUrl: http://127.0.0.1:8080
|
||||
|
||||
@@ -54,8 +54,10 @@ thirdParty:
|
||||
ocr:
|
||||
# OCR磅单、车牌识别接口地址
|
||||
baseUrl: http://127.0.0.1:8080
|
||||
# OCR证件识别接口地址
|
||||
# OCR证件识别接口地址(银行卡等通用证件)
|
||||
baseOtherUrl: http://127.0.0.1:8080
|
||||
# 身份证 OCR 服务地址(POST /ShenFenZheng,formData 字段 image_file)
|
||||
idCardBaseUrl: http://124.71.22.123:8500
|
||||
wps:
|
||||
# WPS开放接口地址
|
||||
baseUrl: http://127.0.0.1:8080
|
||||
|
||||
@@ -3,8 +3,10 @@ thirdParty:
|
||||
ocr:
|
||||
# OCR磅单、车牌识别接口地址
|
||||
baseUrl: ${OCR_BASE_URL:http://127.0.0.1:8080}
|
||||
# OCR证件识别接口地址
|
||||
# OCR证件识别接口地址(银行卡等通用证件)
|
||||
baseOtherUrl: ${OCR_BASE_OTHER_URL:http://127.0.0.1:8080}
|
||||
# 身份证 OCR 服务地址(POST /ShenFenZheng,formData 字段 image_file)
|
||||
idCardBaseUrl: ${OCR_ID_CARD_BASE_URL:http://124.71.22.123:8500}
|
||||
wps:
|
||||
# WPS开放接口地址
|
||||
baseUrl: ${WPS_BASE_URL:http://127.0.0.1:8080}
|
||||
|
||||
Reference in New Issue
Block a user