Commit f2e11f8f5077e666818bcd7bb1e0cfd945c686c8
1 parent
c357bb83
添加向量库
Showing
11 changed files
with
310 additions
and
121 deletions
src/main/java/com/xly/milvus/service/AiGlobalAgentQuestionSqlEmitterService.java
| ... | ... | @@ -12,7 +12,7 @@ public interface AiGlobalAgentQuestionSqlEmitterService { |
| 12 | 12 | * @return void |
| 13 | 13 | * @Description 插入向量库 |
| 14 | 14 | **/ |
| 15 | - void addAiGlobalAgentQuestionSqlEmitter(String sKey,Map<String,Object> data,String sQuestion,String sSqlContent,String cachType,String collectionName); | |
| 15 | + void addAiGlobalAgentQuestionSqlEmitter(String sKey,Map<String,Object> data,String sQuestion,String sSqlContent,String cachType,String collectionName,Boolean isInit); | |
| 16 | 16 | |
| 17 | 17 | |
| 18 | 18 | Map<String, Object> queryAiGlobalAgentQuestionSqlEmitter(String searchText, String collectionName); | ... | ... |
src/main/java/com/xly/milvus/service/MilvusService.java
| ... | ... | @@ -22,6 +22,24 @@ public interface MilvusService { |
| 22 | 22 | |
| 23 | 23 | TTSResponseDTO initDataToMilvus(Map<String, Object> reqMap); |
| 24 | 24 | |
| 25 | + /*** | |
| 26 | + * @Author 钱豹 | |
| 27 | + * @Date 9:00 2026/4/1 | |
| 28 | + * @Param [reqMap] | |
| 29 | + * @return com.xly.tts.bean.TTSResponseDTO | |
| 30 | + * @Description 客户问题库转入全局问题库 | |
| 31 | + **/ | |
| 32 | + TTSResponseDTO addGlobalAgentQuestion(Map<String, Object> reqMap); | |
| 33 | + | |
| 34 | + /*** | |
| 35 | + * @Author 钱豹 | |
| 36 | + * @Date 9:28 2026/4/1 | |
| 37 | + * @Param [reqMap] | |
| 38 | + * @return com.xly.tts.bean.TTSResponseDTO | |
| 39 | + * @Description 初始化全局SQL进入向量库 | |
| 40 | + **/ | |
| 41 | + TTSResponseDTO initGlobalAgentQuestion(Map<String, Object> reqMap); | |
| 42 | + | |
| 25 | 43 | |
| 26 | 44 | /** |
| 27 | 45 | * 创建集合(如果不存在) | ... | ... |
src/main/java/com/xly/milvus/service/impl/AiGlobalAgentQuestionSqlEmitterServiceImpl.java
| ... | ... | @@ -58,7 +58,7 @@ public class AiGlobalAgentQuestionSqlEmitterServiceImpl implements AiGlobalAgent |
| 58 | 58 | * @Description 插入数据 |
| 59 | 59 | **/ |
| 60 | 60 | @Override |
| 61 | - public void addAiGlobalAgentQuestionSqlEmitter(String sKey,Map<String,Object> data,String sQuestion,String sSqlContent,String cachType,String collectionName) { | |
| 61 | + public void addAiGlobalAgentQuestionSqlEmitter(String sKey,Map<String,Object> data,String sQuestion,String sSqlContent,String cachType,String collectionName,Boolean isInit) { | |
| 62 | 62 | // 向量化 |
| 63 | 63 | List<Float> vector = vectorizationService.textToVector(sKey); |
| 64 | 64 | |
| ... | ... | @@ -83,10 +83,12 @@ public class AiGlobalAgentQuestionSqlEmitterServiceImpl implements AiGlobalAgent |
| 83 | 83 | .build(); |
| 84 | 84 | |
| 85 | 85 | InsertResp insertResp = milvusClient.insert(insertReq); |
| 86 | - //调用数据库插入数据库 | |
| 87 | - Map<String, Object> searMap = dynamicExeDbService.getDoProMap(sProName, data); | |
| 88 | - dynamicExeDbService.getCallPro(searMap, sProName); | |
| 89 | - | |
| 86 | + //是否初始化。初始化不需要插入到数据库 | |
| 87 | + if(!isInit){ | |
| 88 | + //调用数据库插入数据库 | |
| 89 | + Map<String, Object> searMap = dynamicExeDbService.getDoProMap(sProName, data); | |
| 90 | + dynamicExeDbService.getCallPro(searMap, sProName); | |
| 91 | + } | |
| 90 | 92 | System.out.println("成功插入 " + insertResp.getInsertCnt() + " 条数据"); |
| 91 | 93 | System.out.println(" - 数据预览:"); |
| 92 | 94 | } | ... | ... |
src/main/java/com/xly/milvus/service/impl/MilvusServiceImpl.java
| ... | ... | @@ -10,6 +10,7 @@ import com.google.common.reflect.TypeToken; |
| 10 | 10 | import com.google.gson.Gson; |
| 11 | 11 | import com.google.gson.JsonArray; |
| 12 | 12 | import com.google.gson.JsonObject; |
| 13 | +import com.xly.milvus.service.AiGlobalAgentQuestionSqlEmitterService; | |
| 13 | 14 | import com.xly.milvus.service.MilvusService; |
| 14 | 15 | import com.xly.milvus.service.VectorizationService; |
| 15 | 16 | import com.xly.milvus.util.MapToJsonConverter; |
| ... | ... | @@ -60,6 +61,7 @@ public class MilvusServiceImpl implements MilvusService { |
| 60 | 61 | private final MilvusClientV2 milvusClient; |
| 61 | 62 | private final VectorizationService vectorizationService; |
| 62 | 63 | private final DynamicExeDbService dynamicExeDbService; |
| 64 | + private final AiGlobalAgentQuestionSqlEmitterService aiGlobalAgentQuestionSqlEmitterService; | |
| 63 | 65 | private static final long NULL_TIMESTAMP = -1L; |
| 64 | 66 | // 日期格式常量 |
| 65 | 67 | private static final DateTimeFormatter ISO_FORMATTER = |
| ... | ... | @@ -128,6 +130,80 @@ public class MilvusServiceImpl implements MilvusService { |
| 128 | 130 | .build(); |
| 129 | 131 | } |
| 130 | 132 | |
| 133 | + /*** | |
| 134 | + * @Author 钱豹 | |
| 135 | + * @Date 9:20 2026/4/1 | |
| 136 | + * @Param [reqMap] | |
| 137 | + * @return com.xly.tts.bean.TTSResponseDTO | |
| 138 | + * @Description 用户问题列表转换成全局问题 | |
| 139 | + **/ | |
| 140 | + @Override | |
| 141 | + public TTSResponseDTO addGlobalAgentQuestion(Map<String, Object> reqMap) { | |
| 142 | + if(ObjectUtil.isEmpty(reqMap.get("sRowData"))){ | |
| 143 | + return TTSResponseDTO.builder() | |
| 144 | + .code(-1) | |
| 145 | + .message("请选择数据") | |
| 146 | + .build(); | |
| 147 | + } | |
| 148 | + //遍历数据 | |
| 149 | + List<Map<String,Object>> data = (List<Map<String, Object>>) reqMap.get("sRowData"); | |
| 150 | + if(ObjectUtil.isEmpty(data)){ | |
| 151 | + return TTSResponseDTO.builder() | |
| 152 | + .code(-1) | |
| 153 | + .message("请选择数据") | |
| 154 | + .build(); | |
| 155 | + } | |
| 156 | + StringBuffer sb = new StringBuffer(); | |
| 157 | + data.forEach(one->{ | |
| 158 | + //查询向量库是否存在 | |
| 159 | + String sSceneId = one.get("sSceneId").toString(); | |
| 160 | + String sMethodId = one.get("sMethodId").toString(); | |
| 161 | + String sUserInput = one.get("sUserInput").toString(); | |
| 162 | + String sSqlContent = one.get("sSqlContent").toString(); | |
| 163 | + String searchText = sSceneId+"_"+sMethodId+"_"+sUserInput; | |
| 164 | + if(ObjectUtil.isNotEmpty(sUserInput)){ | |
| 165 | + //根据问题查询向量库 | |
| 166 | + Map<String,Object> serMap = aiGlobalAgentQuestionSqlEmitterService.queryAiGlobalAgentQuestionSqlEmitter(searchText, "ai_global_agent_question_sql"); | |
| 167 | + if(ObjectUtil.isNotEmpty(serMap)){ | |
| 168 | + aiGlobalAgentQuestionSqlEmitterService.addAiGlobalAgentQuestionSqlEmitter(searchText,one,sUserInput,sSqlContent,"MYSQL","ai_global_agent_question_sql",false); | |
| 169 | + }else{ | |
| 170 | + sb.append(sUserInput).append("已经存在").append("\n"); | |
| 171 | + } | |
| 172 | + //更新数据是否是全局问题,等待朱总确定是否需要 | |
| 173 | + | |
| 174 | + | |
| 175 | + } | |
| 176 | + }); | |
| 177 | + if(ObjectUtil.isEmpty(sb)){ | |
| 178 | + sb.append("操作成功"); | |
| 179 | + } | |
| 180 | + return TTSResponseDTO.builder() | |
| 181 | + .code(200) | |
| 182 | + .message(sb.toString()) | |
| 183 | + .build(); | |
| 184 | + } | |
| 185 | + | |
| 186 | + @Override | |
| 187 | + public TTSResponseDTO initGlobalAgentQuestion(Map<String, Object> reqMap) { | |
| 188 | + //全局问题初始化 | |
| 189 | + List<Map<String,Object>> data = getGlobalAgentQuestion(); | |
| 190 | + data.forEach(one->{ | |
| 191 | + //查询向量库是否存在 | |
| 192 | + String sSceneId = one.get("sSceneId").toString(); | |
| 193 | + String sMethodId = one.get("sMethodId").toString(); | |
| 194 | + String sUserInput = one.get("sUserInput").toString(); | |
| 195 | + String sSqlContent = one.get("sSqlContent").toString(); | |
| 196 | + String searchText = sSceneId+"_"+sMethodId+"_"+sUserInput; | |
| 197 | + if(ObjectUtil.isNotEmpty(sUserInput)){ | |
| 198 | + aiGlobalAgentQuestionSqlEmitterService.addAiGlobalAgentQuestionSqlEmitter(searchText,one,sUserInput,sSqlContent,"MYSQL","ai_global_agent_question_sql",true); | |
| 199 | + } | |
| 200 | + }); | |
| 201 | + return TTSResponseDTO.builder() | |
| 202 | + .code(200) | |
| 203 | + .message("操作成功") | |
| 204 | + .build(); | |
| 205 | + } | |
| 206 | + | |
| 131 | 207 | public String getUpdateDateUp(String sInputTabelName) { |
| 132 | 208 | Map<String,Object> serDataMap = new HashMap<>(); |
| 133 | 209 | String sSql ="SELECT DATE_FORMAT(tUpdateDate,'%Y-%m-%d %H:%i:%s') AS tUpdateDate FROM ai_milvus_vector_record WHERE sInputTabelName = #{sInputTabelName}"; |
| ... | ... | @@ -139,6 +215,14 @@ public class MilvusServiceImpl implements MilvusService { |
| 139 | 215 | return data.get(0).get("tUpdateDate").toString(); |
| 140 | 216 | } |
| 141 | 217 | |
| 218 | + public List<Map<String,Object>> getGlobalAgentQuestion() { | |
| 219 | + Map<String,Object> serDataMap = new HashMap<>(); | |
| 220 | + String sSql ="SELECT * FROM ai_global_agent_question_sql"; | |
| 221 | + //删除集合全部数据 | |
| 222 | + List<Map<String,Object>> data = this.dynamicExeDbService.findSql(serDataMap,sSql); | |
| 223 | + return data; | |
| 224 | + } | |
| 225 | + | |
| 142 | 226 | /*** |
| 143 | 227 | * @Author 钱豹 |
| 144 | 228 | * @Date 22:24 2026/3/24 | ... | ... |
src/main/java/com/xly/milvus/web/MilvusController.java
| ... | ... | @@ -45,5 +45,31 @@ public class MilvusController { |
| 45 | 45 | return ResponseEntity.ok(responseDTO); |
| 46 | 46 | } |
| 47 | 47 | |
| 48 | + /*** | |
| 49 | + * @Author 钱豹 | |
| 50 | + * @Date 14:32 2026/2/10 | |
| 51 | + * @Param [request] | |
| 52 | + * @return org.springframework.http.ResponseEntity<com.xly.tts.bean.TTSResponseDTO> | |
| 53 | + * @Description 初始化AI所有变量 热启动 | |
| 54 | + **/ | |
| 55 | + @PostMapping("/addGlobalAgentQuestion") | |
| 56 | + public ResponseEntity<TTSResponseDTO> addGlobalAgentQuestion(@RequestBody Map<String,Object> reqMap) { | |
| 57 | + TTSResponseDTO responseDTO = milvusService.addGlobalAgentQuestion(reqMap); | |
| 58 | + return ResponseEntity.ok(responseDTO); | |
| 59 | + } | |
| 60 | + | |
| 61 | + /*** | |
| 62 | + * @Author 钱豹 | |
| 63 | + * @Date 14:32 2026/2/10 | |
| 64 | + * @Param [request] | |
| 65 | + * @return org.springframework.http.ResponseEntity<com.xly.tts.bean.TTSResponseDTO> | |
| 66 | + * @Description 初始化全局SQL | |
| 67 | + **/ | |
| 68 | + @PostMapping("/initGlobalAgentQuestion") | |
| 69 | + public ResponseEntity<TTSResponseDTO> initGlobalAgentQuestion(@RequestBody Map<String,Object> reqMap) { | |
| 70 | + TTSResponseDTO responseDTO = milvusService.initGlobalAgentQuestion(reqMap); | |
| 71 | + return ResponseEntity.ok(responseDTO); | |
| 72 | + } | |
| 73 | + | |
| 48 | 74 | |
| 49 | 75 | } |
| 50 | 76 | \ No newline at end of file | ... | ... |
src/main/java/com/xly/ocr/service/OcrService.java
| 1 | 1 | package com.xly.ocr.service; |
| 2 | 2 | |
| 3 | +import com.xly.ocr.util.OcrUtil; | |
| 4 | +import lombok.extern.slf4j.Slf4j; | |
| 3 | 5 | import net.sourceforge.tess4j.Tesseract; |
| 4 | 6 | import net.sourceforge.tess4j.TesseractException; |
| 5 | 7 | import org.slf4j.Logger; |
| ... | ... | @@ -18,11 +20,16 @@ import java.nio.file.Path; |
| 18 | 20 | import java.util.Arrays; |
| 19 | 21 | import java.util.List; |
| 20 | 22 | |
| 21 | -@Service | |
| 23 | +@Slf4j | |
| 24 | +@Service("ocrService") | |
| 22 | 25 | public class OcrService { |
| 23 | 26 | |
| 24 | 27 | private static final Logger logger = LoggerFactory.getLogger(OcrService.class); |
| 25 | 28 | |
| 29 | + @Value("${ocr.tmpPath}") | |
| 30 | + private String tmpPath; | |
| 31 | + | |
| 32 | + | |
| 26 | 33 | private final Tesseract tesseract; |
| 27 | 34 | |
| 28 | 35 | // 配置参数 |
| ... | ... | @@ -457,28 +464,8 @@ public class OcrService { |
| 457 | 464 | logger.warn("不支持的文件格式: {}", originalFilename); |
| 458 | 465 | return "不支持的文件格式,仅支持: " + String.join(", ", ALLOWED_EXTENSIONS); |
| 459 | 466 | } |
| 460 | - | |
| 461 | - Path tempFile = null; | |
| 462 | - try { | |
| 463 | - // 创建临时文件 | |
| 464 | - String suffix = getFileExtension(originalFilename); | |
| 465 | - tempFile = Files.createTempFile("ocr_", suffix); | |
| 466 | - file.transferTo(tempFile.toFile()); | |
| 467 | - | |
| 468 | - logger.info("临时文件创建成功: {}", tempFile); | |
| 469 | - | |
| 470 | - // 执行 OCR | |
| 471 | - String result = extractText(tempFile.toFile()); | |
| 472 | - | |
| 473 | - return result; | |
| 474 | - | |
| 475 | - } catch (IOException e) { | |
| 476 | - logger.error("文件处理失败: {}", e.getMessage(), e); | |
| 477 | - return "文件处理失败: " + e.getMessage(); | |
| 478 | - } finally { | |
| 479 | - // 清理临时文件 | |
| 480 | - cleanupTempFile(tempFile); | |
| 481 | - } | |
| 467 | + String sText = OcrUtil.ocrFile(file,tmpPath); | |
| 468 | + return sText; | |
| 482 | 469 | } |
| 483 | 470 | |
| 484 | 471 | /** | ... | ... |
src/main/java/com/xly/ocr/test/Test.java renamed to src/main/java/com/xly/ocr/util/OcrUtil.java
| 1 | -package com.xly.ocr.test; | |
| 1 | +package com.xly.ocr.util; | |
| 2 | 2 | |
| 3 | +import cn.hutool.core.io.FileUtil; | |
| 4 | +import cn.hutool.core.util.StrUtil; | |
| 3 | 5 | import com.benjaminwan.ocrlibrary.OcrResult; |
| 4 | 6 | import com.benjaminwan.ocrlibrary.TextBlock; |
| 5 | 7 | import io.github.mymonstercat.Model; |
| 6 | 8 | import io.github.mymonstercat.ocr.InferenceEngine; |
| 7 | 9 | import io.github.mymonstercat.ocr.config.ParamConfig; |
| 10 | +import lombok.extern.slf4j.Slf4j; | |
| 11 | +import org.springframework.web.multipart.MultipartFile; | |
| 8 | 12 | |
| 9 | 13 | import javax.imageio.ImageIO; |
| 10 | 14 | import java.awt.*; |
| ... | ... | @@ -13,7 +17,8 @@ import java.io.File; |
| 13 | 17 | import java.io.IOException; |
| 14 | 18 | import java.util.List; |
| 15 | 19 | |
| 16 | -public class Test { | |
| 20 | +@Slf4j | |
| 21 | +public class OcrUtil { | |
| 17 | 22 | |
| 18 | 23 | static { |
| 19 | 24 | try { |
| ... | ... | @@ -35,71 +40,64 @@ public class Test { |
| 35 | 40 | } |
| 36 | 41 | } |
| 37 | 42 | |
| 38 | - public static void main(String[] args) { | |
| 43 | + public static String ocrFile(MultipartFile imageFile, String sTmpPath){ | |
| 44 | + String processedImagePath = StrUtil.EMPTY; | |
| 39 | 45 | try { |
| 40 | - System.out.println("OCR 程序开始执行..."); | |
| 41 | - | |
| 46 | + log.info("OCR 程序开始执行..."); | |
| 42 | 47 | // 1. 初始化引擎(使用 v4 模型) |
| 43 | - System.out.println("正在初始化 OCR 引擎 (PP-OCRv4)..."); | |
| 48 | + log.info("正在初始化 OCR 引擎 (PP-OCRv4)..."); | |
| 44 | 49 | InferenceEngine engine = InferenceEngine.getInstance(Model.ONNX_PPOCR_V4); |
| 45 | - | |
| 46 | 50 | // 2. 创建优化的参数配置 |
| 47 | 51 | ParamConfig config = createOptimizedParamConfig(); |
| 48 | - | |
| 49 | - // 3. 图片路径 | |
| 50 | - String imagePath = "E:/aa/b.jpg"; | |
| 51 | - File imageFile = new File(imagePath); | |
| 52 | - if (!imageFile.exists()) { | |
| 53 | - System.err.println("图片文件不存在: " + imagePath); | |
| 54 | - return; | |
| 55 | - } | |
| 56 | - | |
| 57 | 52 | // 4. 图像预处理(直接处理原图,不保存临时文件) |
| 58 | 53 | System.out.println("正在进行图像预处理..."); |
| 59 | - BufferedImage processedImage = preprocessImage(imageFile); | |
| 60 | - | |
| 54 | + File file = multipartFileToFile(imageFile); | |
| 55 | + BufferedImage processedImage = preprocessImage(file); | |
| 61 | 56 | // 5. 保存预处理后的图片到临时目录 |
| 62 | - String processedImagePath = "D:/temp/ocrJava/processed_" + System.currentTimeMillis() + ".png"; | |
| 57 | + if(!FileUtil.exist(sTmpPath)){ | |
| 58 | + FileUtil.mkdir(sTmpPath); | |
| 59 | + } | |
| 60 | + processedImagePath = sTmpPath+"/processed_" + System.currentTimeMillis() + ".png"; | |
| 63 | 61 | ImageIO.write(processedImage, "png", new File(processedImagePath)); |
| 64 | - System.out.println("预处理图片已保存: " + processedImagePath); | |
| 65 | - | |
| 62 | + log.info("预处理图片已保存: " + processedImagePath); | |
| 66 | 63 | // 6. 执行识别 |
| 67 | - System.out.println("开始识别图片..."); | |
| 64 | + log.info("开始识别图片..."); | |
| 68 | 65 | long startTime = System.currentTimeMillis(); |
| 69 | 66 | OcrResult ocrResult = engine.runOcr(processedImagePath, config); |
| 70 | 67 | long endTime = System.currentTimeMillis(); |
| 71 | - | |
| 72 | 68 | // 7. 输出结果 |
| 73 | 69 | String text = ocrResult.getStrRes().trim(); |
| 74 | - System.out.println("\n=================================="); | |
| 75 | - System.out.println("识别结果:"); | |
| 76 | - System.out.println(text); | |
| 77 | - System.out.println("=================================="); | |
| 78 | - System.out.println("识别耗时: " + (endTime - startTime) + " ms"); | |
| 79 | - | |
| 70 | + log.info("\n=================================="); | |
| 71 | + log.info("识别结果:"); | |
| 72 | + log.info(text); | |
| 73 | + log.info("=================================="); | |
| 74 | + log.info("识别耗时: " + (endTime - startTime) + " ms"); | |
| 80 | 75 | // 8. 输出每个文本块 |
| 81 | - if (ocrResult.getTextBlocks() != null && !ocrResult.getTextBlocks().isEmpty()) { | |
| 82 | - System.out.println("\n文本块详情(共" + ocrResult.getTextBlocks().size() + "块):"); | |
| 83 | - List<TextBlock> textBlocks = ocrResult.getTextBlocks(); | |
| 84 | - for (int i = 0; i < textBlocks.size(); i++) { | |
| 85 | - TextBlock block = textBlocks.get(i); | |
| 86 | - System.out.printf(" 块%d: %s (置信度: %.2f)%n", | |
| 87 | - i + 1, | |
| 88 | - block.getText(), | |
| 89 | - block.getBoxScore() | |
| 90 | - ); | |
| 91 | - } | |
| 92 | - } | |
| 93 | - | |
| 94 | - // 9. 清理临时文件 | |
| 95 | - new File(processedImagePath).delete(); | |
| 76 | +// if (ocrResult.getTextBlocks() != null && !ocrResult.getTextBlocks().isEmpty()) { | |
| 77 | +// System.out.println("\n文本块详情(共" + ocrResult.getTextBlocks().size() + "块):"); | |
| 78 | +// List<TextBlock> textBlocks = ocrResult.getTextBlocks(); | |
| 79 | +// for (int i = 0; i < textBlocks.size(); i++) { | |
| 80 | +// TextBlock block = textBlocks.get(i); | |
| 81 | +// System.out.printf(" 块%d: %s (置信度: %.2f)%n", | |
| 82 | +// i + 1, | |
| 83 | +// block.getText(), | |
| 84 | +// block.getBoxScore() | |
| 85 | +// ); | |
| 86 | +// } | |
| 87 | +// } | |
| 88 | + return text; | |
| 96 | 89 | |
| 97 | 90 | } catch (Exception e) { |
| 98 | 91 | System.err.println("OCR 识别失败: " + e.getMessage()); |
| 99 | 92 | e.printStackTrace(); |
| 93 | + }finally { | |
| 94 | + // 9. 清理临时文件 | |
| 95 | + FileUtil.del(processedImagePath); | |
| 100 | 96 | } |
| 97 | + return StrUtil.EMPTY; | |
| 101 | 98 | } |
| 102 | 99 | |
| 100 | + | |
| 103 | 101 | /** |
| 104 | 102 | * 优化的参数配置 |
| 105 | 103 | */ |
| ... | ... | @@ -142,6 +140,20 @@ public class Test { |
| 142 | 140 | |
| 143 | 141 | return processed; |
| 144 | 142 | } |
| 143 | + /*** | |
| 144 | + * @Author 钱豹 | |
| 145 | + * @Date 11:01 2026/4/1 | |
| 146 | + * @Param [multipartFile] | |
| 147 | + * @return java.io.File | |
| 148 | + * @Description 图片对象转换 | |
| 149 | + **/ | |
| 150 | + public static File multipartFileToFile(MultipartFile multipartFile) throws IOException { | |
| 151 | + // 创建临时文件 | |
| 152 | + File file = File.createTempFile("temp", null); | |
| 153 | + // 将 MultipartFile 的内容传输到 File | |
| 154 | + multipartFile.transferTo(file); | |
| 155 | + return file; | |
| 156 | + } | |
| 145 | 157 | |
| 146 | 158 | /** |
| 147 | 159 | * 调整图片大小 |
| ... | ... | @@ -179,4 +191,69 @@ public class Test { |
| 179 | 191 | } |
| 180 | 192 | return result; |
| 181 | 193 | } |
| 194 | + | |
| 195 | + public static void main(String[] args) { | |
| 196 | + try { | |
| 197 | + System.out.println("OCR 程序开始执行..."); | |
| 198 | + | |
| 199 | + // 1. 初始化引擎(使用 v4 模型) | |
| 200 | + System.out.println("正在初始化 OCR 引擎 (PP-OCRv4)..."); | |
| 201 | + InferenceEngine engine = InferenceEngine.getInstance(Model.ONNX_PPOCR_V4); | |
| 202 | + | |
| 203 | + // 2. 创建优化的参数配置 | |
| 204 | + ParamConfig config = createOptimizedParamConfig(); | |
| 205 | + | |
| 206 | + // 3. 图片路径 | |
| 207 | + String imagePath = "E:/aa/b.jpg"; | |
| 208 | + File imageFile = new File(imagePath); | |
| 209 | + if (!imageFile.exists()) { | |
| 210 | + System.err.println("图片文件不存在: " + imagePath); | |
| 211 | + return; | |
| 212 | + } | |
| 213 | + | |
| 214 | + // 4. 图像预处理(直接处理原图,不保存临时文件) | |
| 215 | + System.out.println("正在进行图像预处理..."); | |
| 216 | + BufferedImage processedImage = preprocessImage(imageFile); | |
| 217 | + | |
| 218 | + // 5. 保存预处理后的图片到临时目录 | |
| 219 | + String processedImagePath = "D:/temp/ocrJava/processed_" + System.currentTimeMillis() + ".png"; | |
| 220 | + ImageIO.write(processedImage, "png", new File(processedImagePath)); | |
| 221 | + System.out.println("预处理图片已保存: " + processedImagePath); | |
| 222 | + | |
| 223 | + // 6. 执行识别 | |
| 224 | + System.out.println("开始识别图片..."); | |
| 225 | + long startTime = System.currentTimeMillis(); | |
| 226 | + OcrResult ocrResult = engine.runOcr(processedImagePath, config); | |
| 227 | + long endTime = System.currentTimeMillis(); | |
| 228 | + | |
| 229 | + // 7. 输出结果 | |
| 230 | + String text = ocrResult.getStrRes().trim(); | |
| 231 | + System.out.println("\n=================================="); | |
| 232 | + System.out.println("识别结果:"); | |
| 233 | + System.out.println(text); | |
| 234 | + System.out.println("=================================="); | |
| 235 | + System.out.println("识别耗时: " + (endTime - startTime) + " ms"); | |
| 236 | + | |
| 237 | + // 8. 输出每个文本块 | |
| 238 | + if (ocrResult.getTextBlocks() != null && !ocrResult.getTextBlocks().isEmpty()) { | |
| 239 | + System.out.println("\n文本块详情(共" + ocrResult.getTextBlocks().size() + "块):"); | |
| 240 | + List<TextBlock> textBlocks = ocrResult.getTextBlocks(); | |
| 241 | + for (int i = 0; i < textBlocks.size(); i++) { | |
| 242 | + TextBlock block = textBlocks.get(i); | |
| 243 | + System.out.printf(" 块%d: %s (置信度: %.2f)%n", | |
| 244 | + i + 1, | |
| 245 | + block.getText(), | |
| 246 | + block.getBoxScore() | |
| 247 | + ); | |
| 248 | + } | |
| 249 | + } | |
| 250 | + | |
| 251 | + // 9. 清理临时文件 | |
| 252 | + new File(processedImagePath).delete(); | |
| 253 | + | |
| 254 | + } catch (Exception e) { | |
| 255 | + System.err.println("OCR 识别失败: " + e.getMessage()); | |
| 256 | + e.printStackTrace(); | |
| 257 | + } | |
| 258 | + } | |
| 182 | 259 | } |
| 183 | 260 | \ No newline at end of file | ... | ... |
src/main/java/com/xly/ocr/web/OcrController.java
| 1 | -//package com.xly.ocr.web; | |
| 2 | -// | |
| 3 | -//import com.xly.ocr.service.OcrService; | |
| 4 | -//import org.springframework.beans.factory.annotation.Autowired; | |
| 5 | -//import org.springframework.http.ResponseEntity; | |
| 6 | -//import org.springframework.web.bind.annotation.*; | |
| 7 | -//import org.springframework.web.multipart.MultipartFile; | |
| 8 | -// | |
| 9 | -//import java.util.HashMap; | |
| 10 | -//import java.util.List; | |
| 11 | -//import java.util.Map; | |
| 12 | -// | |
| 13 | -//@RestController | |
| 14 | -//@RequestMapping("/api/ocr") | |
| 15 | -//public class OcrController { | |
| 16 | -// | |
| 17 | -// @Autowired | |
| 18 | -// private OcrService ocrService; | |
| 19 | -// | |
| 20 | -// @PostMapping("/extract") | |
| 21 | -// public ResponseEntity<Map<String, Object>> extractText( | |
| 22 | -// @RequestParam("file") MultipartFile file) { | |
| 23 | -// | |
| 24 | -// Map<String, Object> response = new HashMap<>(); | |
| 25 | -// long startTime = System.currentTimeMillis(); | |
| 26 | -// | |
| 27 | -// String result = ocrService.extractTextFromMultipartFile(file); | |
| 28 | -// | |
| 29 | -// response.put("text", result); | |
| 30 | -// response.put("time", System.currentTimeMillis() - startTime); | |
| 31 | -// response.put("success", !result.startsWith("错误") && !result.startsWith("失败")); | |
| 32 | -// | |
| 33 | -// return ResponseEntity.ok(response); | |
| 34 | -// } | |
| 35 | -// | |
| 36 | -// @PostMapping("/batch") | |
| 37 | -// public ResponseEntity<List<String>> batchExtract( | |
| 38 | -// @RequestParam("files") List<MultipartFile> files) { | |
| 39 | -// List<String> results = ocrService.batchExtractText(files); | |
| 40 | -// return ResponseEntity.ok(results); | |
| 41 | -// } | |
| 42 | -//} | |
| 43 | 1 | \ No newline at end of file |
| 2 | +package com.xly.ocr.web; | |
| 3 | + | |
| 4 | +import com.xly.ocr.service.OcrService; | |
| 5 | +import com.xly.tts.bean.TTSResponseDTO; | |
| 6 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 7 | +import org.springframework.http.ResponseEntity; | |
| 8 | +import org.springframework.web.bind.annotation.*; | |
| 9 | +import org.springframework.web.multipart.MultipartFile; | |
| 10 | + | |
| 11 | +import java.util.List; | |
| 12 | + | |
| 13 | +@RestController | |
| 14 | +@RequestMapping("/api/ocr") | |
| 15 | +public class OcrController { | |
| 16 | + | |
| 17 | + @Autowired | |
| 18 | + private OcrService ocrService; | |
| 19 | + | |
| 20 | + @PostMapping("/extract") | |
| 21 | + public ResponseEntity<TTSResponseDTO> extractText( | |
| 22 | + @RequestParam("file") MultipartFile file) { | |
| 23 | + String result = ocrService.extractTextFromMultipartFile(file); | |
| 24 | + TTSResponseDTO dto= TTSResponseDTO.builder() | |
| 25 | + .code(200) | |
| 26 | + .message("操作成功") | |
| 27 | + .processedText(result) | |
| 28 | + .build(); | |
| 29 | + return ResponseEntity.ok(dto); | |
| 30 | + } | |
| 31 | + | |
| 32 | + @PostMapping("/batch") | |
| 33 | + public ResponseEntity<List<String>> batchExtract( | |
| 34 | + @RequestParam("files") List<MultipartFile> files) { | |
| 35 | + List<String> results = ocrService.batchExtractText(files); | |
| 36 | + return ResponseEntity.ok(results); | |
| 37 | + } | |
| 38 | +} | |
| 44 | 39 | \ No newline at end of file | ... | ... |
src/main/java/com/xly/service/XlyErpService.java
| ... | ... | @@ -668,10 +668,8 @@ public class XlyErpService { |
| 668 | 668 | //如果查询不到数据走向量库 |
| 669 | 669 | if(ObjectUtil.isEmpty(sqlResult)){ |
| 670 | 670 | session.setDbType("X"); |
| 671 | - | |
| 672 | 671 | //数据集为空的也记录到历史问题中 |
| 673 | - doAiSqlErrorHistoryThread(session, cleanSql, StrUtil.EMPTY, StrUtil.EMPTY,input); | |
| 674 | - | |
| 672 | + doAiSqlErrorHistoryThread(session, StrUtil.EMPTY,cleanSql, "结果为空",input); | |
| 675 | 673 | return getMilvus(session, input, aiAgent,false); |
| 676 | 674 | } |
| 677 | 675 | // 5. 调用AI服务生成自然语言解释(传入表结构,让解释更贴合业务) |
| ... | ... | @@ -679,7 +677,7 @@ public class XlyErpService { |
| 679 | 677 | |
| 680 | 678 | //执行正确去修改对应正确的SQl |
| 681 | 679 | if(Integer.valueOf(iErroCount)>0){ |
| 682 | - doAiSqlErrorHistoryThread(session, cleanSql, StrUtil.EMPTY, StrUtil.EMPTY,input); | |
| 680 | + doAiSqlErrorHistoryThread(session, cleanSql, StrUtil.EMPTY, "执行正确去修改对应正确的SQl",input); | |
| 683 | 681 | } |
| 684 | 682 | //插入常用操作 不包含where 条件 |
| 685 | 683 | if(doAddSql){ |
| ... | ... | @@ -733,7 +731,7 @@ public class XlyErpService { |
| 733 | 731 | **/ |
| 734 | 732 | private Map<String,Object> getDynamicTableCach(UserSceneSession session,String input){ |
| 735 | 733 | try{ |
| 736 | - String searchText = session.getCurrentScene().getSId()+"_"+session.getCurrentTool().getSId()+input; | |
| 734 | + String searchText = session.getCurrentScene().getSId()+"_"+session.getCurrentTool().getSId()+"_"+input; | |
| 737 | 735 | //根据问题查询向量库 |
| 738 | 736 | Map<String,Object> serMap = aiGlobalAgentQuestionSqlEmitterService.queryAiGlobalAgentQuestionSqlEmitter(searchText, "ai_global_agent_question_sql"); |
| 739 | 737 | return serMap; | ... | ... |
src/main/java/com/xly/thread/AiUserAgentQuestionThread.java
| ... | ... | @@ -57,7 +57,7 @@ public class AiUserAgentQuestionThread implements Runnable { |
| 57 | 57 | // SqlValidateUtil.getsKey( sSceneId, sMethodId, SqlValidateUtil.getsQuestion(session.getSUserQuestionList())); |
| 58 | 58 | //存入向量库 不包含where 条件 |
| 59 | 59 | if(!SqlWhereHelper.hasWhereButNoCompareOperators(sSqlContent)){ |
| 60 | - aiGlobalAgentQuestionSqlEmitterService.addAiGlobalAgentQuestionSqlEmitter(sKey,data,sQuestion,sSqlContent,cachType,"ai_global_agent_question_sql"); | |
| 60 | + aiGlobalAgentQuestionSqlEmitterService.addAiGlobalAgentQuestionSqlEmitter(sKey,data,sQuestion,sSqlContent,cachType,"ai_global_agent_question_sql",false); | |
| 61 | 61 | } |
| 62 | 62 | //调用数据库插入数据库 |
| 63 | 63 | Map<String, Object> searMap = dynamicExeDbService.getDoProMap(sProName, data); | ... | ... |