tsurumure 1 hónapja
szülő
commit
6160b5d65f

+ 2 - 2
db/crt_drama_project_storyboard.sql

@@ -24,8 +24,8 @@ CREATE TABLE `crt_drama_project_storyboard` (
     `param_prompt_flux_guidance` FLOAT DEFAULT '3.5' COMMENT '提示词引导系数 (默认值:3.5,小数点后一位,范围:1~30)',
     `param_sampler` VARCHAR(20) DEFAULT 'Euler' COMMENT '采样方法 (枚举)(Euler: euler, DPM++2M: dpmpp_2m)',
     `param_step` INT DEFAULT '20' COMMENT '步数 (默认值:20,整数范围:1~30)',
-    `param_seed` TINYINT DEFAULT '1' COMMENT '随机种子 (默认值:1,范围:(1:随机, 2:自定义))',
-    `param_seed_custom` VARCHAR(255) COMMENT '随机种子自定义值 (长度: 0~64位整数)',
+    `param_seed_type` TINYINT DEFAULT '1' COMMENT '随机种子 (默认值:1,范围:(1:随机, 2:自定义))',
+    `param_seed` VARCHAR(255) COMMENT '随机种子自定义值 (长度: 0~64位整数)',
     `text_to_image_prompt` VARCHAR(2000) COMMENT '文生图提示词 (生图时必填)',
 
     `param_video_reference_type` TINYINT DEFAULT '1' COMMENT '生视频模式 (1:首尾帧模式, 2:多图参考模式)',

+ 2 - 2
src/main/java/com/backendsys/modules/crt/entity/CrtDramaProjectStoryboard.java

@@ -80,11 +80,11 @@ public class CrtDramaProjectStoryboard {
 
     // 随机种子 (默认值:1,范围:(1:随机, 2:自定义))
     @RangeArray(message="随机种子取值有误,范围应是(1, 2)", value = { "1", "2" }, groups = { Update.class })
-    private Integer param_seed;
+    private Integer param_seed_type;
 
     // 随机种子自定义值 (长度: 0~64位整数)
     @Size(max = 64, message = "随机种子自定义值长度不超过 {max} 个字符", groups = { Update.class })
-    private String param_seed_custom;
+    private String param_seed;
 
     // 文生图提示词 (生图时必填)
     @Size(max = 2000, message = "文生图提示词 长度不超过 {max} 个字符", groups = { Update.class })

+ 38 - 417
src/main/java/com/backendsys/modules/crt/service/impl/CrtGenerateServiceImpl.java

@@ -17,8 +17,10 @@ import com.backendsys.modules.crt.enums.SamplerEnums;
 import com.backendsys.modules.crt.service.CrtGenerateService;
 import com.backendsys.modules.sdk.comfyui.entity.CFPromptResponse;
 import com.backendsys.modules.sdk.comfyui.entity.CFQueue;
+import com.backendsys.modules.sdk.comfyui.entity.Text2Image;
 import com.backendsys.modules.sdk.comfyui.service.ComfyUIService;
 import com.backendsys.modules.sdk.comfyui.service.ComfyUISocketService;
+import com.backendsys.modules.sdk.comfyui.service.Text2ImageService;
 import com.backendsys.modules.upload.enums.StyleEnums;
 import com.backendsys.modules.upload.utils.UploadUtil;
 import com.backendsys.utils.response.PageEntity;
@@ -43,6 +45,9 @@ public class CrtGenerateServiceImpl implements CrtGenerateService {
     @Autowired
     private ComfyUISocketService comfyUISocketService;
 
+    @Autowired
+    private Text2ImageService text2ImageService;
+
     @Autowired
     private CrtModelDao crtModelDao;
     @Autowired
@@ -78,14 +83,14 @@ public class CrtGenerateServiceImpl implements CrtGenerateService {
 
         CrtDramaProjectStoryboard storyboardDetail = crtDramaProjectStoryboardDao.selectById(drama_project_storyboard_id);
         if (storyboardDetail == null) throw new CustException("分镜不存在");
-        System.out.println("分镜详情: " + JSONUtil.toJsonStr(storyboardDetail));
+        System.out.println("- 分镜详情: " + JSONUtil.toJsonStr(storyboardDetail));
 
         Long drama_project_id = storyboardDetail.getDrama_project_id();
         LambdaQueryWrapper<CrtDramaProjectSettings> wrapperSettings = new LambdaQueryWrapper<>();
         wrapperSettings.eq(CrtDramaProjectSettings::getDrama_project_id, drama_project_id);
         List<CrtDramaProjectSettings> settingsDetail = crtDramaProjectSettingsDao.selectList(wrapperSettings);
         if (settingsDetail == null) throw new CustException("项目配置不存在");
-        System.out.println("项目配置: " + JSONUtil.toJsonStr(settingsDetail));
+        System.out.println("- 项目配置: " + JSONUtil.toJsonStr(settingsDetail));
 
         // 项目配置类型 (1:生图配置, 2:生视频配置)
         CrtDramaProjectSettings settings_image = settingsDetail.stream().filter(item -> item.getDrama_project_setting_type() == 1).findFirst().orElse(null);
@@ -95,35 +100,35 @@ public class CrtGenerateServiceImpl implements CrtGenerateService {
 
         // 用于更新的参数实体类
         CrtDramaProjectStoryboard entity = new CrtDramaProjectStoryboard();
-        LambdaQueryWrapper<CrtDramaProjectStoryboard> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(CrtDramaProjectStoryboard::getId, drama_project_storyboard_id);
 
 
 
         // 文生图提示词
-        String text_to_image_prompt = crtDramaProjectStoryboard.getText_to_image_prompt();
-        // [更新] 文生图提示词
-        entity.setText_to_image_prompt(text_to_image_prompt);
+        String prompt_text = crtDramaProjectStoryboard.getText_to_image_prompt();
+
 
         // == 从 storboard detail 获取参数 =============================================================================
         Integer param_batch_size = storyboardDetail.getParam_batch_size();                        // 生成图片数量
         Float param_prompt_flux_guidance = storyboardDetail.getParam_prompt_flux_guidance();      // 提示词引导系数
         String param_sampler = SamplerEnums.getValueByKey(storyboardDetail.getParam_sampler());   // 采样器
-        Integer param_step = storyboardDetail.getParam_step();
+        Integer param_step = storyboardDetail.getParam_step();                                    // 步数
 
         // 随机种子 (默认值:1,范围:(1:随机, 2:自定义))
-        Integer param_seed = storyboardDetail.getParam_seed();
-        String param_seed_custom = storyboardDetail.getParam_seed_custom();
-        if (param_seed == 1) {
-            param_seed_custom = Convert.toStr(DateUtil.current());   // 生成一个随机值 (毫秒时间戳)
-            // [更新] 种子值
-            entity.setParam_seed_custom(param_seed_custom);
-        }
+        Integer param_seed_type = storyboardDetail.getParam_seed_type();
+        String param_seed = (param_seed_type == 1) ?
+                Convert.toStr(DateUtil.current()) :
+                storyboardDetail.getParam_seed();
 
-        // [db] 更新分集记录
-        crtDramaProjectStoryboardDao.update(entity, wrapper);
+        entity.setParam_seed(param_seed);
+        entity.setText_to_image_prompt(prompt_text);
 
+        // [db] 更新分集记录 (种子值、提示词)
+        LambdaQueryWrapper<CrtDramaProjectStoryboard> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(CrtDramaProjectStoryboard::getId, drama_project_storyboard_id);
+        crtDramaProjectStoryboardDao.update(entity, wrapper);
 
+        Integer width = 1280;
+        Integer height = 720;
 
         // [db] 获取基础模型 (从项目配置)
         Long model_id = settings_image.getModel_id();
@@ -135,9 +140,6 @@ public class CrtGenerateServiceImpl implements CrtGenerateService {
 
         // ===========================================================================================================
 
-
-
-        // -- 前端生成的UUID ---------------------------------------------
         String client_id = Convert.toStr(UUID.randomUUID());
 
         // -- [ComfyUI] 创建 WebSocket 监听连接 --------------------------
@@ -145,403 +147,22 @@ public class CrtGenerateServiceImpl implements CrtGenerateService {
         params.put("drama_project_storyboard_id", drama_project_storyboard_id);
         comfyUISocketService.connectToSse(client_id, 8000, params).subscribe();
 
-        // -------------------------------------------------------------
-        // [ComfyUI-基础生图]
-//        String prompt = "{" +
-//                    "\"3\": {" +
-//                        "\"inputs\": {" +
-//                            "\"seed\": 449753344472378," +
-//                            "\"steps\": 20," +
-//                            "\"cfg\": 8," +
-//                            "\"sampler_name\": \"euler\"," +
-//                            "\"scheduler\": \"normal\"," +
-//                            "\"denoise\": 1," +
-//                            "\"model\": [\"4\", 0]," +
-//                            "\"positive\": [\"6\", 0]," +
-//                            "\"negative\": [\"7\", 0]," +
-//                            "\"latent_image\": [\"5\", 0]" +
-//                        "}," +
-//                        "\"class_type\": \"KSampler\"," +
-//                        "\"_meta\": { \"title\": \"K采样器\" }" +
-//                    "}," +
-//                    "\"4\": {" +
-//                        "\"inputs\": {" +
-//                            "\"ckpt_name\": \"v1-5-pruned-emaonly-fp16.safetensors\"" +
-//                        "}," +
-//                        "\"class_type\": \"CheckpointLoaderSimple\"," +
-//                        "\"_meta\": { \"title\": \"Checkpoint加载器(简易)\" }" +
-//                    "}," +
-//                    "\"5\": {" +
-//                        "\"inputs\": {" +
-//                            "\"width\": 512, \"height\": 512, \"batch_size\": 1" +
-//                        "}," +
-//                        "\"class_type\": \"EmptyLatentImage\"," +
-//                        "\"_meta\": { \"title\": \"空Latent图像\" }" +
-//                    "}," +
-//                    "\"6\": {" +
-//                        "\"inputs\": {" +
-//                            "\"text\": \"beautiful scenery nature glass bottle landscape, , purple galaxy bottle,\"," +
-//                            "\"speak_and_recognation\": {" +
-//                                "\"__value__\": [false, true]" +
-//                            "}," +
-//                            "\"clip\": [\"4\", 1]" +
-//                        "}," +
-//                        "\"class_type\": \"CLIPTextEncode\"," +
-//                        "\"_meta\": { \"title\": \"CLIP文本编码\" }" +
-//                    "}," +
-//                    "\"7\": {" +
-//                        "\"inputs\": {" +
-//                            "\"text\": \"text, watermark\"," +
-//                            "\"speak_and_recognation\": {" +
-//                                "\"__value__\": [false, true]" +
-//                            "}," +
-//                            "\"clip\": [\"4\", 1]" +
-//                        "}," +
-//                        "\"class_type\": \"CLIPTextEncode\"," +
-//                        "\"_meta\": { \"title\": \"CLIP文本编码\" }" +
-//                    "}," +
-//                    "\"8\": {" +
-//                        "\"inputs\": {" +
-//                            "\"samples\": [\"3\", 0]," +
-//                            "\"vae\": [\"4\", 2]," +
-//                        "}," +
-//                        "\"class_type\": \"VAEDecode\"," +
-//                        "\"_meta\": { \"title\": \"VAE解码\" }" +
-//                    "}," +
-//                    "\"9\": {" +
-//                        "\"inputs\": {" +
-//                            "\"filename_prefix\": \"ComfyUI\"," +
-//                            "\"images\": [\"8\", 0]" +
-//                        "}," +
-//                        "\"class_type\": \"SaveImage\"," +
-//                        "\"_meta\": { \"title\": \"保存图像\" }" +
-//                    "}," +
-//                "}";
-
-        // ComfyUI - 7.4生图.json
-        String prompt = "{"+
-                "  \"3\": {"+
-                "    \"inputs\": {"+
-                "      \"text\": ["+
-                "        \"120\","+
-                "        0"+
-                "      ],"+
-                "      \"speak_and_recognation\": {"+
-                "        \"__value__\": ["+
-                "          false,"+
-                "          true"+
-                "        ]"+
-                "      },"+
-                "      \"clip\": ["+
-                "        \"151\","+
-                "        1"+
-                "      ]"+
-                "    },"+
-                "    \"class_type\": \"CLIPTextEncode\","+
-                "    \"_meta\": {"+
-                "      \"title\": \"CLIP文本编码\""+
-                "    }"+
-                "  },"+
-                "  \"13\": {"+
-                "    \"inputs\": {"+
-                "      \"guidance\": " + param_prompt_flux_guidance + ","+
-                "      \"conditioning\": ["+
-                "        \"3\","+
-                "        0"+
-                "      ]"+
-                "    },"+
-                "    \"class_type\": \"FluxGuidance\","+
-                "    \"_meta\": {"+
-                "      \"title\": \"Flux引导\""+
-                "    }"+
-                "  },"+
-                "  \"15\": {"+
-                "    \"inputs\": {"+
-                "      \"model\": ["+
-                "        \"152\","+
-                "        0"+
-                "      ],"+
-                "      \"conditioning\": ["+
-                "        \"13\","+
-                "        0"+
-                "      ]"+
-                "    },"+
-                "    \"class_type\": \"BasicGuider\","+
-                "    \"_meta\": {"+
-                "      \"title\": \"基本引导器\""+
-                "    }"+
-                "  },"+
-                "  \"31\": {"+
-                "    \"inputs\": {"+
-                "      \"samples\": ["+
-                "        \"32\","+
-                "        0"+
-                "      ],"+
-                "      \"vae\": ["+
-                "        \"151\","+
-                "        2"+
-                "      ]"+
-                "    },"+
-                "    \"class_type\": \"VAEDecode\","+
-                "    \"_meta\": {"+
-                "      \"title\": \"VAE解码\""+
-                "    }"+
-                "  },"+
-                "  \"32\": {"+
-                "    \"inputs\": {"+
-                "      \"noise\": ["+
-                "        \"37\","+
-                "        0"+
-                "      ],"+
-                "      \"guider\": ["+
-                "        \"15\","+
-                "        0"+
-                "      ],"+
-                "      \"sampler\": ["+
-                "        \"84\","+
-                "        0"+
-                "      ],"+
-                "      \"sigmas\": ["+
-                "        \"150\","+
-                "        0"+
-                "      ],"+
-                "      \"latent_image\": ["+
-                "        \"90\","+
-                "        0"+
-                "      ]"+
-                "    },"+
-                "    \"class_type\": \"SamplerCustomAdvanced\","+
-                "    \"_meta\": {"+
-                "      \"title\": \"自定义采样器(高级)\""+
-                "    }"+
-                "  },"+
-                "  \"37\": {"+
-                "    \"inputs\": {"+
-                "      \"noise_seed\": " + param_seed_custom +
-                "    },"+
-                "    \"class_type\": \"RandomNoise\","+
-                "    \"_meta\": {"+
-                "      \"title\": \"随机噪波\""+
-                "    }"+
-                "  },"+
-                "  \"38\": {"+
-                "    \"inputs\": {"+
-                "      \"text\": \"\","+
-                "      \"speak_and_recognation\": {"+
-                "        \"__value__\": ["+
-                "          false,"+
-                "          true"+
-                "        ]"+
-                "      }"+
-                "    },"+
-                "    \"class_type\": \"TextInput_\","+
-                "    \"_meta\": {"+
-                "      \"title\": \"触发词\""+
-                "    }"+
-                "  },"+
-                "  \"51\": {"+
-                "    \"inputs\": {"+
-                "      \"text\": \"fenjing_" + drama_project_storyboard_id + "\","+
-                "      \"speak_and_recognation\": {"+
-                "        \"__value__\": ["+
-                "          false,"+
-                "          true"+
-                "        ]"+
-                "      }"+
-                "    },"+
-                "    \"class_type\": \"TextInput_\","+
-                "    \"_meta\": {"+
-                "      \"title\": \"分镜号\""+
-                "    }"+
-                "  },"+
-                "  \"84\": {"+
-                "    \"inputs\": {"+
-                "      \"sampler_name\": \"" + param_sampler + "\""+
-                "    },"+
-                "    \"class_type\": \"KSamplerSelect\","+
-                "    \"_meta\": {"+
-                "      \"title\": \"K采样器选择\""+
-                "    }"+
-                "  },"+
-                "  \"90\": {"+
-                "    \"inputs\": {"+
-                "      \"width\": ["+
-                "        \"121\","+
-                "        0"+
-                "      ],"+
-                "      \"height\": ["+
-                "        \"122\","+
-                "        0"+
-                "      ],"+
-                "      \"batch_size\": " + param_batch_size +
-                "    },"+
-                "    \"class_type\": \"EmptySD3LatentImage\","+
-                "    \"_meta\": {"+
-                "      \"title\": \"空Latent图像(SD3)\""+
-                "    }"+
-                "  },"+
-                "  \"91\": {"+
-                "    \"inputs\": {"+
-                "      \"filename_prefix\": ["+
-                "        \"51\","+
-                "        0"+
-                "      ],"+
-                "      \"images\": ["+
-                "        \"31\","+
-                "        0"+
-                "      ]"+
-                "    },"+
-                "    \"class_type\": \"SaveImage\","+
-                "    \"_meta\": {"+
-                "      \"title\": \"保存图像\""+
-                "    }"+
-                "  },"+
-                "  \"120\": {"+
-                "    \"inputs\": {"+
-                "      \"text_0\": \", a pig\","+
-                "      \"text\": ["+
-                "        \"148\","+
-                "        0"+
-                "      ]"+
-                "    },"+
-                "    \"class_type\": \"PandasShowText\","+
-                "    \"_meta\": {"+
-                "      \"title\": \"Pandas Show Text\""+
-                "    }"+
-                "  },"+
-                "  \"121\": {"+
-                "    \"inputs\": {"+
-                "      \"value\": 1280"+
-                "    },"+
-                "    \"class_type\": \"easy int\","+
-                "    \"_meta\": {"+
-                "      \"title\": \"整数\""+
-                "    }"+
-                "  },"+
-                "  \"122\": {"+
-                "    \"inputs\": {"+
-                "      \"value\": 720"+
-                "    },"+
-                "    \"class_type\": \"easy int\","+
-                "    \"_meta\": {"+
-                "      \"title\": \"整数\""+
-                "    }"+
-                "  },"+
-                "  \"146\": {"+
-                "    \"inputs\": {"+
-                "      \"from_translate\": \"auto\","+
-                "      \"to_translate\": \"english\","+
-                "      \"add_proxies\": false,"+
-                "      \"proxies\": \"\","+
-                "      \"auth_data\": \"\","+
-                "      \"service\": \"BaiduTranslator [appid and appkey]\","+
-                "      \"text\": ["+
-                "        \"153\","+
-                "        0"+
-                "      ],"+
-                "      \"Show proxy\": \"proxy_hide\","+
-                "      \"Show authorization\": \"authorization_hide\","+
-                "      \"speak_and_recognation\": {"+
-                "        \"__value__\": ["+
-                "          false,"+
-                "          true"+
-                "        ]"+
-                "      }"+
-                "    },"+
-                "    \"class_type\": \"DeepTranslatorTextNode\","+
-                "    \"_meta\": {"+
-                "      \"title\": \"Deep Translator Text Node\""+
-                "    }"+
-                "  },"+
-                "  \"148\": {"+
-                "    \"inputs\": {"+
-                "      \"delimiter\": \", \","+
-                "      \"string1\": ["+
-                "        \"38\","+
-                "        0"+
-                "      ],"+
-                "      \"string2\": ["+
-                "        \"146\","+
-                "        0"+
-                "      ]"+
-                "    },"+
-                "    \"class_type\": \"JoinStrings\","+
-                "    \"_meta\": {"+
-                "      \"title\": \"Join Strings\""+
-                "    }"+
-                "  },"+
-                "  \"150\": {"+
-                "    \"inputs\": {"+
-                "      \"scheduler\": \"normal\","+
-                "      \"steps\": " + param_step + ","+
-                "      \"denoise\": 1,"+
-                "      \"model\": ["+
-                "        \"152\","+
-                "        0"+
-                "      ]"+
-                "    },"+
-                "    \"class_type\": \"BasicScheduler\","+
-                "    \"_meta\": {"+
-                "      \"title\": \"基本调度器\""+
-                "    }"+
-                "  },"+
-                "  \"151\": {"+
-                "    \"inputs\": {"+
-                "      \"ckpt_name\": \"" + model_name + "\""+
-                "    },"+
-                "    \"class_type\": \"CheckpointLoaderSimple\","+
-                "    \"_meta\": {"+
-                "      \"title\": \"Checkpoint加载器(简易)\""+
-                "    }"+
-                "  },"+
-                "  \"152\": {"+
-                "    \"inputs\": {"+
-                "      \"lora_name\": \"【FLUX】都市高武推文 _ 异能 法术 战斗_v1.0.safetensors\","+
-                "      \"strength_model\": 0,"+
-                "      \"model\": ["+
-                "        \"151\","+
-                "        0"+
-                "      ]"+
-                "    },"+
-                "    \"class_type\": \"LoraLoaderModelOnly\","+
-                "    \"_meta\": {"+
-                "      \"title\": \"LoRA加载器(仅模型)\""+
-                "    }"+
-                "  },"+
-                "  \"153\": {"+
-                "    \"inputs\": {"+
-                "      \"text\": \"" + text_to_image_prompt + "\","+
-                "      \"speak_and_recognation\": {"+
-                "        \"__value__\": ["+
-                "          false,"+
-                "          true"+
-                "        ]"+
-                "      }"+
-                "    },"+
-                "    \"class_type\": \"TextInput_\","+
-                "    \"_meta\": {"+
-                "      \"title\": \"Text Input ♾️Mixlab\""+
-                "    }"+
-                "  }"+
-                "}"
-        ;
-
-        // -------------------------------------------------------------
-
-        JSONObject prompt_object = JSONUtil.parseObj(prompt);
-        System.out.println("prompt_object: " + prompt_object);
-
-
-
-        // 这里在点击生成的时候,就应该先创建一条占位数据,并给予 [生成状态],[任务原始JSON]
-
-
-
-
-        // [ComfyUI] 执行任务
-        Mono<CFPromptResponse> cfPromptResponseMono = comfyUIService.prompt(client_id, prompt_object);
-        CFPromptResponse response = cfPromptResponseMono.block();
-        response.setClient_id(client_id);
+        // -- [ComfyUI] 生图参数 ----------------------------------------
+        Text2Image text2Image = new Text2Image();
+        text2Image.setBatch_size(param_batch_size);
+        text2Image.setPrompt_flux_guidance(param_prompt_flux_guidance);
+        text2Image.setSampler(param_sampler);
+        text2Image.setStep(param_step);
+//        text2Image.setWidth(width);
+        text2Image.setWidth(400);
+//        text2Image.setHeight(height);
+        text2Image.setHeight(200);
+        text2Image.setModel_name(model_name);
+        text2Image.setPrompt_text(prompt_text);
+        text2Image.setSeed(param_seed);
+
+        // -- [ComfyUI] 生图 --------------------------------------------
+        CFPromptResponse response = text2ImageService.generateText2Image(client_id, text2Image);
         System.out.println("结果: " + response);
         // 结果: CFPromptResponse(client_id=1a8a2d01-5500-437f-bb11-7a986130da48, prompt_id=c74501ed-6755-48f8-a440-aef3474b523c, number=47, node_errors={}, error=null)
 

+ 16 - 0
src/main/java/com/backendsys/modules/sdk/comfyui/entity/Text2Image.java

@@ -0,0 +1,16 @@
+package com.backendsys.modules.sdk.comfyui.entity;
+
+import lombok.Data;
+
+@Data
+public class Text2Image {
+    private Integer batch_size;           // 生成图片数量
+    private Float prompt_flux_guidance;   // 提示词引导系数
+    private String sampler;               // 采样器
+    private Integer step;                 // 步数
+    private Integer width;                // 图片宽度
+    private Integer height;               // 图片高度
+    private String model_name;            // 模型名称
+    private String prompt_text;           // 提示词
+    private String seed;                  // 种子值
+}

+ 2 - 1
src/main/java/com/backendsys/modules/sdk/comfyui/service/ComfyUIService.java

@@ -3,6 +3,7 @@ package com.backendsys.modules.sdk.comfyui.service;
 import cn.hutool.json.JSONObject;
 import com.backendsys.modules.sdk.comfyui.entity.CFPromptResponse;
 import com.backendsys.modules.sdk.comfyui.entity.CFQueue;
+import com.backendsys.modules.sdk.comfyui.entity.Text2Image;
 import reactor.core.publisher.Mono;
 
 public interface ComfyUIService {
@@ -10,7 +11,7 @@ public interface ComfyUIService {
     // [ComfyUI] 查询任务队列
     Mono<CFQueue> getQueue();
 
-    // [ComfyUI] 执行任务
+    // [ComfyUI] 执行任务 (通用)
     Mono<CFPromptResponse> prompt(String client_id, JSONObject prompt);
 
 }

+ 1 - 0
src/main/java/com/backendsys/modules/sdk/comfyui/service/ComfyUISocketService.java

@@ -2,6 +2,7 @@ package com.backendsys.modules.sdk.comfyui.service;
 
 import reactor.core.publisher.Mono;
 
+import java.util.List;
 import java.util.Map;
 
 public interface ComfyUISocketService {

+ 15 - 0
src/main/java/com/backendsys/modules/sdk/comfyui/service/Text2ImageService.java

@@ -0,0 +1,15 @@
+package com.backendsys.modules.sdk.comfyui.service;
+
+import com.backendsys.modules.sdk.comfyui.entity.CFPromptResponse;
+import com.backendsys.modules.sdk.comfyui.entity.Text2Image;
+import reactor.core.publisher.Mono;
+
+public interface Text2ImageService {
+
+    // [ComfyUI] 文生图 (7.4生图.json)
+    CFPromptResponse generateText2Image(String client_id, Text2Image text2Image);
+
+    // [ComfyUI] 文生图 (基础生图)
+    CFPromptResponse generateText2ImageSimple(String client_id, Text2Image text2Image);
+
+}

+ 1 - 7
src/main/java/com/backendsys/modules/sdk/comfyui/service/impl/ComfyUIServiceImpl.java → src/main/java/com/backendsys/modules/sdk/comfyui/service/impl/ComfyuiServiceImpl.java

@@ -1,6 +1,5 @@
 package com.backendsys.modules.sdk.comfyui.service.impl;
 
-import cn.hutool.core.convert.Convert;
 import cn.hutool.json.JSONObject;
 import com.backendsys.modules.common.Filter.WebClientFilter;
 import com.backendsys.modules.sdk.comfyui.entity.CFPromptRequest;
@@ -11,18 +10,13 @@ import org.springframework.beans.factory.annotation.Value;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
 import org.springframework.stereotype.Service;
-import org.springframework.util.LinkedMultiValueMap;
-import org.springframework.util.MultiValueMap;
 import org.springframework.web.reactive.function.client.WebClient;
-import org.springframework.web.util.UriComponentsBuilder;
 import reactor.core.publisher.Mono;
 
-import java.util.Map;
-import java.util.UUID;
 import java.util.function.Consumer;
 
 @Service
-public class ComfyUIServiceImpl implements ComfyUIService {
+public class ComfyuiServiceImpl implements ComfyUIService {
 
     @Value("${comfyui.host}")
     private String COMFYUI_HOST;

+ 77 - 91
src/main/java/com/backendsys/modules/sdk/comfyui/service/impl/ComfyUISocketServiceImpl.java → src/main/java/com/backendsys/modules/sdk/comfyui/service/impl/ComfyuiSocketServiceImpl.java

@@ -4,18 +4,14 @@ import cn.hutool.core.convert.Convert;
 import cn.hutool.json.JSONArray;
 import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
-import com.backendsys.modules.ai.chat.entity.ChatSseMessage;
 import com.backendsys.modules.common.config.security.utils.SecurityUtil;
 import com.backendsys.modules.crt.dao.CrtGenerateImageDao;
 import com.backendsys.modules.crt.entity.CrtGenerateImage;
 import com.backendsys.modules.sdk.comfyui.enums.TypeEnums;
 import com.backendsys.modules.sdk.comfyui.service.ComfyUISocketService;
-import com.backendsys.modules.sdk.douyincloud.tos.service.DouyinTosService;
-import com.backendsys.modules.sdk.tencentcloud.cos.service.TencentCosService;
 import com.backendsys.modules.sse.entity.SseResponse;
 import com.backendsys.modules.sse.entity.SseResponseEnum;
 import com.backendsys.modules.sse.utils.SseUtil;
-import com.backendsys.modules.system.service.SysCommonService;
 import com.backendsys.modules.upload.entity.SysFileResult;
 import com.backendsys.modules.upload.service.SysFileService;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -32,14 +28,13 @@ import reactor.netty.http.client.HttpClient;
 import java.net.URI;
 import java.time.Duration;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentHashMap;
 
 @Service
-public class ComfyUISocketServiceImpl implements ComfyUISocketService {
+public class ComfyuiSocketServiceImpl implements ComfyUISocketService {
 
     @Autowired
     private SseUtil sseUtil;
@@ -74,30 +69,30 @@ public class ComfyUISocketServiceImpl implements ComfyUISocketService {
      * [ComfyUI] 创建 WebSocket 监听连接
      */
     @Override
-    public Mono<Void> connect(String clientId, Integer port) {
+    public Mono<Void> connect(String client_id, Integer port) {
 
         String wsUrl =  "ws://" + COMFYUI_HOST + ":" + port + "/ws";
         return Mono.defer(() -> {
-            if (sessions.containsKey(clientId)) {
-                return Mono.error(new IllegalStateException("Connection already exists for client: " + clientId));
+            if (sessions.containsKey(client_id)) {
+                return Mono.error(new IllegalStateException("Connection already exists for client: " + client_id));
             }
             // 动态创建带有认证头的客户端
             WebSocketClient clientWithAuth = createWebSocketClientWithToken(COMFYUI_TOKEN);
-            return clientWithAuth.execute(URI.create(wsUrl + "?clientId=" + clientId), session -> {
+            return clientWithAuth.execute(URI.create(wsUrl + "?clientId=" + client_id), session -> {
                 // 保存会话
-                sessions.put(clientId, session);
+                sessions.put(client_id, session);
                 // 接收消息
                 Flux<String> incomingMessages = session.receive()
                     .map(WebSocketMessage::getPayloadAsText)
                     .doOnNext(message -> {
-                        System.out.println("(doOnNext) Received from " + clientId + ": " + message);
+                        System.out.println("(doOnNext) Received from " + client_id + ": " + message);
                     })
                     .doOnError(e -> {
-                        System.err.println("(doOnError) Error for " + clientId + ": " + e.getMessage());
+                        System.err.println("(doOnError) Error for " + client_id + ": " + e.getMessage());
                     })
                     .doFinally(signal -> {
-                        System.out.println("(doFinally) Connection closed for " + clientId + ": " + signal);
-                        sessions.remove(clientId);
+                        System.out.println("(doFinally) Connection closed for " + client_id + ": " + signal);
+                        sessions.remove(client_id);
                     });
                 // 需要返回一个Mono<Void>来表示处理完成
                 return incomingMessages.then();
@@ -109,120 +104,72 @@ public class ComfyUISocketServiceImpl implements ComfyUISocketService {
      * [ComfyUI] 创建 WebSocket 监听连接 (转发到 SSE)
      */
     @Override
-    public Mono<Void> connectToSse(String clientId, Integer port) {
-        return connectToSse(clientId, port, null);
+    public Mono<Void> connectToSse(String client_id, Integer port) {
+        return connectToSse(client_id, port, null);
     }
     @Override
-    public Mono<Void> connectToSse(String clientId, Integer port, Map<String, Object> params) {
+    public Mono<Void> connectToSse(String client_id, Integer port, Map<String, Object> params) {
 
-        CrtGenerateImage entity = new CrtGenerateImage();
-
-        // Websocket 获取不到上下文信息,所以 user_id 需要从外部传递
+        // 由于 Websocket 获取不到上下文信息,所以 user_id 不能在 socket 周期获取
         Long user_id = SecurityUtil.getUserId();
-        entity.setUser_id(user_id);
 
         String wsUrl =  "ws://" + COMFYUI_HOST + ":" + port + "/ws";
         return Mono.defer(() -> {
-            if (sessions.containsKey(clientId)) {
-                return Mono.error(new IllegalStateException("Connection already exists for client: " + clientId));
+            if (sessions.containsKey(client_id)) {
+                return Mono.error(new IllegalStateException("Connection already exists for client: " + client_id));
             }
             // 动态创建带有认证头的客户端
             WebSocketClient clientWithAuth = createWebSocketClientWithToken(COMFYUI_TOKEN);
-            return clientWithAuth.execute(URI.create(wsUrl + "?clientId=" + clientId), session -> {
+            return clientWithAuth.execute(URI.create(wsUrl + "?clientId=" + client_id), session -> {
                 // 保存会话
-                sessions.put(clientId, session);
+                sessions.put(client_id, session);
                 // 接收消息
 
                 System.out.println("------ wsUrl: " + wsUrl + " ------");
-                System.out.println("------ connectToSse clientId: " + clientId + ", user_id: " + user_id + " ------");
+                System.out.println("------ connectToSse client_id: " + client_id + ", user_id: " + user_id + " ------");
 
                 Flux<String> incomingMessages = session.receive()
                         .map(WebSocketMessage::getPayloadAsText)
                         .doOnNext(message -> {
-                            System.out.println("(doOnNext) Received from " + clientId + ": " + message);
+                            System.out.println("(doOnNext) Received from " + client_id + ": " + message);
 
                             JSONObject data = JSONUtil.parseObj(message);
-                            String type = Convert.toStr(data.get("type"));
 
-                            // == [任务执行成功] =======================================================
-                            // { "type": "executed", "data": { "output": { "images": [{ "filename": "ComfyUI_00117_.png" }] } } }
+                            // == [任务执行完成] =======================================================
+                            // { "type": "executed", .. }
+                            String type = Convert.toStr(data.get("type"));
                             if (TypeEnums.EXECUTED.getValue().equals(type)) {
 
                                 JSONObject dataChildren = JSONUtil.parseObj(data.get("data"));
                                 JSONObject output = JSONUtil.parseObj(dataChildren.get("output"));
 
-                                // -- [生成图片] ------------------------------------------------------
+                                // -- [生成图片 -> 转存图片 -> 新增记录] ------------------------------------------------------
                                 // 由于图片地址不是公开的,需要加 Token 访问,因此不能公开返回原始图片地址,比如:
                                 // http://43.128.1.201:8000/api/view?filename=fenjing_1_00012_.png&token=$2b$12$.MR4qGaFetN1FPQzbfyIrehsyjnPJ12xAZhR/l7KZpLkUPQTCG4gy
-
+                                // 因此,直接在 ComfyUI 的物理目录上构建 nginx 静态资源访问目录
                                 Object imagesObj = output.get("images");
                                 if (imagesObj != null) {
-                                    JSONArray images = JSONUtil.parseArray(imagesObj);
-                                    // [{"filename": "ComfyUI_00122_.png", "subfolder": "", "type": "output"}]
-                                    // http://43.128.1.201:8001/api/view?filename=ComfyUI_00117_.png
-                                    // http://43.128.1.201:8001/api/view?filename=ComfyUI_00117_.png&preview=1
-                                    List<String> images_path = new ArrayList<>();
-                                    if (images.size() > 0) {
-                                        for (int i = 0; i < images.size(); i++) {
-                                            JSONObject image = images.getJSONObject(i);
-                                            String filename = image.getStr("filename");
-
-                                            // ComfyUI + Nginx 输出域名转发
-//                                            String filepath = "http://" + COMFYUI_HOST + ":" + port + "/api/view?filename=" + filename;
-//                                            String filepath_with_token = filepath + "&token=" + COMFYUI_TOKEN;
-
-                                            // ComfyUI 输出的临时目录
-                                            String filepath = "http://o.daogu.ai/" + port + "/" + filename;
-
-                                            // -- [图片转存储存桶] -------------------------------------
-                                            SysFileResult result = sysFileService.urlToUploadFile(filepath, user_id);
-                                            System.out.println("urlToUploadFile (result) = " + result);
-
-                                            // -- [记录到生成图片记录表] --------------------------------
-                                            if (params != null) {
-
-                                                // 创建一个 CompletableFuture 来执行异步任务
-                                                CompletableFuture.runAsync(() -> {
-
-                                                    Long drama_project_storyboard_id = Convert.toLong(params.get("drama_project_storyboard_id"));
-                                                    String prompt_id = Convert.toStr(dataChildren.get("prompt_id"));
-                                                    if (drama_project_storyboard_id != null) {
-                                                        entity.setDrama_project_storyboard_id(drama_project_storyboard_id);
-                                                        entity.setPrompt_id(prompt_id);
-                                                        entity.setUrl_origin(filepath);
-                                                        entity.setUrl(result.getUrl());
-                                                        entity.setTarget(result.getTarget());
-                                                        crtGenerateImageDao.insert(entity);
-                                                    }
-
-                                                });
-
-                                            }
-                                            // ------------------------------------------------------
-
-                                            images_path.add(filepath);
-
-                                        }
-                                    }
+                                    String prompt_id = Convert.toStr(dataChildren.get("prompt_id"));
+                                    Long drama_project_storyboard_id = Convert.toLong(params.get("drama_project_storyboard_id"));
+                                    List<String> images_path = imagesToRecord(user_id, prompt_id, port, imagesObj, drama_project_storyboard_id);
                                     output.put("images_path", images_path);
                                     dataChildren.put("output", output);
                                     data.put("data", dataChildren);
                                 }
-                                // ------------------------------------------------------------------
 
                             }
-                            // ======================================================================
+                            // ========================================================================
 
                             sseUtil.send(user_id, new SseResponse(SseResponseEnum.COMFYUI, data).toJsonStr());
                         })
                         .doOnError(e -> {
-                            System.err.println("(doOnError) Error for " + clientId + ": " + e.getMessage());
+                            System.err.println("(doOnError) Error for " + client_id + ": " + e.getMessage());
                             sseUtil.send(user_id, new SseResponse(SseResponseEnum.COMFYUI, e.getMessage()).toJsonStr());
                         })
                         .doFinally(signal -> {
-                            System.out.println("(doFinally) Connection closed for " + clientId + ": " + signal);
+                            System.out.println("(doFinally) Connection closed for " + client_id + ": " + signal);
                             sseUtil.send(user_id, new SseResponse(SseResponseEnum.COMFYUI, signal).toJsonStr());
-                            sessions.remove(clientId);
+                            sessions.remove(client_id);
                             System.out.println("---------------------------------------------------------");
                         });
                 // 需要返回一个Mono<Void>来表示处理完成
@@ -233,23 +180,23 @@ public class ComfyUISocketServiceImpl implements ComfyUISocketService {
 
     /**
      * [ComfyUI] 断开 WebSocket 监听连接
-     * @param clientId 客户端ID
+     * @param client_id 客户端ID
      * @return Mono<Void> 表示断开操作
      */
     @Override
-    public Mono<Void> disconnect(String clientId) {
+    public Mono<Void> disconnect(String client_id) {
         return Mono.fromRunnable(() -> {
-            WebSocketSession session = sessions.get(clientId);
+            WebSocketSession session = sessions.get(client_id);
             if (session != null) {
-                System.out.println("disconnect success! clientId: " + clientId);
+                System.out.println("disconnect success! client_id: " + client_id);
 
                 Long user_id = SecurityUtil.getUserId();
                 if (user_id != null) {
-                    sseUtil.send(user_id, new SseResponse(SseResponseEnum.COMFYUI, "disconnect success! clientId: " + clientId).toJsonStr());
+                    sseUtil.send(user_id, new SseResponse(SseResponseEnum.COMFYUI, "disconnect success! client_id: " + client_id).toJsonStr());
                 }
 
                 session.close().subscribe();
-                sessions.remove(clientId);
+                sessions.remove(client_id);
             }
         });
     }
@@ -262,4 +209,43 @@ public class ComfyUISocketServiceImpl implements ComfyUISocketService {
         return Flux.fromIterable(sessions.keySet());
     }
 
+    // 转存图片
+    private List<String> imagesToRecord(Long user_id, String prompt_id, Integer port, Object imagesObj, Long drama_project_storyboard_id) {
+        JSONArray images = JSONUtil.parseArray(imagesObj);
+        List<String> images_path = new ArrayList<>();
+        if (images.size() > 0) {
+            for (int i = 0; i < images.size(); i++) {
+                JSONObject image = images.getJSONObject(i);
+                String filename = image.getStr("filename");
+                String filepath = "http://o.daogu.ai/" + port + "/" + filename;     // 生成图片临时目录
+
+                // -- [图片转存储存桶] -------------------------------------
+                SysFileResult result = sysFileService.urlToUploadFile(filepath, user_id);
+                System.out.println("urlToUploadFile (result) = " + result);
+
+                // -- [记录到生成图片记录表] --------------------------------
+                // 创建一个 CompletableFuture 来执行异步任务
+                CompletableFuture.runAsync(() -> {
+
+                    if (drama_project_storyboard_id != null) {
+                        CrtGenerateImage entity = new CrtGenerateImage();
+                        entity.setUser_id(user_id);
+                        entity.setDrama_project_storyboard_id(drama_project_storyboard_id);
+                        entity.setPrompt_id(prompt_id);
+                        entity.setUrl_origin(filepath);
+                        entity.setUrl(result.getUrl());
+                        entity.setTarget(result.getTarget());
+                        crtGenerateImageDao.insert(entity);
+                    }
+
+                });
+                // ------------------------------------------------------
+
+                images_path.add(filepath);
+
+            }
+        }
+        return images_path;
+    }
+
 }

+ 424 - 0
src/main/java/com/backendsys/modules/sdk/comfyui/service/impl/Text2ImageServiceImpl.java

@@ -0,0 +1,424 @@
+package com.backendsys.modules.sdk.comfyui.service.impl;
+
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.backendsys.modules.sdk.comfyui.entity.CFPromptResponse;
+import com.backendsys.modules.sdk.comfyui.entity.Text2Image;
+import com.backendsys.modules.sdk.comfyui.service.ComfyUIService;
+import com.backendsys.modules.sdk.comfyui.service.Text2ImageService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import reactor.core.publisher.Mono;
+
+@Service
+public class Text2ImageServiceImpl implements Text2ImageService {
+
+    @Autowired
+    private ComfyUIService comfyUIService;
+
+    /**
+     * [ComfyUI] 文生图 (7.4生图.json)
+     */
+    @Override
+    public CFPromptResponse generateText2Image(String client_id, Text2Image text2Image) {
+
+        String prompt = "{"+
+                "  \"3\": {"+
+                "    \"inputs\": {"+
+                "      \"text\": ["+
+                "        \"120\","+
+                "        0"+
+                "      ],"+
+                "      \"speak_and_recognation\": {"+
+                "        \"__value__\": ["+
+                "          false,"+
+                "          true"+
+                "        ]"+
+                "      },"+
+                "      \"clip\": ["+
+                "        \"151\","+
+                "        1"+
+                "      ]"+
+                "    },"+
+                "    \"class_type\": \"CLIPTextEncode\","+
+                "    \"_meta\": {"+
+                "      \"title\": \"CLIP文本编码\""+
+                "    }"+
+                "  },"+
+                "  \"13\": {"+
+                "    \"inputs\": {"+
+                "      \"guidance\": " + text2Image.getPrompt_flux_guidance() + ","+
+                "      \"conditioning\": ["+
+                "        \"3\","+
+                "        0"+
+                "      ]"+
+                "    },"+
+                "    \"class_type\": \"FluxGuidance\","+
+                "    \"_meta\": {"+
+                "      \"title\": \"Flux引导\""+
+                "    }"+
+                "  },"+
+                "  \"15\": {"+
+                "    \"inputs\": {"+
+                "      \"model\": ["+
+                "        \"152\","+
+                "        0"+
+                "      ],"+
+                "      \"conditioning\": ["+
+                "        \"13\","+
+                "        0"+
+                "      ]"+
+                "    },"+
+                "    \"class_type\": \"BasicGuider\","+
+                "    \"_meta\": {"+
+                "      \"title\": \"基本引导器\""+
+                "    }"+
+                "  },"+
+                "  \"31\": {"+
+                "    \"inputs\": {"+
+                "      \"samples\": ["+
+                "        \"32\","+
+                "        0"+
+                "      ],"+
+                "      \"vae\": ["+
+                "        \"151\","+
+                "        2"+
+                "      ]"+
+                "    },"+
+                "    \"class_type\": \"VAEDecode\","+
+                "    \"_meta\": {"+
+                "      \"title\": \"VAE解码\""+
+                "    }"+
+                "  },"+
+                "  \"32\": {"+
+                "    \"inputs\": {"+
+                "      \"noise\": ["+
+                "        \"37\","+
+                "        0"+
+                "      ],"+
+                "      \"guider\": ["+
+                "        \"15\","+
+                "        0"+
+                "      ],"+
+                "      \"sampler\": ["+
+                "        \"84\","+
+                "        0"+
+                "      ],"+
+                "      \"sigmas\": ["+
+                "        \"150\","+
+                "        0"+
+                "      ],"+
+                "      \"latent_image\": ["+
+                "        \"90\","+
+                "        0"+
+                "      ]"+
+                "    },"+
+                "    \"class_type\": \"SamplerCustomAdvanced\","+
+                "    \"_meta\": {"+
+                "      \"title\": \"自定义采样器(高级)\""+
+                "    }"+
+                "  },"+
+                "  \"37\": {"+
+                "    \"inputs\": {"+
+                "      \"noise_seed\": " + text2Image.getSeed() +
+                "    },"+
+                "    \"class_type\": \"RandomNoise\","+
+                "    \"_meta\": {"+
+                "      \"title\": \"随机噪波\""+
+                "    }"+
+                "  },"+
+                "  \"38\": {"+
+                "    \"inputs\": {"+
+                "      \"text\": \"\","+
+                "      \"speak_and_recognation\": {"+
+                "        \"__value__\": ["+
+                "          false,"+
+                "          true"+
+                "        ]"+
+                "      }"+
+                "    },"+
+                "    \"class_type\": \"TextInput_\","+
+                "    \"_meta\": {"+
+                "      \"title\": \"触发词\""+
+                "    }"+
+                "  },"+
+                "  \"51\": {"+
+                "    \"inputs\": {"+
+                "      \"text\": \"fenjing\","+
+                "      \"speak_and_recognation\": {"+
+                "        \"__value__\": ["+
+                "          false,"+
+                "          true"+
+                "        ]"+
+                "      }"+
+                "    },"+
+                "    \"class_type\": \"TextInput_\","+
+                "    \"_meta\": {"+
+                "      \"title\": \"分镜号\""+
+                "    }"+
+                "  },"+
+                "  \"84\": {"+
+                "    \"inputs\": {"+
+                "      \"sampler_name\": \"" + text2Image.getSampler() + "\""+
+                "    },"+
+                "    \"class_type\": \"KSamplerSelect\","+
+                "    \"_meta\": {"+
+                "      \"title\": \"K采样器选择\""+
+                "    }"+
+                "  },"+
+                "  \"90\": {"+
+                "    \"inputs\": {"+
+                "      \"width\": ["+
+                "        \"121\","+
+                "        0"+
+                "      ],"+
+                "      \"height\": ["+
+                "        \"122\","+
+                "        0"+
+                "      ],"+
+                "      \"batch_size\": " + text2Image.getBatch_size() +
+                "    },"+
+                "    \"class_type\": \"EmptySD3LatentImage\","+
+                "    \"_meta\": {"+
+                "      \"title\": \"空Latent图像(SD3)\""+
+                "    }"+
+                "  },"+
+                "  \"91\": {"+
+                "    \"inputs\": {"+
+                "      \"filename_prefix\": ["+
+                "        \"51\","+
+                "        0"+
+                "      ],"+
+                "      \"images\": ["+
+                "        \"31\","+
+                "        0"+
+                "      ]"+
+                "    },"+
+                "    \"class_type\": \"SaveImage\","+
+                "    \"_meta\": {"+
+                "      \"title\": \"保存图像\""+
+                "    }"+
+                "  },"+
+                "  \"120\": {"+
+                "    \"inputs\": {"+
+                "      \"text_0\": \", a pig\","+
+                "      \"text\": ["+
+                "        \"148\","+
+                "        0"+
+                "      ]"+
+                "    },"+
+                "    \"class_type\": \"PandasShowText\","+
+                "    \"_meta\": {"+
+                "      \"title\": \"Pandas Show Text\""+
+                "    }"+
+                "  },"+
+                "  \"121\": {"+
+                "    \"inputs\": {"+
+                "      \"value\": " + text2Image.getWidth() +
+                "    },"+
+                "    \"class_type\": \"easy int\","+
+                "    \"_meta\": {"+
+                "      \"title\": \"整数\""+
+                "    }"+
+                "  },"+
+                "  \"122\": {"+
+                "    \"inputs\": {"+
+                "      \"value\": " + text2Image.getHeight() +
+                "    },"+
+                "    \"class_type\": \"easy int\","+
+                "    \"_meta\": {"+
+                "      \"title\": \"整数\""+
+                "    }"+
+                "  },"+
+                "  \"146\": {"+
+                "    \"inputs\": {"+
+                "      \"from_translate\": \"auto\","+
+                "      \"to_translate\": \"english\","+
+                "      \"add_proxies\": false,"+
+                "      \"proxies\": \"\","+
+                "      \"auth_data\": \"\","+
+                "      \"service\": \"BaiduTranslator [appid and appkey]\","+
+                "      \"text\": ["+
+                "        \"153\","+
+                "        0"+
+                "      ],"+
+                "      \"Show proxy\": \"proxy_hide\","+
+                "      \"Show authorization\": \"authorization_hide\","+
+                "      \"speak_and_recognation\": {"+
+                "        \"__value__\": ["+
+                "          false,"+
+                "          true"+
+                "        ]"+
+                "      }"+
+                "    },"+
+                "    \"class_type\": \"DeepTranslatorTextNode\","+
+                "    \"_meta\": {"+
+                "      \"title\": \"Deep Translator Text Node\""+
+                "    }"+
+                "  },"+
+                "  \"148\": {"+
+                "    \"inputs\": {"+
+                "      \"delimiter\": \", \","+
+                "      \"string1\": ["+
+                "        \"38\","+
+                "        0"+
+                "      ],"+
+                "      \"string2\": ["+
+                "        \"146\","+
+                "        0"+
+                "      ]"+
+                "    },"+
+                "    \"class_type\": \"JoinStrings\","+
+                "    \"_meta\": {"+
+                "      \"title\": \"Join Strings\""+
+                "    }"+
+                "  },"+
+                "  \"150\": {"+
+                "    \"inputs\": {"+
+                "      \"scheduler\": \"normal\","+
+                "      \"steps\": " + text2Image.getStep() + ","+
+                "      \"denoise\": 1,"+
+                "      \"model\": ["+
+                "        \"152\","+
+                "        0"+
+                "      ]"+
+                "    },"+
+                "    \"class_type\": \"BasicScheduler\","+
+                "    \"_meta\": {"+
+                "      \"title\": \"基本调度器\""+
+                "    }"+
+                "  },"+
+                "  \"151\": {"+
+                "    \"inputs\": {"+
+                "      \"ckpt_name\": \"" + text2Image.getModel_name() + "\""+
+                "    },"+
+                "    \"class_type\": \"CheckpointLoaderSimple\","+
+                "    \"_meta\": {"+
+                "      \"title\": \"Checkpoint加载器(简易)\""+
+                "    }"+
+                "  },"+
+                "  \"152\": {"+
+                "    \"inputs\": {"+
+                "      \"lora_name\": \"【FLUX】都市高武推文 _ 异能 法术 战斗_v1.0.safetensors\","+
+                "      \"strength_model\": 0,"+
+                "      \"model\": ["+
+                "        \"151\","+
+                "        0"+
+                "      ]"+
+                "    },"+
+                "    \"class_type\": \"LoraLoaderModelOnly\","+
+                "    \"_meta\": {"+
+                "      \"title\": \"LoRA加载器(仅模型)\""+
+                "    }"+
+                "  },"+
+                "  \"153\": {"+
+                "    \"inputs\": {"+
+                "      \"text\": \"" + text2Image.getPrompt_text() + "\","+
+                "      \"speak_and_recognation\": {"+
+                "        \"__value__\": ["+
+                "          false,"+
+                "          true"+
+                "        ]"+
+                "      }"+
+                "    },"+
+                "    \"class_type\": \"TextInput_\","+
+                "    \"_meta\": {"+
+                "      \"title\": \"Text Input ♾️Mixlab\""+
+                "    }"+
+                "  }"+
+                "}"
+        ;
+        JSONObject prompt_object = JSONUtil.parseObj(prompt);
+
+        // [ComfyUI] 执行任务
+        Mono<CFPromptResponse> cfPromptResponseMono = comfyUIService.prompt(client_id, prompt_object);
+        CFPromptResponse response = cfPromptResponseMono.block();
+        response.setClient_id(client_id);
+        return response;
+    }
+
+
+    /**
+     * [ComfyUI] 文生图 (基础生图)
+     */
+    @Override
+    public CFPromptResponse generateText2ImageSimple(String client_id, Text2Image text2Image) {
+
+        // [ComfyUI-基础生图]
+        String prompt = "{" +
+                    "\"3\": {" +
+                        "\"inputs\": {" +
+//                            "\"seed\": 449753344472378," +
+                            "\"seed\": " + text2Image.getSeed() + "," +
+//                            "\"steps\": 20," +
+                            "\"steps\": " + text2Image.getStep() + "," +
+                            "\"cfg\": 8," +
+//                            "\"sampler_name\": \"euler\"," +
+                            "\"sampler_name\": \"" + text2Image.getSampler() + "\"," +
+                            "\"scheduler\": \"normal\", \"denoise\": 1," +
+                            "\"model\": [\"4\", 0], \"positive\": [\"6\", 0]," +
+                            "\"negative\": [\"7\", 0], \"latent_image\": [\"5\", 0]" +
+                        "}," +
+                        "\"class_type\": \"KSampler\", \"_meta\": { \"title\": \"K采样器\" }" +
+                    "}," +
+                    "\"4\": {" +
+                        "\"inputs\": {" +
+//                            "\"ckpt_name\": \"v1-5-pruned-emaonly-fp16.safetensors\"" +
+                            "\"ckpt_name\": \"" + text2Image.getModel_name() + "\"" +
+                        "}," +
+                        "\"class_type\": \"CheckpointLoaderSimple\"," +
+                        "\"_meta\": { \"title\": \"Checkpoint加载器(简易)\" }" +
+                    "}," +
+                    "\"5\": {" +
+                        "\"inputs\": {" +
+//                            "\"width\": 512," +
+//                            "\"height\": 512," +
+//                            "\"batch_size\": 1" +
+                            "\"width\": " + text2Image.getWidth() + "," +
+                            "\"height\": " + text2Image.getHeight() + "," +
+                            "\"batch_size\": " + text2Image.getBatch_size() +
+                        "}," +
+                        "\"class_type\": \"EmptyLatentImage\"," +
+                        "\"_meta\": { \"title\": \"空Latent图像\" }" +
+                    "}," +
+                    "\"6\": {" +
+                        "\"inputs\": {" +
+//                            "\"text\": \"beautiful scenery nature glass bottle landscape, , purple galaxy bottle,\"," +
+                            "\"text\": \"" + text2Image.getPrompt_text() + "\"," +
+                            "\"speak_and_recognation\": { \"__value__\": [false, true] }," +
+                            "\"clip\": [\"4\", 1]" +
+                        "}," +
+                        "\"class_type\": \"CLIPTextEncode\", \"_meta\": { \"title\": \"CLIP文本编码\" }" +
+                    "}," +
+                    "\"7\": {" +
+                        "\"inputs\": {" +
+                            "\"text\": \"text, watermark\"," +
+                            "\"speak_and_recognation\": { \"__value__\": [false, true] }," +
+                            "\"clip\": [\"4\", 1]" +
+                        "}," +
+                        "\"class_type\": \"CLIPTextEncode\", \"_meta\": { \"title\": \"CLIP文本编码\" }" +
+                    "}," +
+                    "\"8\": {" +
+                        "\"inputs\": {" +
+                            "\"samples\": [\"3\", 0], \"vae\": [\"4\", 2]," +
+                        "}," +
+                        "\"class_type\": \"VAEDecode\", \"_meta\": { \"title\": \"VAE解码\" }" +
+                    "}," +
+                    "\"9\": {" +
+                        "\"inputs\": {" +
+                            "\"filename_prefix\": \"ComfyUI\", \"images\": [\"8\", 0]" +
+                        "}," +
+                        "\"class_type\": \"SaveImage\", \"_meta\": { \"title\": \"保存图像\" }" +
+                    "}," +
+                "}"
+        ;
+        JSONObject prompt_object = JSONUtil.parseObj(prompt);
+
+        // [ComfyUI] 执行任务
+        Mono<CFPromptResponse> cfPromptResponseMono = comfyUIService.prompt(client_id, prompt_object);
+        CFPromptResponse response = cfPromptResponseMono.block();
+        response.setClient_id(client_id);
+        return response;
+    }
+
+}

+ 1 - 1
src/main/resources/mapper/crt/drama/CrtDramaProjectStoryboardDao.xml

@@ -19,8 +19,8 @@
             <if test="param_prompt_flux_guidance != null and param_prompt_flux_guidance != ''">param_prompt_flux_guidance = #{param_prompt_flux_guidance},</if>
             <if test="param_sampler != null and param_sampler != ''">param_sampler = #{param_sampler},</if>
             <if test="param_step != null and param_step != ''">param_step = #{param_step},</if>
+            <if test="param_seed_type != null and param_seed_type != ''">param_seed_type = #{param_seed_type},</if>
             <if test="param_seed != null and param_seed != ''">param_seed = #{param_seed},</if>
-            <if test="param_seed_custom != null and param_seed_custom != ''">param_seed_custom = #{param_seed_custom},</if>
             <if test="text_to_image_prompt != null and text_to_image_prompt != ''">text_to_image_prompt = #{text_to_image_prompt},</if>
             <if test="param_video_reference_type != null and param_video_reference_type != ''">param_video_reference_type = #{param_video_reference_type},</if>
             <if test="param_video_reference_images != null and param_video_reference_images != ''">param_video_reference_images = #{param_video_reference_images},</if>