Browse Source

Dev Comfyui 生图

tsurumure 2 tháng trước cách đây
mục cha
commit
a71e6a5174

+ 5 - 1
db/sys_user_role_permission.sql

@@ -58,8 +58,12 @@ INSERT INTO sys_user_role_permission(id, parent_id, permission_name, sort) VALUE
                 ('36.2.5.1', '36.2.5', 'AI短剧创作-清空分镜 (自己)', null),
             ('36.2.6', '36.2', 'AI短剧创作-删除分集 (全权限)', null),
                 ('36.2.6.1', '36.2.6', 'AI短剧创作-删除分集 (自己)', null),
+        ('36.3', '36', 'AI短剧创作-生成图片', null),
+        ('36.4', '36', 'AI短剧创作-生成视频', null),
 
-    ('3', -1, '系统用户管理', 900),
+
+
+     ('3', -1, '系统用户管理', 900),
         ('3.1', '3', '系统用户列表 (在线的)', null),
         ('3.2', '3', '系统用户列表', null),
             ('3.2.1', '3.2', '查询用户信息', null),

+ 2 - 1
db/sys_user_role_permission_relation.sql

@@ -116,7 +116,8 @@ INSERT INTO sys_user_role_permission_relation(role_id, permission_id) VALUES
             (1, '36.2.4'), (1, '36.2.4.1'),
             (1, '36.2.5'), (1, '36.2.5.1'),
             (1, '36.2.6'), (1, '36.2.6.1'),
-
+        (1, '36.3'),
+        (1, '36.4'),
 
     (1, '100'),
         (1, '101'),

+ 2 - 1
src/main/java/com/backendsys/modules/crt/controller/CrtGenerateController.java

