refactor(doc): 重构文档分类响应数据结构
- 将 DocClassifyResp 中的 items 字段重命名为 wordsResult - 将 DocClassifyResp 中的 count 字段移除,新增 logId 字段 - 将 DocClassifyItemResp 中的位置相关字段提取为独立的 DocClassifyLocationResp 对象 - 更新所有相关的 getter/setter 调用以匹配新的数据结构 - 修复注释中关于百度 API 字段名拼写错误的说明 - 添加详细的字段说明注释以提高代码可读性
This commit is contained in:
parent
d5ebd16c21
commit
39738eead9
@ -13,6 +13,7 @@ import com.heyu.api.data.utils.R;
|
||||
import com.heyu.api.data.utils.StringUtils;
|
||||
import com.heyu.api.request.doc.DocClassifyRequest;
|
||||
import com.heyu.api.resp.doc.DocClassifyItemResp;
|
||||
import com.heyu.api.resp.doc.DocClassifyLocationResp;
|
||||
import com.heyu.api.resp.doc.DocClassifyResp;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@ -195,7 +196,7 @@ public class DocClassifyController extends AbstractRecognizeController {
|
||||
"解析状态=结果集为空"
|
||||
);
|
||||
}
|
||||
if (data == null || data.getItems() == null || data.getItems().isEmpty()) {
|
||||
if (data == null || data.getWordsResult() == null || data.getWordsResult().isEmpty()) {
|
||||
log.info("文档分类:平台有返回,但分类结果列表为空(可能图片不包含可识别主体)。{}。客户传的:{}。平台回执:{}",
|
||||
ctx.imageInput.getType().getDesc(),
|
||||
ctx.inputLog, buildPlatformReceiptSummary(platformResult));
|
||||
@ -215,7 +216,7 @@ public class DocClassifyController extends AbstractRecognizeController {
|
||||
"字段映射为空",
|
||||
"平台回执包含分类条目,但类别、置信度、位置等结构化字段均未命中",
|
||||
"请确认上传图片清晰且包含可识别的文档、卡证或票据主体",
|
||||
"分类条目数=" + data.getItems().size() + ",有效字段数=0"
|
||||
"分类条目数=" + data.getWordsResult().size() + ",有效字段数=0"
|
||||
);
|
||||
}
|
||||
return null;
|
||||
@ -224,7 +225,7 @@ public class DocClassifyController extends AbstractRecognizeController {
|
||||
private void logRecognizeResult(RecognizeContext ctx, Map<String, Object> platformResult,
|
||||
DocClassifyResp data, String hint, long start) {
|
||||
long cost = System.currentTimeMillis() - start;
|
||||
int itemCount = data != null && data.getItems() != null ? data.getItems().size() : 0;
|
||||
int itemCount = data != null && data.getWordsResult() != null ? data.getWordsResult().size() : 0;
|
||||
int totalFields = countTotalItemFields(data);
|
||||
if (StringUtils.isNotBlank(hint)) {
|
||||
log.info("文档分类:处理结束(接口仍返回成功,但带了提示信息)。耗时 {} ms,分类出 {} 个主体、共 {} 个字段。"
|
||||
@ -290,12 +291,15 @@ public class DocClassifyController extends AbstractRecognizeController {
|
||||
@SuppressWarnings("unchecked")
|
||||
private DocClassifyResp buildResp(Map<String, Object> platformResult) {
|
||||
DocClassifyResp resp = new DocClassifyResp();
|
||||
Object wordsResult = platformResult.get("words_result");
|
||||
Object wordsResultNum = platformResult.get("words_result_num");
|
||||
resp.setCount(wordsResultNum != null ? String.valueOf(wordsResultNum) : "0");
|
||||
|
||||
// 一级字段:log_id
|
||||
Object logId = platformResult.get("log_id");
|
||||
resp.setLogId(logId != null ? String.valueOf(logId) : null);
|
||||
|
||||
// 一级字段:words_result
|
||||
Object wordsResult = platformResult.get("words_result");
|
||||
if (!(wordsResult instanceof List)) {
|
||||
resp.setItems(Collections.emptyList());
|
||||
resp.setWordsResult(Collections.emptyList());
|
||||
return resp;
|
||||
}
|
||||
List<Map<String, Object>> resultList = (List<Map<String, Object>>) wordsResult;
|
||||
@ -303,26 +307,32 @@ public class DocClassifyController extends AbstractRecognizeController {
|
||||
for (Map<String, Object> item : resultList) {
|
||||
items.add(buildItemResp(item));
|
||||
}
|
||||
resp.setItems(items);
|
||||
resp.setWordsResult(items);
|
||||
return resp;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private DocClassifyItemResp buildItemResp(Map<String, Object> item) {
|
||||
DocClassifyItemResp resp = new DocClassifyItemResp();
|
||||
|
||||
// 二级字段:type
|
||||
Object type = item.get("type");
|
||||
resp.setType(type != null ? String.valueOf(type) : null);
|
||||
// 注意:百度 API 原始字段名为 "probablity"(拼写错误),此处与之保持一致
|
||||
|
||||
// 二级字段:probability(注意:百度 API 原始字段名为 "probablity",拼写错误,此处与之保持一致)
|
||||
Object prob = item.get("probablity");
|
||||
resp.setProbability(prob != null ? String.valueOf(prob) : null);
|
||||
|
||||
// 二级字段:location(嵌套对象)
|
||||
Object location = item.get("location");
|
||||
if (location instanceof Map) {
|
||||
Map<String, Object> loc = (Map<String, Object>) location;
|
||||
resp.setTop(stringOrNull(loc.get("top")));
|
||||
resp.setLeft(stringOrNull(loc.get("left")));
|
||||
resp.setWidth(stringOrNull(loc.get("width")));
|
||||
resp.setHeight(stringOrNull(loc.get("height")));
|
||||
DocClassifyLocationResp locationResp = new DocClassifyLocationResp();
|
||||
locationResp.setLeft(stringOrNull(loc.get("left")));
|
||||
locationResp.setTop(stringOrNull(loc.get("top")));
|
||||
locationResp.setWidth(stringOrNull(loc.get("width")));
|
||||
locationResp.setHeight(stringOrNull(loc.get("height")));
|
||||
resp.setLocation(locationResp);
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
@ -353,11 +363,11 @@ public class DocClassifyController extends AbstractRecognizeController {
|
||||
* 统计所有分类条目的非空字段总数(使用父类反射工具)。
|
||||
*/
|
||||
private int countTotalItemFields(DocClassifyResp data) {
|
||||
if (data == null || data.getItems() == null) {
|
||||
if (data == null || data.getWordsResult() == null) {
|
||||
return 0;
|
||||
}
|
||||
int total = 0;
|
||||
for (DocClassifyItemResp item : data.getItems()) {
|
||||
for (DocClassifyItemResp item : data.getWordsResult()) {
|
||||
total += countNonBlankStringFields(item);
|
||||
}
|
||||
return total;
|
||||
@ -370,10 +380,10 @@ public class DocClassifyController extends AbstractRecognizeController {
|
||||
* 改为遍历每条 ItemResp 做反射判断。</p>
|
||||
*/
|
||||
private boolean isAllItemsFieldsBlank(DocClassifyResp data) {
|
||||
if (data == null || data.getItems() == null || data.getItems().isEmpty()) {
|
||||
if (data == null || data.getWordsResult() == null || data.getWordsResult().isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
for (DocClassifyItemResp item : data.getItems()) {
|
||||
for (DocClassifyItemResp item : data.getWordsResult()) {
|
||||
if (!isAllStringFieldsBlank(item)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -3,10 +3,14 @@ package com.heyu.api.resp.doc;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 文档分类检测 — 单个分类结果项。
|
||||
* 文档分类检测 — 单个分类结果项(words_result 数组元素)。
|
||||
* <p>
|
||||
* 所有字段均为 String 类型,保证反射统计工具覆盖。
|
||||
* 字段与百度 doc_classify 接口返回的 words_result 数组元素一一对应。
|
||||
* 二级字段:
|
||||
* <ul>
|
||||
* <li>type — 类别信息</li>
|
||||
* <li>probability — 分类置信度</li>
|
||||
* <li>location — 位置数组(左上角为坐标0点)</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*
|
||||
* @author zhengli
|
||||
@ -23,38 +27,16 @@ public class DocClassifyItemResp {
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 分类置信度(0~1 之间的小数,字符串形式)。
|
||||
* 对应百度字段:probablity(float)
|
||||
* 分类置信度(0~1 之间的小数)。
|
||||
* 对应百度字段:probability(float)
|
||||
* 示例:"0.9999860525"
|
||||
*/
|
||||
private String probability;
|
||||
|
||||
/**
|
||||
* 位置信息 — 表示定位位置的长方形左上顶点的垂直坐标(像素)。
|
||||
* 对应百度字段:location.top(uint32)
|
||||
* 示例:"1684"
|
||||
* 位置信息(左上角为坐标0点)。
|
||||
* 对应百度字段:location(object)
|
||||
*/
|
||||
private String top;
|
||||
|
||||
/**
|
||||
* 位置信息 — 表示定位位置的长方形左上顶点的水平坐标(像素)。
|
||||
* 对应百度字段:location.left(uint32)
|
||||
* 示例:"300"
|
||||
*/
|
||||
private String left;
|
||||
|
||||
/**
|
||||
* 位置信息 — 表示定位位置的长方形的宽度(像素)。
|
||||
* 对应百度字段:location.width(uint32)
|
||||
* 示例:"2710"
|
||||
*/
|
||||
private String width;
|
||||
|
||||
/**
|
||||
* 位置信息 — 表示定位位置的长方形的高度(像素)。
|
||||
* 对应百度字段:location.height(uint32)
|
||||
* 示例:"1712"
|
||||
*/
|
||||
private String height;
|
||||
private DocClassifyLocationResp location;
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,41 @@
|
||||
package com.heyu.api.resp.doc;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 文档分类检测 — 位置信息(location 子对象)。
|
||||
* <p>
|
||||
* 表示定位位置的长方形,左上角为坐标0点。
|
||||
* </p>
|
||||
*
|
||||
* @author zhengli
|
||||
* @since 20260609_zl
|
||||
*/
|
||||
@Data
|
||||
public class DocClassifyLocationResp {
|
||||
|
||||
/**
|
||||
* 表示定位位置的长方形左上顶点的水平坐标(像素)。
|
||||
* 对应百度字段:location.left(uint32)
|
||||
*/
|
||||
private String left;
|
||||
|
||||
/**
|
||||
* 表示定位位置的长方形左上顶点的垂直坐标(像素)。
|
||||
* 对应百度字段:location.top(uint32)
|
||||
*/
|
||||
private String top;
|
||||
|
||||
/**
|
||||
* 表示定位位置的长方形的宽度(像素)。
|
||||
* 对应百度字段:location.width(uint32)
|
||||
*/
|
||||
private String width;
|
||||
|
||||
/**
|
||||
* 表示定位位置的长方形的高度(像素)。
|
||||
* 对应百度字段:location.height(uint32)
|
||||
*/
|
||||
private String height;
|
||||
|
||||
}
|
||||
@ -5,11 +5,13 @@ import lombok.Data;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 文档分类检测响应。
|
||||
* 文档分类检测响应,对齐百度官方接口返回结构。
|
||||
* <p>
|
||||
* 对图片中的文档、卡证、票据等含文字的主体进行检测和分类,
|
||||
* 返回每个主体的类别、置信度和位置信息。
|
||||
* 如图片中无文字内容,items 为空列表。
|
||||
* 一级字段:
|
||||
* <ul>
|
||||
* <li>logId — 唯一的日志id,用于问题定位</li>
|
||||
* <li>wordsResult — 检测和分类结果数组,如图片中无文字内容,则此数组为空</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*
|
||||
* @author zhengli
|
||||
@ -19,15 +21,15 @@ import java.util.List;
|
||||
public class DocClassifyResp {
|
||||
|
||||
/**
|
||||
* 分类结果列表;图片中无文字内容时为空列表。
|
||||
* 示例:[{type="卡证_银行卡", probability="0.9999860525", top="1684", left="300", width="2710", height="1712"}]
|
||||
* 唯一的日志id,用于问题定位。
|
||||
* 对应百度字段:log_id(uint64)
|
||||
*/
|
||||
private List<DocClassifyItemResp> items;
|
||||
private String logId;
|
||||
|
||||
/**
|
||||
* 检测到的主体数量。
|
||||
* 示例:"3"
|
||||
* 检测和分类结果数组;如图片中无文字内容,则此数组为空。
|
||||
* 对应百度字段:words_result(array)
|
||||
*/
|
||||
private String count;
|
||||
private List<DocClassifyItemResp> wordsResult;
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user