feat(ocr): 扫描件与图片识别——OCR 进文字层、资质库上传识别、大图浏览
计划见 docs/architecture/vision-plan.md(VS1–VS13,docs/decisions.md)。 - 验证:OCR(RapidOCR + PP-OCRv6 small,CPU)和 DeepSeek Flash 看图在国动投标文件 和 7 张证书上初测(tech-validation §7,代码 spikes/s5-ocr/) - OCR 服务 services/ocr(镜像、Compose 服务):整页转正(含 180°)、红章附近按红色通道重读 - 扫描页和插图识别后并入文字层 v6,句子标 source=ocr;出处标「OCR」(迁移 0013); 依据识别文字的问题降级,规则不查扫描附件;国动端到端见 check-eval §16 - 资质库上传识别:添加资质对话框最上面传证书照片,识别后填表,只预填和 OCR 文字 对得上的字段;识别值留痕、照片挂成附件(迁移 0014,提示词 vision.cert_fields v1) - 资质库改为查看详情(只读键值 + 附件缩略图),附件用大图浏览控件看,不开新标签页 (设计规范 §7.23);PDF 附件按页出预览图 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
261
packages/api-client/src/schema.d.ts
vendored
261
packages/api-client/src/schema.d.ts
vendored
@@ -1277,6 +1277,63 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/qualifications/{qualification_id}/files/{file_id}/previews": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
qualification_id: components["parameters"]["QualificationId"];
|
||||
file_id: components["schemas"]["Id"];
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
/** 附件的预览图(图片一张,PDF 每页一张,最多 10 页),详情和大图浏览用 */
|
||||
get: operations["getQualificationFilePreviews"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/qualification-scans": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
get?: never;
|
||||
put?: never;
|
||||
/** 上传证书扫描件识别(后台识别,轮询结果;不扣额度,每个企业每天限 100 次) */
|
||||
post: operations["createQualificationScan"];
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/qualification-scans/{scan_id}": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
scan_id: components["schemas"]["Id"];
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
/** 识别结果 */
|
||||
get: operations["getQualificationScan"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
/** 丢弃识别结果(连同原件) */
|
||||
delete: operations["deleteQualificationScan"];
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/qualifications/{qualification_id}/files/{file_id}": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -1890,6 +1947,8 @@ export interface components {
|
||||
quote: string;
|
||||
quads: components["schemas"]["Quad"][];
|
||||
created_by_kind: components["schemas"]["Origin"];
|
||||
/** @description 原句是扫描页或插图上 OCR 识别出来的,可能有错字(界面标「识别文字」) */
|
||||
ocr: boolean;
|
||||
};
|
||||
/** @description 给用户看的失败原因;不含文档内容 */
|
||||
JobError: {
|
||||
@@ -2331,6 +2390,8 @@ export interface components {
|
||||
/** @description 界面上必填(查标时用它核对附件),接口可空,以后批量导入时不一定读得全 */
|
||||
cert_no?: string | null;
|
||||
issuer?: string | null;
|
||||
/** @description 证书主体(企业名、著作权人、持证人) */
|
||||
holder?: string | null;
|
||||
/** Format: date */
|
||||
valid_from?: string | null;
|
||||
/**
|
||||
@@ -2339,8 +2400,93 @@ export interface components {
|
||||
*/
|
||||
valid_to?: string | null;
|
||||
};
|
||||
/** @description 新增、修改资质。从识别结果保存时带上 scan:记下识别值,原件挂成附件(同一个原件不重复挂) */
|
||||
QualificationSave: components["schemas"]["QualificationInput"] & {
|
||||
scan?: {
|
||||
scan_id: components["schemas"]["Id"];
|
||||
/** @description 识别结果里的第几张证书(从 0 数) */
|
||||
index: number;
|
||||
} | null;
|
||||
};
|
||||
/** @description 一次证书识别(vision-plan 第 2 步)。没保存的 24 小时后删除 */
|
||||
QualificationScan: {
|
||||
id: components["schemas"]["Id"];
|
||||
filename: string;
|
||||
/** @enum {string} */
|
||||
status: "queued" | "running" | "succeeded" | "failed";
|
||||
error: null | components["schemas"]["ScanError"];
|
||||
pages: {
|
||||
page: number;
|
||||
/** @description 识别用的页面图宽(像素),高亮框按它换算成比例 */
|
||||
width: number;
|
||||
height: number;
|
||||
/** @description OCR 转正用的角度(0 / 90 / 180 / 270) */
|
||||
rotation: number;
|
||||
/** @description 页面图的短时签名地址 */
|
||||
url: string;
|
||||
}[];
|
||||
certificates: components["schemas"]["ScanCertificate"][];
|
||||
created_at: components["schemas"]["Timestamp"];
|
||||
};
|
||||
ScanError: {
|
||||
code: string;
|
||||
message: string;
|
||||
};
|
||||
ScanCertificate: {
|
||||
page: number;
|
||||
/** @enum {string} */
|
||||
category: "enterprise_qualification" | "system_cert" | "software_copyright" | "product" | "personnel" | "business_license" | "other";
|
||||
kind: components["schemas"]["QualificationKind"];
|
||||
/** @description 建议的资质名称:证书标题,后面括注软件名或专业 */
|
||||
name: string;
|
||||
/**
|
||||
* @description 证书编号取哪个字段(软著取登记号)
|
||||
* @enum {string}
|
||||
*/
|
||||
cert_no_field: "cert_no" | "reg_no";
|
||||
/** @description 字段名 → 识别结果。name、holder、level、specialty、software、cert_no、reg_no、issuer、issued_on、valid_from、valid_to、validity_text */
|
||||
fields: {
|
||||
[key: string]: components["schemas"]["ScanField"];
|
||||
};
|
||||
/** @description 证书上有、但被打码或看不清的字段,要手动填写 */
|
||||
masked: string[];
|
||||
/** @description 推算的建议值,用户点了才填。valid_to:证书只写了有效期长度(如「五年」)时按发证日期推算 */
|
||||
suggest: {
|
||||
/** Format: date */
|
||||
valid_to?: string;
|
||||
};
|
||||
notes: {
|
||||
/** @enum {string} */
|
||||
code: "personnel" | "product" | "business_license" | "holder_mismatch";
|
||||
holder?: string;
|
||||
tenant?: string;
|
||||
}[];
|
||||
/** @description 资质库里证书编号相同的一条(换证时建议更新它) */
|
||||
existing: null | {
|
||||
id: components["schemas"]["Id"];
|
||||
name: string;
|
||||
};
|
||||
};
|
||||
ScanField: {
|
||||
/** @description 证书上的原样文字 */
|
||||
value: string;
|
||||
/**
|
||||
* @description ok / date_ok 才自动填;low_conf(马赛克、模糊)、mismatch(识别结果和 OCR 对不上)等只作建议
|
||||
* @enum {string}
|
||||
*/
|
||||
check: "ok" | "date_ok" | "low_conf" | "mismatch" | "bad_line" | "bad_format";
|
||||
/**
|
||||
* Format: date
|
||||
* @description 日期字段换算成的日期
|
||||
*/
|
||||
day?: string;
|
||||
/** @description 所引 OCR 行在页面图上的位置(像素)[x0, y0, x1, y1] */
|
||||
boxes: number[][];
|
||||
};
|
||||
Qualification: components["schemas"]["QualificationInput"] & {
|
||||
id: components["schemas"]["Id"];
|
||||
/** @description 是从识别结果保存的(识别值留痕) */
|
||||
recognized: boolean;
|
||||
files: {
|
||||
id: components["schemas"]["Id"];
|
||||
filename: string;
|
||||
@@ -4717,7 +4863,7 @@ export interface operations {
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["QualificationInput"];
|
||||
"application/json": components["schemas"]["QualificationSave"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
@@ -4744,7 +4890,7 @@ export interface operations {
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["QualificationInput"];
|
||||
"application/json": components["schemas"]["QualificationSave"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
@@ -4809,6 +4955,117 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
};
|
||||
getQualificationFilePreviews: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
qualification_id: components["parameters"]["QualificationId"];
|
||||
file_id: components["schemas"]["Id"];
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description OK */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": {
|
||||
file_id: components["schemas"]["Id"];
|
||||
filename: string;
|
||||
pages: {
|
||||
page: number;
|
||||
width: number;
|
||||
height: number;
|
||||
/** @description 预览图(JPEG)的短时签名地址 */
|
||||
url: string;
|
||||
}[];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
createQualificationScan: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": {
|
||||
upload_id: components["schemas"]["Id"];
|
||||
};
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description 已排队 */
|
||||
201: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["QualificationScan"];
|
||||
};
|
||||
};
|
||||
429: components["responses"]["RateLimited"];
|
||||
/** @description `ocr_unavailable`:扫描件识别服务没有开或连不上,可以先手动填写 */
|
||||
503: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/problem+json": components["schemas"]["Problem"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
getQualificationScan: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
scan_id: components["schemas"]["Id"];
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description OK */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["QualificationScan"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
deleteQualificationScan: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
scan_id: components["schemas"]["Id"];
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description 已删除 */
|
||||
204: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content?: never;
|
||||
};
|
||||
};
|
||||
};
|
||||
getQualificationFileUrl: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
||||
Reference in New Issue
Block a user