saliacoel commited on
Commit
0498eff
·
verified ·
1 Parent(s): 0311603

Upload BAN_Expression_To_Default.py

Browse files
Files changed (1) hide show
  1. BAN_Expression_To_Default.py +164 -0
BAN_Expression_To_Default.py ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import re
4
+
5
+
6
+ DEFAULT_EXPRESSION_1 = "calm expression"
7
+ DEFAULT_EXPRESSION_2 = "neutral expression"
8
+ DEFAULT_EXPRESSION_3 = "slight smug smile"
9
+
10
+
11
+ # Matches:
12
+ # expression.1=...
13
+ # expression.2: ...
14
+ # expression_tag1=...
15
+ # expression1=...
16
+ _EXPR_RE = re.compile(
17
+ r"^expression(?:\.|_tag)?([1-5])\s*[:=]\s*(.*)$",
18
+ flags=re.IGNORECASE,
19
+ )
20
+
21
+ _SKIN_RE = re.compile(
22
+ r"^skin(?:\.|_tag)?([1-5])\s*[:=]",
23
+ flags=re.IGNORECASE,
24
+ )
25
+
26
+ _AESTHETIC_RE = re.compile(
27
+ r"^aesthetic(?:\.|_tag)?([1-5])\s*[:=]",
28
+ flags=re.IGNORECASE,
29
+ )
30
+
31
+ _EQUIP_RE = re.compile(
32
+ r"^(?:equip|equipment)\.",
33
+ flags=re.IGNORECASE,
34
+ )
35
+
36
+ _GPT_BAM_BLOCK_RE = re.compile(
37
+ r"GPT_BAM_START###(.*?)###GPT_BAM_END",
38
+ flags=re.IGNORECASE | re.DOTALL,
39
+ )
40
+
41
+
42
+ def _split_segments(payload: str) -> list[str]:
43
+ """Split a GPT_BAM payload into ### segments, removing empty/newline-only parts."""
44
+ payload = (payload or "").replace("\r", "\n")
45
+ return [seg.strip() for seg in payload.split("###") if seg.strip()]
46
+
47
+
48
+ def _is_expression_segment(seg: str) -> bool:
49
+ return _EXPR_RE.match(seg) is not None
50
+
51
+
52
+ def _find_insertion_index(segments: list[str]) -> int:
53
+ """
54
+ Where to insert expression.1/2/3 if no expression exists yet:
55
+
56
+ 1) first existing expression position
57
+ 2) after last skin tag
58
+ 3) after last aesthetic tag
59
+ 4) after last equip.* tag
60
+ 5) otherwise at end
61
+ """
62
+ first_expr_idx = None
63
+ last_skin_idx = None
64
+ last_aesthetic_idx = None
65
+ last_equip_idx = None
66
+
67
+ for i, seg in enumerate(segments):
68
+ if _is_expression_segment(seg) and first_expr_idx is None:
69
+ first_expr_idx = i
70
+ if _SKIN_RE.match(seg):
71
+ last_skin_idx = i
72
+ if _AESTHETIC_RE.match(seg):
73
+ last_aesthetic_idx = i
74
+ if _EQUIP_RE.match(seg):
75
+ last_equip_idx = i
76
+
77
+ if first_expr_idx is not None:
78
+ return first_expr_idx
79
+ if last_skin_idx is not None:
80
+ return last_skin_idx + 1
81
+ if last_aesthetic_idx is not None:
82
+ return last_aesthetic_idx + 1
83
+ if last_equip_idx is not None:
84
+ return last_equip_idx + 1
85
+ return len(segments)
86
+
87
+
88
+ def _rewrite_payload(payload: str) -> str:
89
+ segments = _split_segments(payload)
90
+ insertion_index = _find_insertion_index(segments)
91
+
92
+ new_expression_segments = [
93
+ f"expression.1={DEFAULT_EXPRESSION_1}",
94
+ f"expression.2={DEFAULT_EXPRESSION_2}",
95
+ f"expression.3={DEFAULT_EXPRESSION_3}",
96
+ ]
97
+
98
+ out_segments: list[str] = []
99
+ inserted = False
100
+
101
+ for i, seg in enumerate(segments):
102
+ if not inserted and i == insertion_index:
103
+ out_segments.extend(new_expression_segments)
104
+ inserted = True
105
+
106
+ # Remove ALL existing expression.1..5 / expression_tag1..5
107
+ if _is_expression_segment(seg):
108
+ continue
109
+
110
+ out_segments.append(seg)
111
+
112
+ if not inserted:
113
+ out_segments.extend(new_expression_segments)
114
+
115
+ return "###".join(out_segments)
116
+
117
+
118
+ def _rewrite_gpt_bam_text(text: str) -> str:
119
+ """
120
+ If a GPT_BAM block is found, only rewrite that block and preserve any text outside it.
121
+ If no GPT_BAM block is found, treat the whole input as a raw payload and rewrite it.
122
+ """
123
+ text = text or ""
124
+ match = _GPT_BAM_BLOCK_RE.search(text)
125
+
126
+ if not match:
127
+ # Fallback: treat entire text as payload and wrap it back into GPT_BAM
128
+ rewritten_payload = _rewrite_payload(text)
129
+ return f"GPT_BAM_START###{rewritten_payload}###GPT_BAM_END"
130
+
131
+ original_payload = match.group(1)
132
+ rewritten_payload = _rewrite_payload(original_payload)
133
+ new_block = f"GPT_BAM_START###{rewritten_payload}###GPT_BAM_END"
134
+
135
+ return text[:match.start()] + new_block + text[match.end():]
136
+
137
+
138
+ class BAM_expression_default:
139
+ @classmethod
140
+ def INPUT_TYPES(cls):
141
+ return {
142
+ "required": {
143
+ "BAM-format_In": ("STRING", {"multiline": True, "default": ""}),
144
+ }
145
+ }
146
+
147
+ RETURN_TYPES = ("STRING",)
148
+ RETURN_NAMES = ("BAM-format_OUT",)
149
+ FUNCTION = "apply"
150
+ CATEGORY = "BAM"
151
+
152
+ def apply(self, **kwargs):
153
+ bam_in = kwargs.get("BAM-format_In", "")
154
+ bam_out = _rewrite_gpt_bam_text(bam_in)
155
+ return (bam_out,)
156
+
157
+
158
+ NODE_CLASS_MAPPINGS = {
159
+ "BAM_expression_default": BAM_expression_default,
160
+ }
161
+
162
+ NODE_DISPLAY_NAME_MAPPINGS = {
163
+ "BAM_expression_default": "BAM_expression_default",
164
+ }