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,7 +12,7 @@ public interface AiGlobalAgentQuestionSqlEmitterService { | ||
| 12 | * @return void | 12 | * @return void |
| 13 | * @Description 插入向量库 | 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 | Map<String, Object> queryAiGlobalAgentQuestionSqlEmitter(String searchText, String collectionName); | 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,6 +22,24 @@ public interface MilvusService { | ||
| 22 | 22 | ||
| 23 | TTSResponseDTO initDataToMilvus(Map<String, Object> reqMap); | 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,7 +58,7 @@ public class AiGlobalAgentQuestionSqlEmitterServiceImpl implements AiGlobalAgent | ||
| 58 | * @Description 插入数据 | 58 | * @Description 插入数据 |
| 59 | **/ | 59 | **/ |
| 60 | @Override | 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 | List<Float> vector = vectorizationService.textToVector(sKey); | 63 | List<Float> vector = vectorizationService.textToVector(sKey); |
| 64 | 64 | ||
| @@ -83,10 +83,12 @@ public class AiGlobalAgentQuestionSqlEmitterServiceImpl implements AiGlobalAgent | @@ -83,10 +83,12 @@ public class AiGlobalAgentQuestionSqlEmitterServiceImpl implements AiGlobalAgent | ||
| 83 | .build(); | 83 | .build(); |
| 84 | 84 | ||
| 85 | InsertResp insertResp = milvusClient.insert(insertReq); | 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 | System.out.println("成功插入 " + insertResp.getInsertCnt() + " 条数据"); | 92 | System.out.println("成功插入 " + insertResp.getInsertCnt() + " 条数据"); |
| 91 | System.out.println(" - 数据预览:"); | 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,6 +10,7 @@ import com.google.common.reflect.TypeToken; | ||
| 10 | import com.google.gson.Gson; | 10 | import com.google.gson.Gson; |
| 11 | import com.google.gson.JsonArray; | 11 | import com.google.gson.JsonArray; |
| 12 | import com.google.gson.JsonObject; | 12 | import com.google.gson.JsonObject; |
| 13 | +import com.xly.milvus.service.AiGlobalAgentQuestionSqlEmitterService; | ||
| 13 | import com.xly.milvus.service.MilvusService; | 14 | import com.xly.milvus.service.MilvusService; |
| 14 | import com.xly.milvus.service.VectorizationService; | 15 | import com.xly.milvus.service.VectorizationService; |
| 15 | import com.xly.milvus.util.MapToJsonConverter; | 16 | import com.xly.milvus.util.MapToJsonConverter; |
| @@ -60,6 +61,7 @@ public class MilvusServiceImpl implements MilvusService { | @@ -60,6 +61,7 @@ public class MilvusServiceImpl implements MilvusService { | ||
| 60 | private final MilvusClientV2 milvusClient; | 61 | private final MilvusClientV2 milvusClient; |
| 61 | private final VectorizationService vectorizationService; | 62 | private final VectorizationService vectorizationService; |
| 62 | private final DynamicExeDbService dynamicExeDbService; | 63 | private final DynamicExeDbService dynamicExeDbService; |
| 64 | + private final AiGlobalAgentQuestionSqlEmitterService aiGlobalAgentQuestionSqlEmitterService; | ||
| 63 | private static final long NULL_TIMESTAMP = -1L; | 65 | private static final long NULL_TIMESTAMP = -1L; |
| 64 | // 日期格式常量 | 66 | // 日期格式常量 |
| 65 | private static final DateTimeFormatter ISO_FORMATTER = | 67 | private static final DateTimeFormatter ISO_FORMATTER = |
| @@ -128,6 +130,80 @@ public class MilvusServiceImpl implements MilvusService { | @@ -128,6 +130,80 @@ public class MilvusServiceImpl implements MilvusService { | ||
| 128 | .build(); | 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 | public String getUpdateDateUp(String sInputTabelName) { | 207 | public String getUpdateDateUp(String sInputTabelName) { |
| 132 | Map<String,Object> serDataMap = new HashMap<>(); | 208 | Map<String,Object> serDataMap = new HashMap<>(); |
| 133 | String sSql ="SELECT DATE_FORMAT(tUpdateDate,'%Y-%m-%d %H:%i:%s') AS tUpdateDate FROM ai_milvus_vector_record WHERE sInputTabelName = #{sInputTabelName}"; | 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,6 +215,14 @@ public class MilvusServiceImpl implements MilvusService { | ||
| 139 | return data.get(0).get("tUpdateDate").toString(); | 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 | * @Author 钱豹 | 227 | * @Author 钱豹 |
| 144 | * @Date 22:24 2026/3/24 | 228 | * @Date 22:24 2026/3/24 |
src/main/java/com/xly/milvus/web/MilvusController.java
| @@ -45,5 +45,31 @@ public class MilvusController { | @@ -45,5 +45,31 @@ public class MilvusController { | ||
| 45 | return ResponseEntity.ok(responseDTO); | 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 | \ No newline at end of file | 76 | \ No newline at end of file |
src/main/java/com/xly/ocr/service/OcrService.java
| 1 | package com.xly.ocr.service; | 1 | package com.xly.ocr.service; |
| 2 | 2 | ||
| 3 | +import com.xly.ocr.util.OcrUtil; | ||
| 4 | +import lombok.extern.slf4j.Slf4j; | ||
| 3 | import net.sourceforge.tess4j.Tesseract; | 5 | import net.sourceforge.tess4j.Tesseract; |
| 4 | import net.sourceforge.tess4j.TesseractException; | 6 | import net.sourceforge.tess4j.TesseractException; |
| 5 | import org.slf4j.Logger; | 7 | import org.slf4j.Logger; |
| @@ -18,11 +20,16 @@ import java.nio.file.Path; | @@ -18,11 +20,16 @@ import java.nio.file.Path; | ||
| 18 | import java.util.Arrays; | 20 | import java.util.Arrays; |
| 19 | import java.util.List; | 21 | import java.util.List; |
| 20 | 22 | ||
| 21 | -@Service | 23 | +@Slf4j |
| 24 | +@Service("ocrService") | ||
| 22 | public class OcrService { | 25 | public class OcrService { |
| 23 | 26 | ||
| 24 | private static final Logger logger = LoggerFactory.getLogger(OcrService.class); | 27 | private static final Logger logger = LoggerFactory.getLogger(OcrService.class); |
| 25 | 28 | ||
| 29 | + @Value("${ocr.tmpPath}") | ||
| 30 | + private String tmpPath; | ||
| 31 | + | ||
| 32 | + | ||
| 26 | private final Tesseract tesseract; | 33 | private final Tesseract tesseract; |
| 27 | 34 | ||
| 28 | // 配置参数 | 35 | // 配置参数 |
| @@ -457,28 +464,8 @@ public class OcrService { | @@ -457,28 +464,8 @@ public class OcrService { | ||
| 457 | logger.warn("不支持的文件格式: {}", originalFilename); | 464 | logger.warn("不支持的文件格式: {}", originalFilename); |
| 458 | return "不支持的文件格式,仅支持: " + String.join(", ", ALLOWED_EXTENSIONS); | 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 | import com.benjaminwan.ocrlibrary.OcrResult; | 5 | import com.benjaminwan.ocrlibrary.OcrResult; |
| 4 | import com.benjaminwan.ocrlibrary.TextBlock; | 6 | import com.benjaminwan.ocrlibrary.TextBlock; |
| 5 | import io.github.mymonstercat.Model; | 7 | import io.github.mymonstercat.Model; |
| 6 | import io.github.mymonstercat.ocr.InferenceEngine; | 8 | import io.github.mymonstercat.ocr.InferenceEngine; |
| 7 | import io.github.mymonstercat.ocr.config.ParamConfig; | 9 | import io.github.mymonstercat.ocr.config.ParamConfig; |
| 10 | +import lombok.extern.slf4j.Slf4j; | ||
| 11 | +import org.springframework.web.multipart.MultipartFile; | ||
| 8 | 12 | ||
| 9 | import javax.imageio.ImageIO; | 13 | import javax.imageio.ImageIO; |
| 10 | import java.awt.*; | 14 | import java.awt.*; |
| @@ -13,7 +17,8 @@ import java.io.File; | @@ -13,7 +17,8 @@ import java.io.File; | ||
| 13 | import java.io.IOException; | 17 | import java.io.IOException; |
| 14 | import java.util.List; | 18 | import java.util.List; |
| 15 | 19 | ||
| 16 | -public class Test { | 20 | +@Slf4j |
| 21 | +public class OcrUtil { | ||
| 17 | 22 | ||
| 18 | static { | 23 | static { |
| 19 | try { | 24 | try { |
| @@ -35,71 +40,64 @@ public class Test { | @@ -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 | try { | 45 | try { |
| 40 | - System.out.println("OCR 程序开始执行..."); | ||
| 41 | - | 46 | + log.info("OCR 程序开始执行..."); |
| 42 | // 1. 初始化引擎(使用 v4 模型) | 47 | // 1. 初始化引擎(使用 v4 模型) |
| 43 | - System.out.println("正在初始化 OCR 引擎 (PP-OCRv4)..."); | 48 | + log.info("正在初始化 OCR 引擎 (PP-OCRv4)..."); |
| 44 | InferenceEngine engine = InferenceEngine.getInstance(Model.ONNX_PPOCR_V4); | 49 | InferenceEngine engine = InferenceEngine.getInstance(Model.ONNX_PPOCR_V4); |
| 45 | - | ||
| 46 | // 2. 创建优化的参数配置 | 50 | // 2. 创建优化的参数配置 |
| 47 | ParamConfig config = createOptimizedParamConfig(); | 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 | // 4. 图像预处理(直接处理原图,不保存临时文件) | 52 | // 4. 图像预处理(直接处理原图,不保存临时文件) |
| 58 | System.out.println("正在进行图像预处理..."); | 53 | System.out.println("正在进行图像预处理..."); |
| 59 | - BufferedImage processedImage = preprocessImage(imageFile); | ||
| 60 | - | 54 | + File file = multipartFileToFile(imageFile); |
| 55 | + BufferedImage processedImage = preprocessImage(file); | ||
| 61 | // 5. 保存预处理后的图片到临时目录 | 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 | ImageIO.write(processedImage, "png", new File(processedImagePath)); | 61 | ImageIO.write(processedImage, "png", new File(processedImagePath)); |
| 64 | - System.out.println("预处理图片已保存: " + processedImagePath); | ||
| 65 | - | 62 | + log.info("预处理图片已保存: " + processedImagePath); |
| 66 | // 6. 执行识别 | 63 | // 6. 执行识别 |
| 67 | - System.out.println("开始识别图片..."); | 64 | + log.info("开始识别图片..."); |
| 68 | long startTime = System.currentTimeMillis(); | 65 | long startTime = System.currentTimeMillis(); |
| 69 | OcrResult ocrResult = engine.runOcr(processedImagePath, config); | 66 | OcrResult ocrResult = engine.runOcr(processedImagePath, config); |
| 70 | long endTime = System.currentTimeMillis(); | 67 | long endTime = System.currentTimeMillis(); |
| 71 | - | ||
| 72 | // 7. 输出结果 | 68 | // 7. 输出结果 |
| 73 | String text = ocrResult.getStrRes().trim(); | 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 | // 8. 输出每个文本块 | 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 | } catch (Exception e) { | 90 | } catch (Exception e) { |
| 98 | System.err.println("OCR 识别失败: " + e.getMessage()); | 91 | System.err.println("OCR 识别失败: " + e.getMessage()); |
| 99 | e.printStackTrace(); | 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,6 +140,20 @@ public class Test { | ||
| 142 | 140 | ||
| 143 | return processed; | 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,4 +191,69 @@ public class Test { | ||
| 179 | } | 191 | } |
| 180 | return result; | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 39 | \ No newline at end of file |
src/main/java/com/xly/service/XlyErpService.java
| @@ -668,10 +668,8 @@ public class XlyErpService { | @@ -668,10 +668,8 @@ public class XlyErpService { | ||
| 668 | //如果查询不到数据走向量库 | 668 | //如果查询不到数据走向量库 |
| 669 | if(ObjectUtil.isEmpty(sqlResult)){ | 669 | if(ObjectUtil.isEmpty(sqlResult)){ |
| 670 | session.setDbType("X"); | 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 | return getMilvus(session, input, aiAgent,false); | 673 | return getMilvus(session, input, aiAgent,false); |
| 676 | } | 674 | } |
| 677 | // 5. 调用AI服务生成自然语言解释(传入表结构,让解释更贴合业务) | 675 | // 5. 调用AI服务生成自然语言解释(传入表结构,让解释更贴合业务) |
| @@ -679,7 +677,7 @@ public class XlyErpService { | @@ -679,7 +677,7 @@ public class XlyErpService { | ||
| 679 | 677 | ||
| 680 | //执行正确去修改对应正确的SQl | 678 | //执行正确去修改对应正确的SQl |
| 681 | if(Integer.valueOf(iErroCount)>0){ | 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 | //插入常用操作 不包含where 条件 | 682 | //插入常用操作 不包含where 条件 |
| 685 | if(doAddSql){ | 683 | if(doAddSql){ |
| @@ -733,7 +731,7 @@ public class XlyErpService { | @@ -733,7 +731,7 @@ public class XlyErpService { | ||
| 733 | **/ | 731 | **/ |
| 734 | private Map<String,Object> getDynamicTableCach(UserSceneSession session,String input){ | 732 | private Map<String,Object> getDynamicTableCach(UserSceneSession session,String input){ |
| 735 | try{ | 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 | Map<String,Object> serMap = aiGlobalAgentQuestionSqlEmitterService.queryAiGlobalAgentQuestionSqlEmitter(searchText, "ai_global_agent_question_sql"); | 736 | Map<String,Object> serMap = aiGlobalAgentQuestionSqlEmitterService.queryAiGlobalAgentQuestionSqlEmitter(searchText, "ai_global_agent_question_sql"); |
| 739 | return serMap; | 737 | return serMap; |
src/main/java/com/xly/thread/AiUserAgentQuestionThread.java
| @@ -57,7 +57,7 @@ public class AiUserAgentQuestionThread implements Runnable { | @@ -57,7 +57,7 @@ public class AiUserAgentQuestionThread implements Runnable { | ||
| 57 | // SqlValidateUtil.getsKey( sSceneId, sMethodId, SqlValidateUtil.getsQuestion(session.getSUserQuestionList())); | 57 | // SqlValidateUtil.getsKey( sSceneId, sMethodId, SqlValidateUtil.getsQuestion(session.getSUserQuestionList())); |
| 58 | //存入向量库 不包含where 条件 | 58 | //存入向量库 不包含where 条件 |
| 59 | if(!SqlWhereHelper.hasWhereButNoCompareOperators(sSqlContent)){ | 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 | Map<String, Object> searMap = dynamicExeDbService.getDoProMap(sProName, data); | 63 | Map<String, Object> searMap = dynamicExeDbService.getDoProMap(sProName, data); |
src/main/resources/application.yml
| @@ -65,6 +65,8 @@ spring: | @@ -65,6 +65,8 @@ spring: | ||
| 65 | max-active: 8 # 连接池最大连接数 | 65 | max-active: 8 # 连接池最大连接数 |
| 66 | max-idle: 8 # 连接池最大空闲连接 | 66 | max-idle: 8 # 连接池最大空闲连接 |
| 67 | min-idle: 0 # 连接池最小空闲连接' | 67 | min-idle: 0 # 连接池最小空闲连接' |
| 68 | +ocr: | ||
| 69 | + tmpPath: D:/xlyweberp/ai/ocrtmp | ||
| 68 | 70 | ||
| 69 | milvus: | 71 | milvus: |
| 70 | host: 112.82.245.194 | 72 | host: 112.82.245.194 |