feat: prompt entered once in SelvaFeatureExtractor, reused by SelvaSampler
SelvaFeatureExtractor now stores the prompt in SELVA_FEATURES (both in the returned dict and the .npz cache). SelvaSampler's prompt is now optional — when left empty it falls back to the prompt stored in features. A non-empty override can still be passed when CLIP text should differ from the sync text. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -150,6 +150,7 @@ class SelvaFeatureExtractor:
|
|||||||
clip_features=clip_features.cpu().float().numpy(),
|
clip_features=clip_features.cpu().float().numpy(),
|
||||||
sync_features=sync_features.cpu().float().numpy(),
|
sync_features=sync_features.cpu().float().numpy(),
|
||||||
duration=float(duration),
|
duration=float(duration),
|
||||||
|
prompt=np.array(prompt),
|
||||||
)
|
)
|
||||||
print(f"[SelVA] Features cached: {cached_path}", flush=True)
|
print(f"[SelVA] Features cached: {cached_path}", flush=True)
|
||||||
|
|
||||||
@@ -157,13 +158,17 @@ class SelvaFeatureExtractor:
|
|||||||
"clip_features": clip_features.cpu(),
|
"clip_features": clip_features.cpu(),
|
||||||
"sync_features": sync_features.cpu(),
|
"sync_features": sync_features.cpu(),
|
||||||
"duration": float(duration),
|
"duration": float(duration),
|
||||||
|
"prompt": prompt,
|
||||||
}, float(fps))
|
}, float(fps))
|
||||||
|
|
||||||
|
|
||||||
def _load_cached(path):
|
def _load_cached(path):
|
||||||
data = np.load(path, allow_pickle=False)
|
data = np.load(path, allow_pickle=False)
|
||||||
return {
|
features = {
|
||||||
"clip_features": torch.from_numpy(data["clip_features"]),
|
"clip_features": torch.from_numpy(data["clip_features"]),
|
||||||
"sync_features": torch.from_numpy(data["sync_features"]),
|
"sync_features": torch.from_numpy(data["sync_features"]),
|
||||||
"duration": float(data["duration"]),
|
"duration": float(data["duration"]),
|
||||||
}
|
}
|
||||||
|
if "prompt" in data:
|
||||||
|
features["prompt"] = str(data["prompt"])
|
||||||
|
return features
|
||||||
|
|||||||
+15
-5
@@ -11,10 +11,6 @@ class SelvaSampler:
|
|||||||
"required": {
|
"required": {
|
||||||
"model": ("SELVA_MODEL",),
|
"model": ("SELVA_MODEL",),
|
||||||
"features": ("SELVA_FEATURES",),
|
"features": ("SELVA_FEATURES",),
|
||||||
"prompt": ("STRING", {
|
|
||||||
"default": "", "multiline": True,
|
|
||||||
"tooltip": "Should match the prompt used in SelvaFeatureExtractor.",
|
|
||||||
}),
|
|
||||||
"negative_prompt": ("STRING", {
|
"negative_prompt": ("STRING", {
|
||||||
"default": "", "multiline": True,
|
"default": "", "multiline": True,
|
||||||
"tooltip": "Sounds to steer away from, e.g. 'wind noise, background music'.",
|
"tooltip": "Sounds to steer away from, e.g. 'wind noise, background music'.",
|
||||||
@@ -29,6 +25,12 @@ class SelvaSampler:
|
|||||||
"tooltip": "CFG scale (SelVA default is 4.5)."}),
|
"tooltip": "CFG scale (SelVA default is 4.5)."}),
|
||||||
"seed": ("INT", {"default": 0, "min": 0, "max": 0xFFFFFFFF}),
|
"seed": ("INT", {"default": 0, "min": 0, "max": 0xFFFFFFFF}),
|
||||||
},
|
},
|
||||||
|
"optional": {
|
||||||
|
"prompt": ("STRING", {
|
||||||
|
"default": "", "multiline": True,
|
||||||
|
"tooltip": "CLIP text for audio generation. Leave empty to reuse the prompt from SelvaFeatureExtractor.",
|
||||||
|
}),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_TYPES = ("AUDIO",)
|
RETURN_TYPES = ("AUDIO",)
|
||||||
@@ -36,7 +38,7 @@ class SelvaSampler:
|
|||||||
FUNCTION = "generate"
|
FUNCTION = "generate"
|
||||||
CATEGORY = PRISMAUDIO_CATEGORY
|
CATEGORY = PRISMAUDIO_CATEGORY
|
||||||
|
|
||||||
def generate(self, model, features, prompt, negative_prompt, duration, steps, cfg_strength, seed):
|
def generate(self, model, features, negative_prompt, duration, steps, cfg_strength, seed, prompt=None):
|
||||||
from selva_core.model.flow_matching import FlowMatching
|
from selva_core.model.flow_matching import FlowMatching
|
||||||
from selva_core.model.sequence_config import SequenceConfig
|
from selva_core.model.sequence_config import SequenceConfig
|
||||||
|
|
||||||
@@ -47,6 +49,14 @@ class SelvaSampler:
|
|||||||
feature_utils = model["feature_utils"]
|
feature_utils = model["feature_utils"]
|
||||||
mode = model["mode"]
|
mode = model["mode"]
|
||||||
|
|
||||||
|
# Resolve prompt: use override if given, otherwise fall back to features prompt
|
||||||
|
if not prompt or not prompt.strip():
|
||||||
|
prompt = features.get("prompt", "")
|
||||||
|
if prompt:
|
||||||
|
print(f"[SelVA] Using prompt from features: '{prompt[:60]}'", flush=True)
|
||||||
|
else:
|
||||||
|
print("[SelVA] Warning: no prompt in features or sampler — CLIP text conditioning will be empty.", flush=True)
|
||||||
|
|
||||||
# Resolve duration
|
# Resolve duration
|
||||||
if duration <= 0:
|
if duration <= 0:
|
||||||
if "duration" not in features:
|
if "duration" not in features:
|
||||||
|
|||||||
Reference in New Issue
Block a user