feat(wiki): expose method=tika short-circuit on extract_document_text

This commit is contained in:
matevip 2026-04-25 19:02:35 +08:00
parent c752c1f2ae
commit c13d9b4c88

View File

@ -45,20 +45,26 @@ public class DocumentExtractTool {
- Excel (.xlsx, .xls) - 提取为文本表格 - Excel (.xlsx, .xls) - 提取为文本表格
- PowerPoint (.pptx, .ppt) - PowerPoint (.pptx, .ppt)
提取策略自动选择最优方式 提取策略默认自动选择最优方式
1. 优先使用系统命令pdftotext, textutil, pandoc 1. 优先使用系统命令pdftotext, textutil, pandoc
2. 系统命令不可用时使用纯 Java 实现 2. 系统命令不可用时使用纯 Java 实现
3. 返回详细的提取过程和元数据 3. PDF 扫描版进入 OCR
4. 全部失败前用 Apache Tika 兜底覆盖 SmartArt共享字符串表等盲区
5. 返回详细的提取过程和元数据
参数 options 可包含 参数 options 可包含
- pages: 指定页码范围 "1-5" "1,3,5" - pages: 指定页码范围 "1-5" "1,3,5"
- preserveLayout: 是否保留布局默认 true - preserveLayout: 是否保留布局默认 true
- method: 强制指定提取器跳过自动 fallback 当前支持
* "auto"默认 走完整 fallback
* "tika" 直接用 Apache Tika 抽取适合 Windows 上没装
Poppler/Python 的环境或验证 Tika 单独是否能解开
如果提取失败会返回详细的尝试过程和错误信息 如果提取失败会返回详细的尝试过程和错误信息
""") """)
public String extract_document_text( public String extract_document_text(
@ToolParam(description = "文件的绝对路径或相对路径") String filePath, @ToolParam(description = "文件的绝对路径或相对路径") String filePath,
@ToolParam(description = "可选参数 JSON如 {\"pages\": \"1-5\", \"preserveLayout\": true}", required = false) String options) { @ToolParam(description = "可选参数 JSON如 {\"pages\": \"1-5\", \"method\": \"tika\"}", required = false) String options) {
JSONObject result = new JSONObject(); JSONObject result = new JSONObject();
result.set("filePath", filePath); result.set("filePath", filePath);
@ -75,6 +81,38 @@ public class DocumentExtractTool {
String mimeType = detectMimeType(path); String mimeType = detectMimeType(path);
result.set("mimeType", mimeType); result.set("mimeType", mimeType);
// RFC-051: method=tika 短路 跳过整条 fallback 直接调 Tika
// 用于1) 测试 Tika 集成是否健康2) 用户明知系统命令不可用想免去
// 那一长串失败日志的场景结果里仍然带 attempts 数组告知"应用户要求跳过自动链"
String forcedMethod = extractOption(options, "method");
if ("tika".equalsIgnoreCase(forcedMethod)) {
long t = System.currentTimeMillis();
String text = TikaExtractor.extract(path);
attempts.add("user-forced method=tika: skipped automatic fallback chain");
if (text == null || text.isBlank()) {
attempts.add("tika: 失败或不可用 (" + (System.currentTimeMillis() - t) + "ms)");
return errorResult(filePath, "Tika 抽取无文本(可能格式不支持或文件损坏)", attempts);
}
attempts.add("tika: 成功 (" + (System.currentTimeMillis() - t) + "ms)");
String capped = text;
boolean trunc = false;
if (capped.length() > MAX_OUTPUT_LENGTH) {
capped = capped.substring(0, MAX_OUTPUT_LENGTH)
+ "\n\n... [内容已截断,总长度: " + text.length() + " 字符]";
trunc = true;
}
result.set("text", capped);
result.set("method", "tika");
result.set("pages", estimatePages(text));
result.set("attempts", attempts);
result.set("truncated", trunc);
result.set("success", true);
log.info("[DocumentExtract] {} 使用 method=tika 强制提取成功,{} 字符",
filePath, text.length());
return JSONUtil.toJsonPrettyStr(result);
}
// 根据类型选择提取器 // 根据类型选择提取器
ExtractedContent content; ExtractedContent content;
if (mimeType.contains("pdf")) { if (mimeType.contains("pdf")) {