@@ -7,6 +7,7 @@ import com.backendsys.modules.crt.service.CrtGenerateService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -21,8 +22,8 @@ public class CrtGenerateController {
     private CrtGenerateService crtGenerateService;
 
     // 生成图片
+    @PreAuthorize("@sr.hasPermission('36.3')")
     @Operation(summary = "生成图片")
-    @Anonymous
     @PostMapping("/api/crt/generate/image")
     public Result generateImage(@Validated(CrtDramaProjectStoryboard.GenerateImage.class) @RequestBody CrtDramaProjectStoryboard crtDramaProjectStoryboard) {
         return Result.success().put("data", crtGenerateService.generateImage(crtDramaProjectStoryboard));

+ 1 - 0
src/main/java/com/backendsys/modules/crt/service/CrtGenerateService.java

@@ -6,6 +6,7 @@ import java.util.Map;
 
 public interface CrtGenerateService {
 
+    // 短剧创作-生成图片
     Map<String, Object> generateImage(CrtDramaProjectStoryboard crtDramaProjectStoryboard);
 
 }

+ 44 - 3
src/main/java/com/backendsys/modules/crt/service/impl/CrtGenerateServiceImpl.java

@@ -31,6 +31,9 @@ public class CrtGenerateServiceImpl implements CrtGenerateService {
     @Autowired
     private CrtDramaProjectStoryboardDao crtDramaProjectStoryboardDao;
 
+    /**
+     * 短剧创作-生成图片
+     */
     @Override
     public Map<String, Object> generateImage(CrtDramaProjectStoryboard crtDramaProjectStoryboard) {
 
@@ -44,11 +47,49 @@ public class CrtGenerateServiceImpl implements CrtGenerateService {
         String client_id = crtDramaProjectStoryboard.getClient_id();
 
         // -- [ComfyUI] 创建 WebSocket 监听连接 ---------------------------
-        comfyUISocketService.connect(client_id, "ws://43.128.1.201:8007/ws").subscribe();
+        comfyUISocketService.connectToSse(client_id, "ws://43.128.1.201:8007/ws").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\":\"保存图像\"}}}}";
-        String prompt = "{}";
+
+
+
+        // [Demo-基础生图]
+        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\": {" +
+                    "}," +
+                    "\"5\": {" +
+                    "}," +
+                    "\"6\": {" +
+                    "}," +
+                    "\"7\": {" +
+                    "}," +
+                    "\"8\": {" +
+                    "}," +
+                    "\"9\": {" +
+                    "}," +
+                "}";
+
+
+
+
         JSONObject prompt_object = JSONUtil.parseObj(prompt);
 
         System.out.println("prompt_object: " + prompt_object);

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

@@ -7,6 +7,9 @@ public interface ComfyUISocketService {
     // [ComfyUI] 创建 WebSocket 监听连接
     Mono<Void> connect(String clientId, String wsUrl);
 
+    // [ComfyUI] 创建 WebSocket 监听连接 (转发到 SSE)
+    Mono<Void> connectToSse(String clientId, String wsUrl);
+
     // [ComfyUI] 断开 WebSocket 监听连接
     Mono<Void> disconnect(String clientId);
 

+ 58 - 10
src/main/java/com/backendsys/modules/sdk/comfyui/service/impl/ComfyUISocketServiceImpl.java

@@ -1,6 +1,12 @@
 package com.backendsys.modules.sdk.comfyui.service.impl;
 
+import com.backendsys.modules.ai.chat.entity.ChatSseMessage;
+import com.backendsys.modules.common.config.security.utils.SecurityUtil;
 import com.backendsys.modules.sdk.comfyui.service.ComfyUISocketService;
+import com.backendsys.modules.sse.entity.SseResponse;
+import com.backendsys.modules.sse.entity.SseResponseEnum;
+import com.backendsys.modules.sse.utils.SseUtil;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import org.springframework.web.reactive.socket.WebSocketMessage;
@@ -19,6 +25,9 @@ import java.util.concurrent.ConcurrentHashMap;
 @Service
 public class ComfyUISocketServiceImpl implements ComfyUISocketService {
 
+    @Autowired
+    private SseUtil sseUtil;
+
     @Value("${comfyui.token}")
     private String COMFYUI_TOKEN;
 
@@ -41,32 +50,23 @@ public class ComfyUISocketServiceImpl implements ComfyUISocketService {
 
     /**
      * [ComfyUI] 创建 WebSocket 监听连接
-     * @param clientId 客户端ID(用于标识连接)
-     * @param wsUrl WebSocket 地址
-     * @return Mono<Void> 表示连接操作
      */
     @Override
     public Mono<Void> connect(String clientId, String wsUrl) {
-
         return Mono.defer(() -> {
             if (sessions.containsKey(clientId)) {
                 return Mono.error(new IllegalStateException("Connection already exists for client: " + clientId));
             }
-
             // 动态创建带有认证头的客户端
             WebSocketClient clientWithAuth = createWebSocketClientWithToken(COMFYUI_TOKEN);
             return clientWithAuth.execute(URI.create(wsUrl + "?clientId=" + clientId), session -> {
                 // 保存会话
                 sessions.put(clientId, session);
-
                 // 接收消息
                 Flux<String> incomingMessages = session.receive()
                     .map(WebSocketMessage::getPayloadAsText)
                     .doOnNext(message -> {
-
                         System.out.println("(doOnNext) Received from " + clientId + ": " + message);
-//                            // 转发到消息总线
-//                            messageSink.tryEmitNext(message);
                     })
                     .doOnError(e -> {
                         System.err.println("(doOnError) Error for " + clientId + ": " + e.getMessage());
@@ -75,12 +75,54 @@ public class ComfyUISocketServiceImpl implements ComfyUISocketService {
                         System.out.println("(doFinally) Connection closed for " + clientId + ": " + signal);
                         sessions.remove(clientId);
                     });
-
                 // 需要返回一个Mono<Void>来表示处理完成
                 return incomingMessages.then();
             });
         });
+    }
+
+    /**
+     * [ComfyUI] 创建 WebSocket 监听连接 (转发到 SSE)
+     */
+    @Override
+    public Mono<Void> connectToSse(String clientId, String wsUrl) {
+
+        Long user_id = SecurityUtil.getUserId();
+
+        return Mono.defer(() -> {
+            if (sessions.containsKey(clientId)) {
+                return Mono.error(new IllegalStateException("Connection already exists for client: " + clientId));
+            }
+            // 动态创建带有认证头的客户端
+            WebSocketClient clientWithAuth = createWebSocketClientWithToken(COMFYUI_TOKEN);
+            return clientWithAuth.execute(URI.create(wsUrl + "?clientId=" + clientId), session -> {
+                // 保存会话
+                sessions.put(clientId, session);
+                // 接收消息
+
+//                // [SSE] 发送消息
+//                ChatSseMessage chatSearchSseMessage = new ChatSseMessage("SEARCH", context, null, history_code);
 
+
+                Flux<String> incomingMessages = session.receive()
+                        .map(WebSocketMessage::getPayloadAsText)
+                        .doOnNext(message -> {
+                            System.out.println("(doOnNext) Received from " + clientId + ": " + message);
+                            sseUtil.send(user_id, new SseResponse(SseResponseEnum.COMFYUI, message).toJsonStr());
+                        })
+                        .doOnError(e -> {
+                            System.err.println("(doOnError) Error for " + clientId + ": " + e.getMessage());
+                            sseUtil.send(user_id, new SseResponse(SseResponseEnum.COMFYUI, e.getMessage()).toJsonStr());
+                        })
+                        .doFinally(signal -> {
+                            System.out.println("(doFinally) Connection closed for " + clientId + ": " + signal);
+                            sseUtil.send(user_id, new SseResponse(SseResponseEnum.COMFYUI, signal).toJsonStr());
+                            sessions.remove(clientId);
+                        });
+                // 需要返回一个Mono<Void>来表示处理完成
+                return incomingMessages.then();
+            });
+        });
     }
 
     /**
@@ -94,6 +136,12 @@ public class ComfyUISocketServiceImpl implements ComfyUISocketService {
             WebSocketSession session = sessions.get(clientId);
             if (session != null) {
                 System.out.println("disconnect success! clientId: " + clientId);
+
+                Long user_id = SecurityUtil.getUserId();
+                if (user_id != null) {
+                    sseUtil.send(user_id, new SseResponse(SseResponseEnum.COMFYUI, "disconnect success! clientId: " + clientId).toJsonStr());
+                }
+
                 session.close().subscribe();
                 sessions.remove(clientId);
             }

+ 1 - 0
src/main/java/com/backendsys/modules/sse/entity/SseResponseEnum.java

@@ -7,6 +7,7 @@ public enum SseResponseEnum {
     LOGOUT("logout", "退出登录"),
     NOTICE("notice", "通知"),
     UPLOAD("upload", "上传"),
+    COMFYUI("comfyui", "ComfyUI"),
     OLLAMA("ollama", "Ollama"),
     DEEPSEEK("deepseek", "Deepseek"),
     HUNYUAN("hunyuan", "Hunyuan");