diff --git a/base/src/main/java/com/tinyengine/it/common/utils/ImageThumbnailGenerator.java b/base/src/main/java/com/tinyengine/it/common/utils/ImageThumbnailGenerator.java index ab8adad9..12724f3b 100644 --- a/base/src/main/java/com/tinyengine/it/common/utils/ImageThumbnailGenerator.java +++ b/base/src/main/java/com/tinyengine/it/common/utils/ImageThumbnailGenerator.java @@ -33,6 +33,7 @@ import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -149,7 +150,7 @@ private static ImageInputInfo parseImageInput(String imageInput) { // 检查是否为数据URI格式 Matcher matcher = DATA_URI_PATTERN.matcher(trimmed); if (matcher.matches()) { - String mimeType = matcher.group(1).toLowerCase(); + String mimeType = matcher.group(1).toLowerCase(Locale.ROOT); String cleanBase64 = matcher.group(2); String format = mimeTypeToFormat(mimeType); @@ -173,7 +174,7 @@ public static String detectFormatFromBase64(String base64Input) { // 先检查是否为SVG String content = new String(imageBytes, 0, Math.min(1000, imageBytes.length), - StandardCharsets.UTF_8).trim().toLowerCase(); + StandardCharsets.UTF_8).trim().toLowerCase(Locale.ROOT); if (content.contains(" resourceUpload(@RequestParam MultipartFile file) throws // 获取文件的原始名称 String fileName = StringUtils.cleanPath(java.util.Optional.ofNullable(file.getOriginalFilename()).orElse("image")); - if(!ImageThumbnailGenerator.validateByImageIO(file)){ + if (!ImageThumbnailGenerator.validateByImageIO(file)) { return Result.failed(ExceptionEnum.CM325); } - if(fileName.contains("..")) { + if (fileName.contains("..")) { return Result.failed(ExceptionEnum.CM325); } // 将文件转为 Base64 diff --git a/base/src/main/java/com/tinyengine/it/controller/VectorStorageController.java b/base/src/main/java/com/tinyengine/it/controller/VectorStorageController.java index ee57e43b..0d56f894 100644 --- a/base/src/main/java/com/tinyengine/it/controller/VectorStorageController.java +++ b/base/src/main/java/com/tinyengine/it/controller/VectorStorageController.java @@ -221,7 +221,7 @@ public Result deleteByFilePath(@RequestParam String filePath, @Req @DeleteMapping("/vector-storage/batch/{collection}") public Result deleteMultipleFiles(@PathVariable String collection, @RequestBody @NotEmpty List<@NotEmpty String> filePaths) { - BatchDeleteResult result = vectorStorageService.deleteMultipleFiles(filePaths,collection); + BatchDeleteResult result = vectorStorageService.deleteMultipleFiles(filePaths, collection); return Result.success(result); } diff --git a/base/src/main/java/com/tinyengine/it/mapper/ResourceGroupResourceMapper.java b/base/src/main/java/com/tinyengine/it/mapper/ResourceGroupResourceMapper.java index d563c5a9..f8a77ad2 100644 --- a/base/src/main/java/com/tinyengine/it/mapper/ResourceGroupResourceMapper.java +++ b/base/src/main/java/com/tinyengine/it/mapper/ResourceGroupResourceMapper.java @@ -14,7 +14,6 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.tinyengine.it.model.entity.ResourceGroupResource; -import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Select; import java.util.List; diff --git a/base/src/main/java/com/tinyengine/it/rag/entity/EmbeddingMatchDto.java b/base/src/main/java/com/tinyengine/it/rag/entity/EmbeddingMatchDto.java index 473ab6d9..5ccadc97 100644 --- a/base/src/main/java/com/tinyengine/it/rag/entity/EmbeddingMatchDto.java +++ b/base/src/main/java/com/tinyengine/it/rag/entity/EmbeddingMatchDto.java @@ -83,9 +83,15 @@ public static EmbeddingMatchDto from(EmbeddingMatch match) { dto.setSource(source); // 将常用字段也放入 metadata map - if (collection != null) metadataMap.put("collection", collection); - if (documentSetId != null) metadataMap.put("documentSetId", documentSetId); - if (source != null) metadataMap.put("source", source); + if (collection != null) { + metadataMap.put("collection", collection); + } + if (documentSetId != null) { + metadataMap.put("documentSetId", documentSetId); + } + if (source != null) { + metadataMap.put("source", source); + } dto.setMetadata(metadataMap); } else { diff --git a/base/src/main/java/com/tinyengine/it/rag/entity/VectorDocument.java b/base/src/main/java/com/tinyengine/it/rag/entity/VectorDocument.java index e44c018a..1096ef11 100644 --- a/base/src/main/java/com/tinyengine/it/rag/entity/VectorDocument.java +++ b/base/src/main/java/com/tinyengine/it/rag/entity/VectorDocument.java @@ -75,6 +75,7 @@ public VectorDocument(int successCount, int errorCount, String documentSetId, St this.processingTime = 0L; this.status = errorCount == 0 ? "SUCCESS" : "PARTIAL_SUCCESS"; } + /** * 获取总处理数量 */ diff --git a/base/src/main/java/com/tinyengine/it/rag/service/StorageService.java b/base/src/main/java/com/tinyengine/it/rag/service/StorageService.java index 818b9abf..acdb725e 100644 --- a/base/src/main/java/com/tinyengine/it/rag/service/StorageService.java +++ b/base/src/main/java/com/tinyengine/it/rag/service/StorageService.java @@ -43,9 +43,11 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; +import java.util.stream.Stream; /** * 存储服务 - 支持动态集合管理 @@ -92,7 +94,7 @@ public class StorageService { * Check if file format is supported */ private boolean isSupportedFormat(Path filePath) { - String fileName = filePath.getFileName().toString().toLowerCase(); + String fileName = filePath.getFileName().toString().toLowerCase(Locale.ROOT); return SUPPORTED_FORMATS.stream().anyMatch(format -> fileName.endsWith(format)); } @@ -166,30 +168,25 @@ public VectorDocument autoAddFolderToKnowledgeBase() { * 扫描文件夹中所有支持的文件 */ private List scanSupportedFiles(String folderPath) { - List supportedFiles = new ArrayList<>(); - - try { - Path folder = Paths.get(folderPath); - // 使用 Files.walk 递归扫描子文件夹 - Files.walk(folder) - .filter(Files::isRegularFile) - .filter(this::isSupportedFormat) - .forEach(filePath -> { - supportedFiles.add(filePath.toString()); - log.debug("Found supported file: {}", filePath); - }); - - supportedFiles.sort(String::compareTo); + Path folder = Paths.get(folderPath); + + try (Stream pathStream = Files.walk(folder)) { + return pathStream + .filter(Files::isRegularFile) + .filter(this::isSupportedFormat) + .peek(filePath -> log.debug("Found supported file: {}", filePath)) + .map(Path::toString) + .sorted() + .collect(Collectors.toList()); } catch (IOException e) { log.error("Failed to scan folder: {}", folderPath, e); throw new ServiceException(ExceptionEnum.CM333.getResultCode(), ExceptionEnum.CM333.getResultMsg()); } - - return supportedFiles; } + /** * 根据文档路径和自定义集合确定目标集合 */ @@ -205,7 +202,7 @@ private String determineCollectionName(String filePath, String customCollection) // 根据文件路径自动判断集合 if (filePath != null) { - String lowerPath = filePath.toLowerCase(); + String lowerPath = filePath.toLowerCase(Locale.ROOT); // 如果路径包含特定关键词,映射到对应集合 for (Map.Entry entry : collectionMapping.entrySet()) { if (lowerPath.contains(entry.getKey())) { @@ -223,9 +220,11 @@ private String determineCollectionName(String filePath, String customCollection) * 检查文件格式是否支持 */ private boolean isSupportedFormat(String filePath) { - if (filePath == null) return false; + if (filePath == null) { + return false; + } - String lowerPath = filePath.toLowerCase(); + String lowerPath = filePath.toLowerCase(Locale.ROOT); return SUPPORTED_FORMATS.stream().anyMatch(lowerPath::endsWith); } @@ -233,9 +232,11 @@ private boolean isSupportedFormat(String filePath) { * 检查是否为文本格式 */ private boolean isTextFormat(String filePath) { - if (filePath == null) return false; + if (filePath == null) { + return false; + } - String lowerPath = filePath.toLowerCase(); + String lowerPath = filePath.toLowerCase(Locale.ROOT); return TEXT_FORMATS.stream().anyMatch(lowerPath::endsWith); } @@ -243,27 +244,65 @@ private boolean isTextFormat(String filePath) { * 获取文件格式描述 */ private String getFileFormatDescription(String filePath) { - if (filePath == null) return "unknown"; - - String lowerPath = filePath.toLowerCase(); - if (lowerPath.endsWith(".pdf")) return "PDF Document"; - if (lowerPath.endsWith(".sql")) return "SQL Script"; - if (lowerPath.endsWith(".java")) return "Java Source"; - if (lowerPath.endsWith(".py")) return "Python Script"; - if (lowerPath.endsWith(".js")) return "JavaScript"; - if (lowerPath.endsWith(".ts")) return "TypeScript"; - if (lowerPath.endsWith(".html")) return "HTML Document"; - if (lowerPath.endsWith(".css")) return "CSS Stylesheet"; - if (lowerPath.endsWith(".xml")) return "XML Document"; - if (lowerPath.endsWith(".json")) return "JSON Data"; - if (lowerPath.endsWith(".yaml") || lowerPath.endsWith(".yml")) return "YAML Configuration"; - if (lowerPath.endsWith(".properties")) return "Properties File"; - if (lowerPath.endsWith(".sh")) return "Shell Script"; - if (lowerPath.endsWith(".bat") || lowerPath.endsWith(".cmd")) return "Batch File"; - if (lowerPath.endsWith(".c")) return "C Source"; - if (lowerPath.endsWith(".cpp") || lowerPath.endsWith(".h") || lowerPath.endsWith(".hpp")) return "C++ Source"; - if (lowerPath.endsWith(".txt")) return "Text Document"; - if (lowerPath.endsWith(".md")) return "Markdown Document"; + if (filePath == null) { + return "unknown"; + } + + String lowerPath = filePath.toLowerCase(Locale.ROOT); + if (lowerPath.endsWith(".pdf")) { + return "PDF Document"; + } + if (lowerPath.endsWith(".sql")) { + return "SQL Script"; + } + if (lowerPath.endsWith(".java")) { + return "Java Source"; + } + if (lowerPath.endsWith(".py")) { + return "Python Script"; + } + if (lowerPath.endsWith(".js")) { + return "JavaScript"; + } + if (lowerPath.endsWith(".ts")) { + return "TypeScript"; + } + if (lowerPath.endsWith(".html")) { + return "HTML Document"; + } + if (lowerPath.endsWith(".css")) { + return "CSS Stylesheet"; + } + if (lowerPath.endsWith(".xml")) { + return "XML Document"; + } + if (lowerPath.endsWith(".json")) { + return "JSON Data"; + } + if (lowerPath.endsWith(".yaml") || lowerPath.endsWith(".yml")) { + return "YAML Configuration"; + } + if (lowerPath.endsWith(".properties")) { + return "Properties File"; + } + if (lowerPath.endsWith(".sh")) { + return "Shell Script"; + } + if (lowerPath.endsWith(".bat") || lowerPath.endsWith(".cmd")) { + return "Batch File"; + } + if (lowerPath.endsWith(".c")) { + return "C Source"; + } + if (lowerPath.endsWith(".cpp") || lowerPath.endsWith(".h") || lowerPath.endsWith(".hpp")) { + return "C++ Source"; + } + if (lowerPath.endsWith(".txt")) { + return "Text Document"; + } + if (lowerPath.endsWith(".md")) { + return "Markdown Document"; + } return "Unknown Format"; } @@ -339,7 +378,7 @@ private List loadDocuments(List documentPaths, String document Path filePath = Paths.get(path); Document document; - if (path.toLowerCase().endsWith(".pdf")) { + if (path.toLowerCase(Locale.ROOT).endsWith(".pdf")) { // PDF 文件使用 PDF 解析器 ApachePdfBoxDocumentParser pdfParser = new ApachePdfBoxDocumentParser(); document = FileSystemDocumentLoader.loadDocument(filePath, pdfParser); @@ -666,6 +705,7 @@ public BatchDeleteResult deleteMultipleFiles(List filePaths, String coll throw new ServiceException(ExceptionEnum.CM332.getResultCode(), "Batch delete files failed"); } } + /** * 获取所有集合及其包含的文档路径 */ diff --git a/base/src/main/java/com/tinyengine/it/service/app/impl/v1/AiChatV1ServiceImpl.java b/base/src/main/java/com/tinyengine/it/service/app/impl/v1/AiChatV1ServiceImpl.java index df546898..5e9c0574 100644 --- a/base/src/main/java/com/tinyengine/it/service/app/impl/v1/AiChatV1ServiceImpl.java +++ b/base/src/main/java/com/tinyengine/it/service/app/impl/v1/AiChatV1ServiceImpl.java @@ -88,7 +88,7 @@ private String normalizeApiUrl(String baseUrl) { if (baseUrl.contains("v1")) { return ensureUrlProtocol(baseUrl) + "/chat/completions"; - } else { + } else { return ensureUrlProtocol(baseUrl) + "/v1/chat/completions"; } } @@ -114,40 +114,40 @@ private String buildRequestBody(ChatRequest request) { body.put("max_tokens", request.getMaxTokens()); } body.put("temperature", request.getTemperature()); - if(request.getTemperature() != null) { + if (request.getTemperature() != null) { body.put("temperature", request.getTemperature()); } - if(request.getSearchOptions() != null) { + if (request.getSearchOptions() != null) { body.put("stream_options", request.getSearchOptions()); } - if(request.getPresencePenalty() != null) { + if (request.getPresencePenalty() != null) { body.put("presence_penalty", request.getPresencePenalty()); } - if(request.getResponseFormat() != null) { + if (request.getResponseFormat() != null) { body.put("response_format", request.getResponseFormat()); } - if(request.getMaxInputTokens() != null) { + if (request.getMaxInputTokens() != null) { body.put("max_input_tokens", request.getMaxInputTokens()); } - if(request.getMaxInputTokens() != null) { + if (request.getMaxInputTokens() != null) { body.put("vl_high_resolution_images", request.getVlHighResolutionImages()); } - if(request.getEnableThinking() != null) { + if (request.getEnableThinking() != null) { body.put("enable_thinking", request.getEnableThinking()); } - if(request.getToolChoice() != null) { + if (request.getToolChoice() != null) { body.put("tool_choice", request.getToolChoice()); } - if(request.getStop() != null) { + if (request.getStop() != null) { body.put("stop", request.getStop()); } - if(request.getParallelToolCalls() != null) { + if (request.getParallelToolCalls() != null) { body.put("parallel_tool_calls", request.getParallelToolCalls()); } - if(request.getEnableSearch() != null) { + if (request.getEnableSearch() != null) { body.put("enable_search", request.getEnableSearch()); } - if(request.getFrequencyPenalty() != null) { + if (request.getFrequencyPenalty() != null) { body.put("frequency_penalty", request.getFrequencyPenalty()); } @@ -186,8 +186,9 @@ private StreamingResponseBody processStreamResponse(HttpRequest.Builder requestB String errorEvent = "data: {\"error\": \"" + e.getMessage() + "\"}\n\n"; outputStream.write(errorEvent.getBytes(StandardCharsets.UTF_8)); outputStream.flush(); - } catch (IOException ignored) { - + } catch (IOException ioException) { + throw new IOException("API请求失败,且无法发送错误信息: " + e.getMessage() + + " (IO错误: " + ioException.getMessage() + ")", e); } } }; diff --git a/base/src/main/java/com/tinyengine/it/service/material/impl/BlockServiceImpl.java b/base/src/main/java/com/tinyengine/it/service/material/impl/BlockServiceImpl.java index 24161939..e22361ee 100644 --- a/base/src/main/java/com/tinyengine/it/service/material/impl/BlockServiceImpl.java +++ b/base/src/main/java/com/tinyengine/it/service/material/impl/BlockServiceImpl.java @@ -606,13 +606,13 @@ public IPage findBlocksByConditionPagetion(Map request) { public List getUsers(List blocksList) { Set userSet = new HashSet<>(); List users = new ArrayList<>(); - if(blocksList.isEmpty()) { + if (blocksList.isEmpty()) { return users; } // 提取 createdBy 列表中的唯一值 blocksList.forEach(item -> { if (item.getCreatedBy() != null && !userSet.contains(item.getCreatedBy())) { - userSet.add(String.valueOf(item.getCreatedBy())); + userSet.add(item.getCreatedBy()); } }); diff --git a/base/src/test/java/com/tinyengine/it/controller/AiChatControllerTest.java b/base/src/test/java/com/tinyengine/it/controller/AiChatControllerTest.java index fde49572..a0cd9755 100644 --- a/base/src/test/java/com/tinyengine/it/controller/AiChatControllerTest.java +++ b/base/src/test/java/com/tinyengine/it/controller/AiChatControllerTest.java @@ -12,23 +12,9 @@ package com.tinyengine.it.controller; -import static org.mockito.Mockito.when; - -import com.tinyengine.it.common.base.Result; -import com.tinyengine.it.model.dto.AiParam; -import com.tinyengine.it.model.dto.ChatRequest; -import com.tinyengine.it.service.app.AiChatService; - -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import java.util.HashMap; -import java.util.Map; - /** * test case *