feat: support RTF knowledge uploads

This commit is contained in:
key
2026-08-03 01:49:48 +08:00
parent a07bbcca07
commit a275f98fad
8 changed files with 42 additions and 7 deletions
@@ -817,7 +817,7 @@ public class AihrSopSeedService {
}
String fileName = AihrMultipartFiles.sanitizeFileName(file.getOriginalFilename(), "knowledge.txt");
if (!supportedFile(fileName)) {
throw new ServiceException("仅支持 txt/md/markdown/pdf/doc/docx/xls/xlsx/ppt/pptx/图片文件");
throw new ServiceException("仅支持 txt/md/markdown/rtf/pdf/doc/docx/xls/xlsx/ppt/pptx/图片文件");
}
if (file.getSize() > 100 * 1024 * 1024) {
throw new ServiceException("文件不能超过 100MB");
@@ -2588,6 +2588,7 @@ public class AihrSopSeedService {
case "xls", "xlsx" -> "Excel";
case "ppt", "pptx" -> "PPT";
case "pdf" -> "PDF";
case "rtf" -> "RTF";
case "txt", "md", "markdown" -> "Text";
case "jpg", "jpeg", "png", "gif", "webp", "bmp" -> "图片";
case "mp4", "mov", "avi", "mkv", "webm", "m4v" -> "视频";
@@ -4894,6 +4895,7 @@ public class AihrSopSeedService {
return textFile(lower)
|| imageFile(lower)
|| AihrVideoService.videoFile(lower)
|| lower.endsWith(".rtf")
|| lower.endsWith(".pdf")
|| lower.endsWith(".doc")
|| lower.endsWith(".docx")
@@ -121,7 +121,7 @@ public class AihrUploadQueueService {
String fileName = sanitizeFileName(file.getOriginalFilename());
boolean archive = isZip(fileName);
if (!archive && !AihrSopSeedService.supportedFile(fileName)) {
throw new ServiceException("仅支持 txt/md/markdown/pdf/doc/docx/xls/xlsx/ppt/pptx/图片/视频/zip文件");
throw new ServiceException("仅支持 txt/md/markdown/rtf/pdf/doc/docx/xls/xlsx/ppt/pptx/图片/视频/zip文件");
}
if (file.getSize() > MAX_FILE_BYTES) {
throw new ServiceException(archive
@@ -44,6 +44,20 @@ class TikaKnowledgeDocumentParserTest {
);
}
@Test
void parsesRichTextFormatDocuments() {
KnowledgeDocumentParser parser = new TikaKnowledgeDocumentParser();
byte[] rtf = ("{\\rtf1 \\ansi \\deff0 {\\fonttbl {\\f0 Times New Roman;}}"
+ "\\f0 \\fs24 Interview notes: resident service experience.\\par}")
.getBytes(StandardCharsets.US_ASCII);
ParsedDocument document = parser.parse("interview.rtf", "application/rtf", rtf);
assertEquals("application/rtf", document.mimeType());
assertTrue(document.text().contains("Interview notes"));
assertFalse(document.segments().isEmpty());
}
@Test
void rejectsInvalidChunkSettings() {
ParsedDocument document = new ParsedDocument("有效内容", "text/plain", java.util.Map.of());
@@ -44,6 +44,25 @@ class AihrUploadQueueServiceTest {
assertEquals(500L * 1024 * 1024, field.getLong(null));
}
@Test
void supportsRtfAtTopLevelAndInsideZip() throws Exception {
assertTrue(AihrSopSeedService.supportedFile("interview.rtf"));
Path staging = Files.createDirectories(tempDir.resolve("rtf-staging"));
Path archive = tempDir.resolve("rtf.zip");
writeZip(archive, java.nio.charset.StandardCharsets.UTF_8, "notes/interview.rtf");
JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class);
when(jdbcTemplate.update(anyString(), any(Object[].class))).thenReturn(1);
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
try {
AihrUploadQueueService service = new AihrUploadQueueService(null, null, jdbcTemplate, executor, staging.toString());
assertEquals(1, expandArchive(service, itemRow(archive)));
} finally {
executor.shutdownNow();
}
}
@Test
void expandsLegacyGbkZipAtomicallyAndKeepsDuplicateEntries() throws Exception {
Path staging = Files.createDirectories(tempDir.resolve("staging"));