package cn.iocoder.yudao.module.qcreport.service.aiimport.document;
|
|
import java.util.List;
|
|
/**
|
* 一个文件被适配器抽取后的中间结果。
|
* <p>
|
* <b>刻意不是树、也不是 HTML</b>:它只是「这份文件能交给模型的东西是什么」这个更小的问题的答案。
|
* 树要表达版式,HTML 要表达样式,两者都会把「模型能看见什么」放大到不可控;这里只留两个通道,
|
* 迫使下游(提示词构造、调用计划)不必再考虑第三种形态。
|
*
|
* <h3>为什么是双通道而不是一种</h3>
|
* 电子版 PDF / Word / Excel 有真实文本层,抽取成字符串最省 token,模型也读得最准;
|
* 扫描件与照片没有文本层,只能把页面渲染成图交给多模态模型。
|
* 这两条路的调用方式({@code chat} 与 {@code chatWithImage})、计费口径、失败模式都不同,
|
* 所以必须在类型上分开,而不是塞进一个字段里靠猜。
|
*
|
* @param channel 通道类型,见 {@link Channel}
|
* @param text TEXT 通道的正文,多页时页间以 {@code --- 第 N 页 ---} 分隔;IMAGES 通道恒为空串
|
* @param images IMAGES 通道的图片,每页一张;TEXT 通道恒为空列表
|
* @param pageCount 页数,用于超限校验与提示文案
|
* @param extractor 实际生效的抽取器标识(如 {@code pdfbox-text}),会写进日志便于排查
|
* @param notes 抽取阶段的软提示,直接进响应的 warnings 展示给用户
|
*/
|
public record QcReportDocumentExtract(
|
Channel channel,
|
String text,
|
List<ImagePart> images,
|
int pageCount,
|
String extractor,
|
List<String> notes) {
|
|
/**
|
* 纵向合并续格的占位标记。
|
* <p>
|
* 它属于「抽取出来的文本长什么样」这条契约,所以和 {@code text} 放在一处,
|
* 由生产者({@link OfficeImportAdapter})与解释者({@code QcReportTemplatePromptBuilder})
|
* 共用一份,避免两边各写一个字面量后各自漂移。
|
* <p>
|
* 为什么不能留空:{@code w:vMerge} 的续格在 Word 里表示「这一格与上一行是同一个值」,
|
* 但 POI 取出来就是空串。留空的话,模型区分不出「合并续格」与「原件本来就没填」,
|
* 于是整张表看起来是一层平铺的检验项,看不出分组结构。
|
*/
|
public static final String VERTICAL_MERGE_MARK = "↑同上";
|
|
/**
|
* 抽取通道。
|
*/
|
public enum Channel {
|
/** 有文本层,整份文件拼成一段文本,一次模型调用 */
|
TEXT,
|
/** 无文本层(扫描件/照片),逐页转图,每页一次模型调用 */
|
IMAGES
|
}
|
|
/**
|
* IMAGES 通道里的一页图。
|
*
|
* @param bytes 图片字节,执行器负责转成裸 base64
|
* @param mimeType 形如 {@code image/png} 的裸类型,不带 {@code data:} 前缀
|
* @param label 页标签,用于拼错误与提示文案,例如「扫描件.pdf 第 2 页」
|
*/
|
public record ImagePart(byte[] bytes, String mimeType, String label) {
|
}
|
|
/**
|
* 文本通道的工厂。{@code notes} 允许为空表示没有软提示。
|
*/
|
public static QcReportDocumentExtract ofText(String text, int pageCount, String extractor,
|
List<String> notes) {
|
return new QcReportDocumentExtract(Channel.TEXT, text, List.of(), pageCount, extractor, notes);
|
}
|
|
/**
|
* 图片通道的工厂。
|
*/
|
public static QcReportDocumentExtract ofImages(List<ImagePart> images, int pageCount,
|
String extractor, List<String> notes) {
|
return new QcReportDocumentExtract(Channel.IMAGES, "", List.copyOf(images), pageCount,
|
extractor, notes);
|
}
|
|
}
|