| | |
| | | import java.util.List; |
| | | |
| | | @Service("mainProcessPseudocodeService") |
| | | public class MainProcessPseudocodeServiceImpl implements MainProcessPseudocodeService { |
| | | public class MainProcessPseudocodeServiceImpl { |
| | | |
| | | private static final long SUCCESS_CACHE_SECONDS = 60 * 60 * 24; |
| | | private static final long FAILURE_CACHE_SECONDS = 60 * 10; |
| | | private static final String FAILURE_TEXT = "AI生成伪代码失败"; |
| | | private static final String PSEUDOCODE_SYSTEM_PROMPT = """ |
| | | 你现在是一名高级 Java 架构师兼伪代码转换专家,专门负责把复杂的 Java 代码转换成结构清晰、适合大模型阅读与推理的伪代码。 |
| | | |
| | | 请严格遵守以下要求工作: |
| | | |
| | | 核心目标 |
| | | |
| | | 输入是一段或多段 Java 代码。 |
| | | |
| | | 输出是一段人类可读、逻辑清晰、尽量语言中立的伪代码。 |
| | | |
| | | 这份伪代码将被用作后续大模型提问的“参考描述”,所以要: |
| | | |
| | | 保留关键业务逻辑和判断条件; |
| | | |
| | | 弱化语言细节(如具体库、注解、框架细节); |
| | | |
| | | 用自然语言 + 简洁流程结构,帮助大模型快速理解代码意图。 |
| | | |
| | | 风格要求 |
| | | |
| | | 使用中文描述逻辑,但可以保留少量关键英文标识(例如类名、方法名、状态枚举)以便跟代码对应。 |
| | | |
| | | 伪代码要分层分块,尽量按: |
| | | |
| | | 类职责说明 |
| | | |
| | | 重要字段 / 全局变量说明 |
| | | |
| | | 每个公开方法 / 核心私有方法的伪代码 |
| | | |
| | | 逻辑上使用类似: |
| | | |
| | | 如果 ... 则 ... |
| | | |
| | | 否则如果 ... |
| | | |
| | | 循环遍历列表 ... |
| | | |
| | | 调用服务/方法: ... |
| | | |
| | | 返回 ... |
| | | |
| | | 不追求严格语法,只追求易懂和准确。 |
| | | |
| | | 保留信息 & 抽象信息 |
| | | |
| | | 必须保留: |
| | | |
| | | 关键业务含义(例如“生成入库任务”、“检查堆垛机任务是否完成”) |
| | | |
| | | 关键条件判断(状态字段、枚举、重要配置开关) |
| | | |
| | | 重要数据流向(从哪里读数据、写到哪里、调用了哪些服务) |
| | | |
| | | 与外部系统交互(如 HTTP 调用 WMS、写 Redis 锁、写数据库) |
| | | |
| | | 可以抽象或省略: |
| | | |
| | | 日志打印的具体格式,只保留“记录日志:xxx”即可; |
| | | |
| | | 具体框架注解(如 @Component, @Autowired 等); |
| | | |
| | | 泛型、异常栈细节、工具类内部实现; |
| | | |
| | | 结构模板(优先遵循) |
| | | |
| | | 对于一段较大的 Java 类,请按以下结构输出伪代码: |
| | | |
| | | 类整体说明 |
| | | |
| | | 简要说明这个类的用途和在系统中的角色。 |
| | | |
| | | 重要字段 / 配置说明 |
| | | |
| | | 列出关键静态变量 / 配置项 / 状态缓存,并用一行解释它们的含义。 |
| | | |
| | | 主流程方法(例如 run()) |
| | | |
| | | 用有序列表或伪代码,按调用顺序描述主要步骤。 |
| | | |
| | | 每个核心私有方法 |
| | | |
| | | 对于每个关键方法: |
| | | |
| | | 先用一行中文总结功能; |
| | | |
| | | 再给出伪代码流程(条件、循环、关键调用); |
| | | |
| | | 与外部系统交互的说明 |
| | | |
| | | 单独强调有哪些地方调用了外部服务(HTTP、消息队列、数据库、Redis 等)。 |
| | | |
| | | 输出格式要求 |
| | | |
| | | 使用 Markdown 结构,方便复制给其他大模型: |
| | | |
| | | 用 ## 标题区分“类说明”、“主流程伪代码”、“方法伪代码”等部分; |
| | | |
| | | 伪代码块可以使用缩进和项目符号,或用 pseudo 代码块 包裹; |
| | | |
| | | 不要直接逐行翻译代码,而是做抽象和整理; |
| | | |
| | | 不要输出无关文本,例如道歉、寒暄或与任务无关的解释。 |
| | | |
| | | 伪代码示例风格(示意) |
| | | |
| | | 例如当输入一个 run() 方法时,期望你的输出风格类似: |
| | | |
| | | 函数 run(): |
| | | 读取配置 enableFake, fakeRealTaskRequestWms |
| | | 如果 enableFake == "Y": |
| | | 调用 checkInStationHasTask() 检测入库站并生成仿真站点数据 |
| | | 如果 fakeRealTaskRequestWms == "N": |
| | | 调用 generateFakeInTask() 生成本地仿真入库任务 |
| | | 调用 generateFakeOutTask() 生成本地仿真出库任务 |
| | | 计算所有站点的停留时间 calcAllStationStayTime() |
| | | 检查出库站点是否超时并重置 checkOutStationStayTimeOut() |
| | | 检查入库站点货物是否已被堆垛机取走 checkInStationCrnTake() |
| | | 如果 fakeRealTaskRequestWms == "Y": |
| | | 调用 generateStoreWrkFile() 请求 WMS 生成真实任务 |
| | | 调用 crnOperateUtils.crnIoExecute() 执行堆垛机任务 |
| | | 调用 crnIoExecuteFinish() 处理堆垛机任务完成后的状态更新和仿真站点生成 |
| | | 调用 stationOperateProcessUtils.submitStationInTasks(...) 按 lane 提交输送站入库任务 |
| | | 调用 stationOperateProcessUtils.stationOutExecute() 执行输送站出库任务 |
| | | 调用 stationOperateProcessUtils.stationOutExecuteFinish() 检查输送站出库任务完成 |
| | | |
| | | 对输入的要求 |
| | | |
| | | 如果用户给出的是多段代码或只给出片段: |
| | | |
| | | 先推断这段代码的职责; |
| | | |
| | | 再按你能理解到的范围进行伪代码转换; |
| | | |
| | | 如果存在明显缺失的类/方法,只需在伪代码中用“调用 XXX(具体逻辑略)”标记即可。 |
| | | |
| | | 请始终以「让后续大模型能看懂这段代码逻辑并基于伪代码进行推理和提问」为最高优先级来组织你的输出。 |
| | | """; |
| | | private static final String PSEUDOCODE_SYSTEM_PROMPT = "";//" |
| | | // 你现在是一名高级 Java 架构师兼伪代码转换专家,专门负责把复杂的 Java 代码转换成结构清晰、适合大模型阅读与推理的伪代码。 |
| | | // |
| | | // 请严格遵守以下要求工作: |
| | | // |
| | | // 核心目标 |
| | | // |
| | | // 输入是一段或多段 Java 代码。 |
| | | // |
| | | // 输出是一段人类可读、逻辑清晰、尽量语言中立的伪代码。 |
| | | // |
| | | // 这份伪代码将被用作后续大模型提问的“参考描述”,所以要: |
| | | // |
| | | // 保留关键业务逻辑和判断条件; |
| | | // |
| | | // 弱化语言细节(如具体库、注解、框架细节); |
| | | // |
| | | // 用自然语言 + 简洁流程结构,帮助大模型快速理解代码意图。 |
| | | // |
| | | // 风格要求 |
| | | // |
| | | // 使用中文描述逻辑,但可以保留少量关键英文标识(例如类名、方法名、状态枚举)以便跟代码对应。 |
| | | // |
| | | // 伪代码要分层分块,尽量按: |
| | | // |
| | | // 类职责说明 |
| | | // |
| | | // 重要字段 / 全局变量说明 |
| | | // |
| | | // 每个公开方法 / 核心私有方法的伪代码 |
| | | // |
| | | // 逻辑上使用类似: |
| | | // |
| | | // 如果 ... 则 ... |
| | | // |
| | | // 否则如果 ... |
| | | // |
| | | // 循环遍历列表 ... |
| | | // |
| | | // 调用服务/方法: ... |
| | | // |
| | | // 返回 ... |
| | | // |
| | | // 不追求严格语法,只追求易懂和准确。 |
| | | // |
| | | // 保留信息 & 抽象信息 |
| | | // |
| | | // 必须保留: |
| | | // |
| | | // 关键业务含义(例如“生成入库任务”、“检查堆垛机任务是否完成”) |
| | | // |
| | | // 关键条件判断(状态字段、枚举、重要配置开关) |
| | | // |
| | | // 重要数据流向(从哪里读数据、写到哪里、调用了哪些服务) |
| | | // |
| | | // 与外部系统交互(如 HTTP 调用 WMS、写 Redis 锁、写数据库) |
| | | // |
| | | // 可以抽象或省略: |
| | | // |
| | | // 日志打印的具体格式,只保留“记录日志:xxx”即可; |
| | | // |
| | | // 具体框架注解(如 @Component, @Autowired 等); |
| | | // |
| | | // 泛型、异常栈细节、工具类内部实现; |
| | | // |
| | | // 结构模板(优先遵循) |
| | | // |
| | | // 对于一段较大的 Java 类,请按以下结构输出伪代码: |
| | | // |
| | | // 类整体说明 |
| | | // |
| | | // 简要说明这个类的用途和在系统中的角色。 |
| | | // |
| | | // 重要字段 / 配置说明 |
| | | // |
| | | // 列出关键静态变量 / 配置项 / 状态缓存,并用一行解释它们的含义。 |
| | | // |
| | | // 主流程方法(例如 run()) |
| | | // |
| | | // 用有序列表或伪代码,按调用顺序描述主要步骤。 |
| | | // |
| | | // 每个核心私有方法 |
| | | // |
| | | // 对于每个关键方法: |
| | | // |
| | | // 先用一行中文总结功能; |
| | | // |
| | | // 再给出伪代码流程(条件、循环、关键调用); |
| | | // |
| | | // 与外部系统交互的说明 |
| | | // |
| | | // 单独强调有哪些地方调用了外部服务(HTTP、消息队列、数据库、Redis 等)。 |
| | | // |
| | | // 输出格式要求 |
| | | // |
| | | // 使用 Markdown 结构,方便复制给其他大模型: |
| | | // |
| | | // 用 ## 标题区分“类说明”、“主流程伪代码”、“方法伪代码”等部分; |
| | | // |
| | | // 伪代码块可以使用缩进和项目符号,或用 pseudo 代码块 包裹; |
| | | // |
| | | // 不要直接逐行翻译代码,而是做抽象和整理; |
| | | // |
| | | // 不要输出无关文本,例如道歉、寒暄或与任务无关的解释。 |
| | | // |
| | | // 伪代码示例风格(示意) |
| | | // |
| | | // 例如当输入一个 run() 方法时,期望你的输出风格类似: |
| | | // |
| | | // 函数 run(): |
| | | // 读取配置 enableFake, fakeRealTaskRequestWms |
| | | // 如果 enableFake == "Y": |
| | | // 调用 checkInStationHasTask() 检测入库站并生成仿真站点数据 |
| | | // 如果 fakeRealTaskRequestWms == "N": |
| | | // 调用 generateFakeInTask() 生成本地仿真入库任务 |
| | | // 调用 generateFakeOutTask() 生成本地仿真出库任务 |
| | | // 计算所有站点的停留时间 calcAllStationStayTime() |
| | | // 检查出库站点是否超时并重置 checkOutStationStayTimeOut() |
| | | // 检查入库站点货物是否已被堆垛机取走 checkInStationCrnTake() |
| | | // 如果 fakeRealTaskRequestWms == "Y": |
| | | // 调用 generateStoreWrkFile() 请求 WMS 生成真实任务 |
| | | // 调用 crnOperateUtils.crnIoExecute() 执行堆垛机任务 |
| | | // 调用 crnIoExecuteFinish() 处理堆垛机任务完成后的状态更新和仿真站点生成 |
| | | // 调用 stationOperateProcessUtils.submitStationInTasks(...) 按 lane 提交输送站入库任务 |
| | | // 调用 stationOperateProcessUtils.stationOutExecute() 执行输送站出库任务 |
| | | // 调用 stationOperateProcessUtils.stationOutExecuteFinish() 检查输送站出库任务完成 |
| | | // |
| | | // 对输入的要求 |
| | | // |
| | | // 如果用户给出的是多段代码或只给出片段: |
| | | // |
| | | // 先推断这段代码的职责; |
| | | // |
| | | // 再按你能理解到的范围进行伪代码转换; |
| | | // |
| | | // 如果存在明显缺失的类/方法,只需在伪代码中用“调用 XXX(具体逻辑略)”标记即可。 |
| | | // |
| | | // 请始终以「让后续大模型能看懂这段代码逻辑并基于伪代码进行推理和提问」为最高优先级来组织你的输出。 |
| | | // """; |
| | | |
| | | @Value("${mainProcessPlugin}") |
| | | private String mainProcessPlugin; |
| | |
| | | @Autowired |
| | | private RedisUtil redisUtil; |
| | | |
| | | @Override |
| | | public JSONObject queryMainProcessPseudocode(boolean refresh) { |
| | | String cacheKey = RedisKeyType.MAIN_PROCESS_PSEUDOCODE.key; |
| | | String cached = trimToNull(redisUtil.get(cacheKey)); |
| | | String pseudocode = cached; |
| | | String status = "cached"; |
| | | String message = null; |
| | | boolean generatedFresh = false; |
| | | // @Override |
| | | // public JSONObject queryMainProcessPseudocode(boolean refresh) { |
| | | // String cacheKey = RedisKeyType.MAIN_PROCESS_PSEUDOCODE.key; |
| | | // String cached = trimToNull(redisUtil.get(cacheKey)); |
| | | // String pseudocode = cached; |
| | | // String status = "cached"; |
| | | // String message = null; |
| | | // boolean generatedFresh = false; |
| | | // |
| | | // if (refresh || pseudocode == null) { |
| | | // String generated = generateAndCachePseudocode(); |
| | | // if (generated != null) { |
| | | // pseudocode = generated; |
| | | // generatedFresh = true; |
| | | // status = refresh ? "refreshed" : "generated"; |
| | | // } else if (cached != null) { |
| | | // pseudocode = cached; |
| | | // status = "fallback_cached"; |
| | | // message = "重新生成失败,返回缓存中的伪代码"; |
| | | // } else { |
| | | // pseudocode = FAILURE_TEXT; |
| | | // status = "failed"; |
| | | // message = FAILURE_TEXT; |
| | | // redisUtil.set(cacheKey, FAILURE_TEXT, FAILURE_CACHE_SECONDS); |
| | | // News.info(FAILURE_TEXT); |
| | | // } |
| | | // } |
| | | // |
| | | // JSONObject result = new JSONObject(); |
| | | // result.put("mainProcessPlugin", resolvePlugin()); |
| | | // result.put("mainProcessPluginClass", resolvePluginClassName()); |
| | | // result.put("refreshRequested", refresh); |
| | | // result.put("generatedFresh", generatedFresh); |
| | | // result.put("cacheHit", !generatedFresh && ("cached".equals(status) || "fallback_cached".equals(status))); |
| | | // result.put("status", status); |
| | | // result.put("expireSeconds", redisUtil.getExpire(cacheKey)); |
| | | // result.put("message", message); |
| | | // result.put("pseudocode", pseudocode); |
| | | // return result; |
| | | // } |
| | | |
| | | if (refresh || pseudocode == null) { |
| | | String generated = generateAndCachePseudocode(); |
| | | if (generated != null) { |
| | | pseudocode = generated; |
| | | generatedFresh = true; |
| | | status = refresh ? "refreshed" : "generated"; |
| | | } else if (cached != null) { |
| | | pseudocode = cached; |
| | | status = "fallback_cached"; |
| | | message = "重新生成失败,返回缓存中的伪代码"; |
| | | } else { |
| | | pseudocode = FAILURE_TEXT; |
| | | status = "failed"; |
| | | message = FAILURE_TEXT; |
| | | redisUtil.set(cacheKey, FAILURE_TEXT, FAILURE_CACHE_SECONDS); |
| | | News.info(FAILURE_TEXT); |
| | | } |
| | | } |
| | | // private String generateAndCachePseudocode() { |
| | | // String code = loadSourceBundle(); |
| | | // if (code == null || code.isEmpty()) { |
| | | // return null; |
| | | // } |
| | | // |
| | | // List<ChatCompletionRequest.Message> messages = new ArrayList<>(); |
| | | // ChatCompletionRequest.Message system = new ChatCompletionRequest.Message(); |
| | | // system.setRole("system"); |
| | | // system.setContent(PSEUDOCODE_SYSTEM_PROMPT); |
| | | // messages.add(system); |
| | | // |
| | | // ChatCompletionRequest.Message user = new ChatCompletionRequest.Message(); |
| | | // user.setRole("user"); |
| | | // user.setContent("主流程插件类源代码:\n\n" + code); |
| | | // messages.add(user); |
| | | // |
| | | // try { |
| | | // String result = trimToNull(llmChatService.chat(messages, 0.2, 2048)); |
| | | // if (result == null) { |
| | | // return null; |
| | | // } |
| | | // redisUtil.set(RedisKeyType.MAIN_PROCESS_PSEUDOCODE.key, result, SUCCESS_CACHE_SECONDS); |
| | | // News.info("AI生成伪代码成功"); |
| | | // return result; |
| | | // } catch (Exception ignore) { |
| | | // return null; |
| | | // } |
| | | // } |
| | | // String code = loadSourceBundle(); |
| | | // if (code == null || code.isEmpty()) { |
| | | // return null; |
| | | // } |
| | | // |
| | | // List<ChatCompletionRequest.Message> messages = new ArrayList<>(); |
| | | // ChatCompletionRequest.Message system = new ChatCompletionRequest.Message(); |
| | | // system.setRole("system"); |
| | | // system.setContent(PSEUDOCODE_SYSTEM_PROMPT); |
| | | // messages.add(system); |
| | | // |
| | | // ChatCompletionRequest.Message user = new ChatCompletionRequest.Message(); |
| | | // user.setRole("user"); |
| | | // user.setContent("主流程插件类源代码:\n\n" + code); |
| | | // messages.add(user); |
| | | // |
| | | // try { |
| | | // String result = trimToNull(llmChatService.chat(messages, 0.2, 2048)); |
| | | // if (result == null) { |
| | | // return null; |
| | | // } |
| | | // redisUtil.set(RedisKeyType.MAIN_PROCESS_PSEUDOCODE.key, result, SUCCESS_CACHE_SECONDS); |
| | | // News.info("AI生成伪代码成功"); |
| | | // return result; |
| | | // } catch (Exception ignore) { |
| | | // return null; |
| | | // } |
| | | // } |
| | | |
| | | JSONObject result = new JSONObject(); |
| | | result.put("mainProcessPlugin", resolvePlugin()); |
| | | result.put("mainProcessPluginClass", resolvePluginClassName()); |
| | | result.put("refreshRequested", refresh); |
| | | result.put("generatedFresh", generatedFresh); |
| | | result.put("cacheHit", !generatedFresh && ("cached".equals(status) || "fallback_cached".equals(status))); |
| | | result.put("status", status); |
| | | result.put("expireSeconds", redisUtil.getExpire(cacheKey)); |
| | | result.put("message", message); |
| | | result.put("pseudocode", pseudocode); |
| | | return result; |
| | | } |
| | | // private String loadSourceBundle() { |
| | | // StringBuilder code = new StringBuilder(); |
| | | // appendSource(code, resolvePluginClassName()); |
| | | // appendSource(code, "com.zy.core.utils.CrnOperateProcessUtils"); |
| | | // appendSource(code, "com.zy.core.utils.StationOperateProcessUtils"); |
| | | // return code.toString(); |
| | | // } |
| | | |
| | | private String generateAndCachePseudocode() { |
| | | String code = loadSourceBundle(); |
| | | if (code == null || code.isEmpty()) { |
| | | return null; |
| | | } |
| | | // private void appendSource(StringBuilder code, String className) { |
| | | // if (className == null || className.trim().isEmpty()) { |
| | | // return; |
| | | // } |
| | | // String source = readJavaSource(className); |
| | | // if (source == null || source.isEmpty()) { |
| | | // return; |
| | | // } |
| | | // if (code.length() > 0) { |
| | | // code.append("\n\n"); |
| | | // } |
| | | // code.append("// ===== ").append(className).append(" =====\n"); |
| | | // code.append(source); |
| | | // } |
| | | |
| | | List<ChatCompletionRequest.Message> messages = new ArrayList<>(); |
| | | ChatCompletionRequest.Message system = new ChatCompletionRequest.Message(); |
| | | system.setRole("system"); |
| | | system.setContent(PSEUDOCODE_SYSTEM_PROMPT); |
| | | messages.add(system); |
| | | |
| | | ChatCompletionRequest.Message user = new ChatCompletionRequest.Message(); |
| | | user.setRole("user"); |
| | | user.setContent("主流程插件类源代码:\n\n" + code); |
| | | messages.add(user); |
| | | |
| | | try { |
| | | String result = trimToNull(llmChatService.chat(messages, 0.2, 2048)); |
| | | if (result == null) { |
| | | return null; |
| | | } |
| | | redisUtil.set(RedisKeyType.MAIN_PROCESS_PSEUDOCODE.key, result, SUCCESS_CACHE_SECONDS); |
| | | News.info("AI生成伪代码成功"); |
| | | return result; |
| | | } catch (Exception ignore) { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | private String loadSourceBundle() { |
| | | StringBuilder code = new StringBuilder(); |
| | | appendSource(code, resolvePluginClassName()); |
| | | appendSource(code, "com.zy.core.utils.CrnOperateProcessUtils"); |
| | | appendSource(code, "com.zy.core.utils.StationOperateProcessUtils"); |
| | | return code.toString(); |
| | | } |
| | | |
| | | private void appendSource(StringBuilder code, String className) { |
| | | if (className == null || className.trim().isEmpty()) { |
| | | return; |
| | | } |
| | | String source = readJavaSource(className); |
| | | if (source == null || source.isEmpty()) { |
| | | return; |
| | | } |
| | | if (code.length() > 0) { |
| | | code.append("\n\n"); |
| | | } |
| | | code.append("// ===== ").append(className).append(" =====\n"); |
| | | code.append(source); |
| | | } |
| | | |
| | | private String readJavaSource(String className) { |
| | | try { |
| | | String rel = className.replace('.', '/') + ".java"; |
| | | Path path = Paths.get(System.getProperty("user.dir"), "src", "main", "java", rel); |
| | | if (!Files.exists(path)) { |
| | | return null; |
| | | } |
| | | return Files.readString(path, StandardCharsets.UTF_8); |
| | | } catch (Exception ignore) { |
| | | return null; |
| | | } |
| | | } |
| | | // private String readJavaSource(String className) { |
| | | // try { |
| | | // String rel = className.replace('.', '/') + ".java"; |
| | | // Path path = Paths.get(System.getProperty("user.dir"), "src", "main", "java", rel); |
| | | // if (!Files.exists(path)) { |
| | | // return null; |
| | | // } |
| | | // return Files.readString(path, StandardCharsets.UTF_8); |
| | | // } catch (Exception ignore) { |
| | | // return null; |
| | | // } |
| | | // } |
| | | |
| | | private String resolvePlugin() { |
| | | String plugin = trimToNull(mainProcessPlugin); |