Add DiffusionPipeline support and auto mode retry logic

- Add DiffusionPipeline to PIPELINE_CLASS_MAP for generic model loading
- Add fallback to DiffusionPipeline for unknown pipeline classes
- Add return_all parameter to select_best_model() for getting all candidates
- Store alternative models in auto mode for retry support
- Implement retry logic when model loading fails in auto mode
- Retry up to 3 times with alternative models before failing
- Add debug output for model loading troubleshooting
- Improve error messages with troubleshooting hints
parent 4ba0b99f
Pipeline #223 canceled with stages
...@@ -154,6 +154,8 @@ PIPELINE_CLASS_MAP = { ...@@ -154,6 +154,8 @@ PIPELINE_CLASS_MAP = {
"StepVideoPipeline": {"type": "t2v", "default_vram": "~90-140 GB"}, "StepVideoPipeline": {"type": "t2v", "default_vram": "~90-140 GB"},
"CogVideoXPipeline": {"type": "t2v", "default_vram": "~20-30 GB"}, "CogVideoXPipeline": {"type": "t2v", "default_vram": "~20-30 GB"},
"HotshotXLPipeline": {"type": "video", "default_vram": "~8-12 GB"}, "HotshotXLPipeline": {"type": "video", "default_vram": "~8-12 GB"},
# Generic pipeline - auto-detects model type from loaded model
"DiffusionPipeline": {"type": "auto", "default_vram": "~10-30 GB"},
} }
...@@ -189,28 +191,61 @@ def save_models_config(models): ...@@ -189,28 +191,61 @@ def save_models_config(models):
print(f"❌ Could not save models config: {e}") print(f"❌ Could not save models config: {e}")
def validate_hf_model(model_id, hf_token=None): def validate_hf_model(model_id, hf_token=None, debug=False):
"""Validate if a HuggingFace model exists and get its info""" """Validate if a HuggingFace model exists and get its info"""
headers = {} headers = {}
if hf_token: if hf_token:
headers["Authorization"] = f"Bearer {hf_token}" headers["Authorization"] = f"Bearer {hf_token}"
if debug:
print(f"\n🔍 [DEBUG] Validating model: {model_id}")
print(f" [DEBUG] HF Token: {'***' + hf_token[-4:] if hf_token else 'Not set'}")
try: try:
url = f"https://huggingface.co/api/models/{model_id}" url = f"https://huggingface.co/api/models/{model_id}"
if debug:
print(f" [DEBUG] API URL: {url}")
req = urllib.request.Request(url, headers=headers) req = urllib.request.Request(url, headers=headers)
if debug:
print(f" [DEBUG] Sending request...")
with urllib.request.urlopen(req, timeout=10) as response: with urllib.request.urlopen(req, timeout=10) as response:
if debug:
print(f" [DEBUG] Response status: {response.status}")
data = json.loads(response.read().decode()) data = json.loads(response.read().decode())
if debug:
print(f" [DEBUG] Model found! Tags: {data.get('tags', [])[:5]}")
return data return data
except urllib.error.HTTPError as e: except urllib.error.HTTPError as e:
if debug:
print(f" [DEBUG] HTTP Error: {e.code} - {e.reason}")
print(f" [DEBUG] Response headers: {dict(e.headers)}")
try:
error_body = e.read().decode()
print(f" [DEBUG] Response body: {error_body[:500]}")
except:
pass
if e.code == 401: if e.code == 401:
print(f"❌ Model {model_id} requires authentication. Set HF_TOKEN environment variable.") print(f"❌ Model {model_id} requires authentication. Set HF_TOKEN environment variable.")
elif e.code == 404: elif e.code == 404:
print(f"❌ Model {model_id} not found on HuggingFace.") print(f"❌ Model {model_id} not found on HuggingFace.")
if debug:
print(f" [DEBUG] The model ID may be incorrect or the model may have been removed.")
print(f" [DEBUG] Check the URL: https://huggingface.co/{model_id}")
else: else:
print(f"❌ HTTP error {e.code} for {model_id}") print(f"❌ HTTP error {e.code} for {model_id}")
return None return None
except urllib.error.URLError as e:
if debug:
print(f" [DEBUG] URL Error: {e.reason}")
print(f"❌ Network error validating {model_id}: {e.reason}")
return None
except Exception as e: except Exception as e:
if debug:
print(f" [DEBUG] Unexpected error: {type(e).__name__}: {e}")
print(f"❌ Error validating {model_id}: {e}") print(f"❌ Error validating {model_id}: {e}")
return None return None
...@@ -258,6 +293,9 @@ def detect_pipeline_class(model_info): ...@@ -258,6 +293,9 @@ def detect_pipeline_class(model_info):
return "TextToVideoZeroPipeline" return "TextToVideoZeroPipeline"
if "modelscope" in model_id or "text-to-video-ms" in model_id: if "modelscope" in model_id or "text-to-video-ms" in model_id:
return "TextToVideoSDPipeline" return "TextToVideoSDPipeline"
# Check for qwen or other diffusers models that use generic DiffusionPipeline
if "qwen" in model_id or "diffusers" in model_id:
return "DiffusionPipeline"
# Check tags # Check tags
if "video" in tags: if "video" in tags:
...@@ -269,8 +307,9 @@ def detect_pipeline_class(model_info): ...@@ -269,8 +307,9 @@ def detect_pipeline_class(model_info):
# Check library # Check library
if library_name == "diffusers": if library_name == "diffusers":
# Default to video pipeline # Use generic DiffusionPipeline for diffusers models
return "WanPipeline" # This allows loading any diffusers-compatible model
return "DiffusionPipeline"
return None return None
...@@ -309,7 +348,7 @@ def parse_hf_url_or_id(input_str): ...@@ -309,7 +348,7 @@ def parse_hf_url_or_id(input_str):
return input_str return input_str
def add_model_from_hf(model_id_or_url, name=None, hf_token=None): def add_model_from_hf(model_id_or_url, name=None, hf_token=None, debug=False):
"""Add a model from HuggingFace to the config """Add a model from HuggingFace to the config
Accepts both model IDs (org/model-name) and HuggingFace URLs Accepts both model IDs (org/model-name) and HuggingFace URLs
...@@ -321,7 +360,7 @@ def add_model_from_hf(model_id_or_url, name=None, hf_token=None): ...@@ -321,7 +360,7 @@ def add_model_from_hf(model_id_or_url, name=None, hf_token=None):
if model_id != model_id_or_url: if model_id != model_id_or_url:
print(f" (parsed from URL: {model_id_or_url})") print(f" (parsed from URL: {model_id_or_url})")
model_info = validate_hf_model(model_id, hf_token) model_info = validate_hf_model(model_id, hf_token, debug=debug)
if not model_info: if not model_info:
return None return None
...@@ -1154,6 +1193,7 @@ def get_pipeline_class(class_name): ...@@ -1154,6 +1193,7 @@ def get_pipeline_class(class_name):
"StableVideoDiffusionPipeline": ["StableVideoDiffusionImg2VidPipeline"], "StableVideoDiffusionPipeline": ["StableVideoDiffusionImg2VidPipeline"],
"CogVideoXPipeline": ["CogVideoXImageToVideoPipeline", "CogVideoXVideoToVideoPipeline"], "CogVideoXPipeline": ["CogVideoXImageToVideoPipeline", "CogVideoXVideoToVideoPipeline"],
"MochiPipeline": ["Mochi1Pipeline", "MochiVideoPipeline"], "MochiPipeline": ["Mochi1Pipeline", "MochiVideoPipeline"],
"DiffusionPipeline": [], # No alternatives needed - it's the generic class
} }
if class_name in alternatives: if class_name in alternatives:
...@@ -1165,6 +1205,15 @@ def get_pipeline_class(class_name): ...@@ -1165,6 +1205,15 @@ def get_pipeline_class(class_name):
except AttributeError: except AttributeError:
continue continue
# Fallback to DiffusionPipeline for unknown classes
# This allows loading any diffusers-compatible model
if class_name not in ["Unknown", None]:
try:
print(f" ℹ️ Trying generic DiffusionPipeline for: {class_name}")
return diffusers.DiffusionPipeline
except AttributeError:
pass
return None return None
...@@ -1857,7 +1906,7 @@ def detect_generation_type(prompt, prompt_image=None, prompt_animation=None, arg ...@@ -1857,7 +1906,7 @@ def detect_generation_type(prompt, prompt_image=None, prompt_animation=None, arg
return result return result
def select_best_model(gen_type, models, vram_gb=24, prefer_quality=True): def select_best_model(gen_type, models, vram_gb=24, prefer_quality=True, return_all=False):
"""Select the best model based on generation type and constraints """Select the best model based on generation type and constraints
Args: Args:
...@@ -1865,8 +1914,9 @@ def select_best_model(gen_type, models, vram_gb=24, prefer_quality=True): ...@@ -1865,8 +1914,9 @@ def select_best_model(gen_type, models, vram_gb=24, prefer_quality=True):
models: Available models dict models: Available models dict
vram_gb: Available VRAM in GB vram_gb: Available VRAM in GB
prefer_quality: Prefer quality over speed prefer_quality: Prefer quality over speed
return_all: If True, return all candidates sorted by score
Returns: (model_name, model_info, reason) Returns: (model_name, model_info, reason) or [(model_name, model_info, reason), ...] if return_all=True
""" """
candidates = [] candidates = []
is_nsfw = gen_type.get("is_nsfw", False) is_nsfw = gen_type.get("is_nsfw", False)
...@@ -1932,12 +1982,21 @@ def select_best_model(gen_type, models, vram_gb=24, prefer_quality=True): ...@@ -1932,12 +1982,21 @@ def select_best_model(gen_type, models, vram_gb=24, prefer_quality=True):
# Fallback: return first available model # Fallback: return first available model
for name, info in models.items(): for name, info in models.items():
if not info.get("is_lora"): if not info.get("is_lora"):
if return_all:
return [(name, info, "Fallback (no ideal match)")]
return name, info, "Fallback (no ideal match)" return name, info, "Fallback (no ideal match)"
if return_all:
return []
return None, None, "No models available" return None, None, "No models available"
# Sort by score (highest first) # Sort by score (highest first)
candidates.sort(key=lambda x: x[2], reverse=True) candidates.sort(key=lambda x: x[2], reverse=True)
if return_all:
# Return all candidates with their reasons
return [(name, info, f"Score: {score} - {', '.join(reasons)}")
for name, info, score, reasons in candidates]
best_name, best_info, best_score, best_reasons = candidates[0] best_name, best_info, best_score, best_reasons = candidates[0]
return best_name, best_info, f"Score: {best_score} - {', '.join(best_reasons)}" return best_name, best_info, f"Score: {best_score} - {', '.join(best_reasons)}"
...@@ -2169,6 +2228,10 @@ def run_auto_mode(args, models): ...@@ -2169,6 +2228,10 @@ def run_auto_mode(args, models):
'image': getattr(args, 'image', None) is not None, 'image': getattr(args, 'image', None) is not None,
} }
# Store alternative models for retry in auto mode
args._auto_alternative_models = []
args._auto_alternative_image_models = []
# Detect generation type # Detect generation type
print("\n📊 Analyzing prompts...") print("\n📊 Analyzing prompts...")
gen_type = detect_generation_type( gen_type = detect_generation_type(
...@@ -2199,17 +2262,25 @@ def run_auto_mode(args, models): ...@@ -2199,17 +2262,25 @@ def run_auto_mode(args, models):
prefer_quality = not getattr(args, 'prefer_speed', False) prefer_quality = not getattr(args, 'prefer_speed', False)
if not user_provided['model']: if not user_provided['model']:
model_name, model_info, reason = select_best_model(gen_type, models, vram_gb, prefer_quality) # Get all candidate models for retry support
all_candidates = select_best_model(gen_type, models, vram_gb, prefer_quality, return_all=True)
if not model_name: if not all_candidates:
print(" Could not find a suitable model!") print(" Could not find a suitable model!")
print(" Try running --update-models to update the model database") print(" Try running --update-models to update the model database")
return None return None
# Use the best candidate
model_name, model_info, reason = all_candidates[0]
print(f" ✅ Selected: {model_name}") print(f" ✅ Selected: {model_name}")
print(f" {model_info.get('id', 'Unknown')}") print(f" {model_info.get('id', 'Unknown')}")
print(f" {reason}") print(f" {reason}")
args.model = model_name args.model = model_name
# Store alternatives for retry (excluding the selected one)
args._auto_alternative_models = all_candidates[1:]
if args._auto_alternative_models:
print(f" 📋 {len(args._auto_alternative_models)} alternative models available for retry")
else: else:
# User specified a model - use it # User specified a model - use it
model_name = args.model model_name = args.model
...@@ -2225,13 +2296,22 @@ def run_auto_mode(args, models): ...@@ -2225,13 +2296,22 @@ def run_auto_mode(args, models):
print(f"\n🎯 Selecting image model for I2V...") print(f"\n🎯 Selecting image model for I2V...")
img_gen_type = gen_type.copy() img_gen_type = gen_type.copy()
img_gen_type['type'] = 't2i' img_gen_type['type'] = 't2i'
image_model_name, image_model_info, img_reason = select_best_model(
img_gen_type, models, vram_gb, prefer_quality=True # Get all image model candidates
all_img_candidates = select_best_model(
img_gen_type, models, vram_gb, prefer_quality=True, return_all=True
) )
if image_model_name:
if all_img_candidates:
image_model_name, image_model_info, img_reason = all_img_candidates[0]
print(f" ✅ Selected: {image_model_name}") print(f" ✅ Selected: {image_model_name}")
print(f" {image_model_info.get('id', 'Unknown')}") print(f" {image_model_info.get('id', 'Unknown')}")
args.image_model = image_model_name args.image_model = image_model_name
# Store alternatives for retry
args._auto_alternative_image_models = all_img_candidates[1:]
if args._auto_alternative_image_models:
print(f" 📋 {len(args._auto_alternative_image_models)} alternative image models available")
else: else:
print(f"\n🎯 Using user-specified image model: {args.image_model}") print(f"\n🎯 Using user-specified image model: {args.image_model}")
...@@ -2744,7 +2824,7 @@ def main(args): ...@@ -2744,7 +2824,7 @@ def main(args):
# Handle model addition # Handle model addition
if args.add_model: if args.add_model:
hf_token = os.environ.get("HF_TOKEN") hf_token = os.environ.get("HF_TOKEN")
result = add_model_from_hf(args.add_model, name=args.name, hf_token=hf_token) result = add_model_from_hf(args.add_model, name=args.name, hf_token=hf_token, debug=getattr(args, 'debug', False))
if result: if result:
name, model_entry = result name, model_entry = result
MODELS[name] = model_entry MODELS[name] = model_entry
...@@ -2756,7 +2836,7 @@ def main(args): ...@@ -2756,7 +2836,7 @@ def main(args):
# Handle model validation # Handle model validation
if args.validate_model: if args.validate_model:
hf_token = os.environ.get("HF_TOKEN") hf_token = os.environ.get("HF_TOKEN")
model_info = validate_hf_model(args.validate_model, hf_token=hf_token) model_info = validate_hf_model(args.validate_model, hf_token=hf_token, debug=getattr(args, 'debug', False))
if model_info: if model_info:
print(f"✅ Model {args.validate_model} is valid") print(f"✅ Model {args.validate_model} is valid")
print(f" Tags: {', '.join(model_info.get('tags', [])[:10])}") print(f" Tags: {', '.join(model_info.get('tags', [])[:10])}")
...@@ -2785,7 +2865,7 @@ def main(args): ...@@ -2785,7 +2865,7 @@ def main(args):
if not getattr(args, 'auto', False) and not args.model_list and not args.tts_list and not args.search_models and not args.add_model and not args.validate_model and not args.prompt: if not getattr(args, 'auto', False) and not args.model_list and not args.tts_list and not args.search_models and not args.add_model and not args.validate_model and not args.prompt:
parser.error("the following arguments are required: --prompt") parser.error("the following arguments are required: --prompt")
# Handle auto mode # Handle auto mode with retry support
if getattr(args, 'auto', False): if getattr(args, 'auto', False):
if not args.prompt: if not args.prompt:
parser.error("--auto requires --prompt to analyze") parser.error("--auto requires --prompt to analyze")
...@@ -2793,6 +2873,11 @@ def main(args): ...@@ -2793,6 +2873,11 @@ def main(args):
if args is None: if args is None:
sys.exit(1) sys.exit(1)
# Store original args for retry
args._auto_mode = True
args._retry_count = 0
args._max_retries = 3 # Maximum number of model retries
if args.distribute and args.interface: if args.distribute and args.interface:
os.environ["NCCL_SOCKET_IFNAME"] = args.interface os.environ["NCCL_SOCKET_IFNAME"] = args.interface
os.environ["GLOO_SOCKET_IFNAME"] = args.interface os.environ["GLOO_SOCKET_IFNAME"] = args.interface
...@@ -2932,15 +3017,71 @@ def main(args): ...@@ -2932,15 +3017,71 @@ def main(args):
timing.start() timing.start()
timing.begin_step("model_loading") timing.begin_step("model_loading")
debug = getattr(args, 'debug', False)
if debug:
print(f"\n🔍 [DEBUG] Model Loading Details:")
print(f" [DEBUG] Model ID to load: {model_id_to_load}")
print(f" [DEBUG] Pipeline class: {m_info['class']}")
print(f" [DEBUG] Is LoRA: {is_lora}")
if is_lora:
print(f" [DEBUG] LoRA ID: {lora_id}")
print(f" [DEBUG] Pipeline kwargs:")
for k, v in pipe_kwargs.items():
if k == "max_memory":
print(f" {k}: {v}")
elif k == "device_map":
print(f" {k}: {v}")
else:
print(f" {k}: {v}")
print(f" [DEBUG] HF Token: {'***' + os.environ.get('HF_TOKEN', '')[-4:] if os.environ.get('HF_TOKEN') else 'Not set'}")
print(f" [DEBUG] Cache dir: {os.environ.get('HF_HOME', 'default')}")
print()
try: try:
pipe = PipelineClass.from_pretrained(model_id_to_load, **pipe_kwargs) pipe = PipelineClass.from_pretrained(model_id_to_load, **pipe_kwargs)
except Exception as e: except Exception as e:
error_str = str(e) error_str = str(e)
if debug:
print(f"\n🔍 [DEBUG] Error Details:")
print(f" [DEBUG] Exception type: {type(e).__name__}")
print(f" [DEBUG] Error message: {error_str}")
if hasattr(e, 'response'):
print(f" [DEBUG] Response: {e.response}")
print()
# Check if we should retry with an alternative model (auto mode)
if getattr(args, '_auto_mode', False) and getattr(args, '_retry_count', 0) < getattr(args, '_max_retries', 3):
alternative_models = getattr(args, '_auto_alternative_models', [])
if alternative_models:
args._retry_count += 1
next_model_name, next_model_info, next_reason = alternative_models.pop(0)
args._auto_alternative_models = alternative_models # Update the list
print(f"\n⚠️ Model loading failed: {model_id_to_load}")
print(f" Error: {error_str[:100]}...")
print(f"\n🔄 Retrying with alternative model ({args._retry_count}/{args._max_retries})...")
print(f" New model: {next_model_name}")
print(f" {next_reason}")
# Update args with new model and recurse
args.model = next_model_name
# Clean up any partial model loading
if torch.cuda.is_available():
torch.cuda.empty_cache()
# Retry main() with the new model
return main(args)
# Check for common errors and provide helpful messages # Check for common errors and provide helpful messages
if "404" in error_str or "Entry Not Found" in error_str: if "404" in error_str or "Entry Not Found" in error_str:
print(f"❌ Model not found on HuggingFace: {model_id_to_load}") print(f"❌ Model not found on HuggingFace: {model_id_to_load}")
print(f" This model may have been removed or the ID is incorrect.") print(f" This model may have been removed or the ID is incorrect.")
if debug:
print(f"\n [DEBUG] Troubleshooting:")
print(f" - Check if the model exists: https://huggingface.co/{model_id_to_load}")
print(f" - Verify the model ID spelling")
print(f" - The model may have been renamed or moved")
print(f"\n 💡 Try searching for an alternative:") print(f"\n 💡 Try searching for an alternative:")
print(f" videogen --search-models ltxvideo") print(f" videogen --search-models ltxvideo")
print(f"\n 💡 Or use the official LTX Video model:") print(f"\n 💡 Or use the official LTX Video model:")
...@@ -2950,13 +3091,30 @@ def main(args): ...@@ -2950,13 +3091,30 @@ def main(args):
print(f" Set your HuggingFace token:") print(f" Set your HuggingFace token:")
print(f" export HF_TOKEN=your_token_here") print(f" export HF_TOKEN=your_token_here")
print(f" huggingface-cli login") print(f" huggingface-cli login")
if debug:
print(f"\n [DEBUG] To get a token:")
print(f" 1. Go to https://huggingface.co/settings/tokens")
print(f" 2. Create a new token with 'read' permissions")
print(f" 3. Export it: export HF_TOKEN=hf_xxx")
elif "gated" in error_str.lower(): elif "gated" in error_str.lower():
print(f"❌ This is a gated model: {model_id_to_load}") print(f"❌ This is a gated model: {model_id_to_load}")
print(f" You need to accept the license on HuggingFace:") print(f" You need to accept the license on HuggingFace:")
print(f" https://huggingface.co/{model_id_to_load}") print(f" https://huggingface.co/{model_id_to_load}")
print(f" Then set HF_TOKEN and run again.") print(f" Then set HF_TOKEN and run again.")
elif "connection" in error_str.lower() or "timeout" in error_str.lower():
print(f"❌ Network error loading model: {model_id_to_load}")
print(f" Check your internet connection and try again.")
if debug:
print(f"\n [DEBUG] Network troubleshooting:")
print(f" - Check if you can access: https://huggingface.co/{model_id_to_load}")
print(f" - Try with a VPN if HuggingFace is blocked")
print(f" - Check if HF_ENDPOINT is set (for China mirror): {os.environ.get('HF_ENDPOINT', 'not set')}")
else: else:
print(f"Model loading failed: {e}") print(f"Model loading failed: {e}")
if debug:
import traceback
print(f"\n [DEBUG] Full traceback:")
traceback.print_exc()
sys.exit(1) sys.exit(1)
...@@ -3600,5 +3758,9 @@ List TTS voices: ...@@ -3600,5 +3758,9 @@ List TTS voices:
parser.add_argument("--prefer-speed", action="store_true", parser.add_argument("--prefer-speed", action="store_true",
help="In auto mode, prefer faster models over higher quality") help="In auto mode, prefer faster models over higher quality")
# Debug mode
parser.add_argument("--debug", action="store_true",
help="Enable debug mode for detailed error messages and troubleshooting")
args = parser.parse_args() args = parser.parse_args()
main(args) main(args)
{
"models": {
"wan_1.3b_i2v": {
"id": "Wan-AI/Wan2.1-I2V-1.3B-Diffusers",
"vram": "~8–10 GB",
"class": "WanPipeline",
"desc": "Small Wan I2V variant – NSFW friendly, no filter",
"extra": {"use_custom_vae": true},
"supports_i2v": true,
"tags": ["i2v", "video", "wan", "nsfw-friendly"]
},
"svd_xt_1.1": {
"id": "stabilityai/stable-video-diffusion-img2vid-xt-1-1",
"vram": "~14–18 GB",
"class": "StableVideoDiffusionPipeline",
"desc": "Stable Video Diffusion XT 1.1 – high-quality I2V, NSFW capable",
"supports_i2v": true,
"tags": ["i2v", "video", "svd", "nsfw-friendly"]
},
"i2vgen_xl": {
"id": "ali-vilab/i2vgen-xl",
"vram": "~18–24 GB",
"class": "I2VGenXLPipeline",
"desc": "Strong image-to-video XL – works with NSFW content",
"supports_i2v": true,
"tags": ["i2v", "video", "nsfw-friendly"]
},
"ltx_video": {
"id": "Lightricks/LTX-Video",
"vram": "~12–16 GB",
"class": "LTXVideoPipeline",
"desc": "Fast & efficient local video gen – NSFW friendly",
"supports_i2v": true,
"tags": ["i2v", "video", "ltx", "nsfw-friendly"]
},
"wan_14b_i2v": {
"id": "Wan-AI/Wan2.1-I2V-14B-Diffusers",
"vram": "~20–24 GB",
"class": "WanPipeline",
"desc": "Strong Wan I2V variant",
"extra": {"use_custom_vae": true},
"supports_i2v": true,
"tags": ["i2v", "video", "wan", "nsfw-friendly"]
},
"pony_uncensored_v6": {
"id": "AstraliteHeart/pony-diffusion-v6-xl-uncensored",
"vram": "~10–14 GB",
"class": "StableDiffusionXLPipeline",
"desc": "Uncensored Pony V6 XL – extremely NSFW-capable",
"supports_i2v": false,
"tags": ["image", "pony", "nsfw", "uncensored", "sdxl"]
},
"pony_realism_v2.2": {
"id": "AstraliteHeart/pony-realism-v2.2",
"vram": "~11–15 GB",
"class": "StableDiffusionXLPipeline",
"desc": "Realistic Pony merge – good for NSFW photoreal",
"supports_i2v": false,
"tags": ["image", "pony", "nsfw", "realism", "sdxl"]
},
"flux_nsfw_uncensored": {
"id": "lllyasviel/flux-nsfw-uncensored",
"vram": "~20–25 GB",
"class": "FluxPipeline",
"desc": "Uncensored NSFW Flux variant",
"supports_i2v": false,
"tags": ["image", "flux", "nsfw", "uncensored"]
},
"realistic_vision_v6": {
"id": "SG161222/Realistic_Vision_V6.0_B1_noVAE",
"vram": "~12–16 GB",
"class": "StableDiffusionXLPipeline",
"desc": "Realistic Vision V6 – strong NSFW realism",
"supports_i2v": false,
"tags": ["image", "realism", "nsfw-friendly", "sdxl"]
}
},
"search_queries": [
"i2v video generation nsfw",
"stable video diffusion",
"image to video",
"animatediff nsfw",
"svd fine-tune",
"wan i2v",
"ltx video",
"cogvideox"
]
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment