File size: 3,829 Bytes
7aaa385
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import os
import re
import json
import hashlib
import urllib.request
import urllib.error

import folder_paths
import comfy.sd
import comfy.lora
import comfy.utils
from safetensors import safe_open

try:
    from .promp_logic_v32_story import MODEL_PRESETS, MODEL_PRESET_LABELS, resolve_model
except Exception:
    MODEL_PRESETS = {"๐Ÿ”ž DeepSeek V3.2": "deepseek/deepseek-v3.2"}
    MODEL_PRESET_LABELS = list(MODEL_PRESETS.keys())
    def resolve_model(p, c): return c if p == "custom" else "deepseek/deepseek-v3.2"

class DolphinCinematicDirector:
    @classmethod
    def INPUT_TYPES(s):
        loras = ["None"] + folder_paths.get_filename_list("loras")
        return {
            "required": {
                "model_base": ("MODEL",), "model_high": ("MODEL",), "model_low": ("MODEL",),
                "mode": (["๐Ÿค– Auto LLM (Story Splitter)", "โœ๏ธ Manual"], {"default": "๐Ÿค– Auto LLM (Story Splitter)"}),
                "master_story": ("STRING", {"multiline": True}),
                "tagger_context": ("STRING", {"multiline": True}),
                "openrouter_api_key": ("STRING", {"default": ""}),
            },
            "optional": {
                "external_triggers": ("STRING", {"forceInput": True}),
            }
        }

    RETURN_TYPES = ("MODEL", "MODEL", "MODEL", "STRING") * 4 + ("STRING",)
    RETURN_NAMES = tuple([f"c{i}_{n}" for i in range(1, 5) for n in ["base", "high", "low", "prompt"]] + ["debug_info"])
    FUNCTION = "direct"
    CATEGORY = "Dolphin"

    def _build_final(self, action, tags, master_scene, name, trigger_str):
        # 1. ํŠธ๋ฆฌ๊ฑฐ ์›Œ๋“œ(trigger_str)์™€ ์บ๋ฆญํ„ฐ ์ด๋ฆ„(name)๋งŒ ์ƒ๋‹จ์— ๋ฐฐ์น˜
        header = []
        if name: header.append(name)
        if trigger_str: header.append(trigger_str)
        
        # 2. ๋™์ž‘(action)๊ณผ ๋ฐฐ๊ฒฝ(master_scene)๋งŒ ํ•˜๋‹จ์— ๋ฐฐ์น˜
        # ๐Ÿš€ ํ•ต์‹ฌ: ์—ฌ๊ธฐ์„œ 'tags' ๋ณ€์ˆ˜๋ฅผ ์•„์˜ˆ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ์œผ๋กœ์จ ๋ฌ˜์‚ฌ ํฌํ•จ์„ ์›์ฒœ ์ฐจ๋‹จ
        body = []
        if master_scene and master_scene.strip():
            body.append(master_scene.strip())
        if action and action.strip():
            body.append(action.strip())
        
        # ๊ฒฐ๊ณผ๊ฐ’ ๊ฒฐํ•ฉ
        header_str = ", ".join(header)
        body_str = " ".join(body)
        
        if header_str and body_str:
            return f"{header_str}\n{body_str}"
        return header_str or body_str

    def _llm_split(self, story, name, tags, key, model):
        # ๐Ÿš€ ์ˆ˜์ •: LLM์—๊ฒŒ๋Š” ๋ฌ˜์‚ฌ๋ฅผ ๋ณด๋‚ด๋˜, ์ถœ๋ ฅ JSON์—์„œ๋Š” ๋™์ž‘๋งŒ ๋ฝ‘๋„๋ก ๊ฐ•์ œ
       sys_p = (
    "You are an action-only generator. "
    "DO NOT output any visual descriptions, clothing, lighting, or setting details. "
    "Your output must ONLY be the physical movement of the character. "
    "If you include any adjective-heavy descriptions, you will be penalized. "
    "Strictly output only the kinetic action in the JSON fields."
)

    def direct(self, model_base, model_high, model_low, mode, master_story, tagger_context, openrouter_api_key, external_triggers="", **kw):
        # ๐Ÿš€ ๊ฐ•๋ ฅํ•œ ๋ฐฉ์–ด: ์–ด๋–ค ๋ฌ˜์‚ฌ๊ฐ€ ๋“ค์–ด์™€๋„ ํƒœ๊ทธ๋Š” ๊ฐ•์ œ๋กœ ๋นˆ ๊ฐ’์œผ๋กœ ๋Œ€์ฒด
        tagger_context = "" 
        
        # ์ดํ›„ ๋กœ์ง...
        # ๋ชจ๋“œ๋ณ„ ์ฒ˜๋ฆฌ
        clips = [master_story] * 4 # ๋‹จ์ˆœํ™” ๋กœ์ง
        master_scene = "action"
        final_name = "character"
        
        outs = []
        for c in range(1, 5):
            # ๐Ÿš€ ๊ฐ•์ œ๋กœ tags(tagger_context)๋ฅผ ๋นˆ ๋ฌธ์ž์—ด("")๋กœ ์ „๋‹ฌํ•˜์—ฌ ๋ฌด๋ ฅํ™”
            prompt = self._build_final(clips[c-1], "", master_scene, final_name, external_triggers)
            outs.extend([model_base, model_high, model_low, prompt])

        return tuple(outs) + ("Success",)

NODE_CLASS_MAPPINGS = {"DolphinCinematicDirector": DolphinCinematicDirector}