Files
EricRollei-Local_LLM_Prompt…/import_prompts_node.py
T
Eric HissandClaude Fable 5.1 4459af9ea6 V2.0.0: wildcard engine, platform profiles, MiniMax H3 default, API models
Every node id, input name and existing widget position is unchanged, so saved
workflows load; new inputs are appended only.

Wildcards
- core/wildcards: Dynamic Prompts / Impact Pack grammar, tag queries, variables,
  conditionals, concept / verbatim / loose bindings, reproducible seeds.
  Wired into every enhancer node; reads ComfyUI/models/wildcards.
- New nodes: Wildcard Processor, Semantic Variation (direction axes),
  Concept Survival Check. Starter lists in wildcards/.
- Random choices use a private generator; global random state is untouched.

Platform profiles
- core/profiles + profiles/*.yaml: one file per model (format, length,
  negative prompt or none, quality tokens, text and dialogue syntax, vendor
  rewriter prompt fetched once and cached). profiles_user/ overrides by id.
- New node: Platform Prompt Rewriter (prose, tags, edit instructions, JSON,
  MiniMax H3 fields, Hailuo brackets), with validators for each format.
- Text-to-Image and Image-to-Image read profiles through platforms.py;
  corrected facts for FLUX, Kontext, Chroma, Wan, AuraFlow, Kolors, NoobAI,
  Qwen-Image, HunyuanImage. Negative prompt is empty for models without one.
- Hosted / API models: Seedream 5, Nano Banana, GPT Image, Midjourney V8,
  FLUX.2 pro, Ideogram 3, Recraft V4, Seedance 2.0 / 2.5, Kling 3.0, Veo 3.1,
  Gemini Omni Flash, Runway, Wan 3.0, Luma, hosted H3, Grok, Vidu, PixVerse.
  Reports say how to switch the vendor's own prompt rewriting off.
- Illustrious: spaced tags, quality tags last, 25-80 words (OnomaAI paper).

Video nodes
- target_model and duration_seconds appended to the three video expanders.
  Default target is MiniMax H3; wan22_video is the original path, unchanged.
  A workflow saved earlier loads with the default until the input is set.

Also included: the Alice, Ideogram Magic Prompt and prompt-database nodes that
were already registered in __init__.py but had not been committed.

Fixes: v1 {animal} / {label:a|b} wildcards were inert in the video nodes;
Image-to-Video save_to_file raised NameError; T2I padded short-prompt models.

.gitattributes added (text=auto) so CRLF working files stop showing as
whole-file changes. prompt_database.db and the cached Ideogram prompt are
git-ignored.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019VpCi6nw5UECMdZ7ayYJvN
2026-09-21 00:28:58 -07:00

152 lines
5.4 KiB
Python

"""
Import Prompts to Database Node
ComfyUI node that bulk-imports prompts from .txt, .csv, or .json files.
Author: Eric Hiss (GitHub: EricRollei)
"""
import os
import logging
from .prompt_database import PromptDatabase, PLATFORMS, CATEGORIES
logger = logging.getLogger(__name__)
class ImportPromptsToDatabase:
"""
Bulk-import prompts from external files into the local prompt database.
Supported formats:
- .txt (one prompt per line, or paragraph-separated)
- .csv (header row: prompt_text, negative_prompt, category, …)
- .json (array of strings or array of objects with prompt_text key)
Duplicate detection prevents the same prompt being imported twice.
"""
def __init__(self):
self.db = PromptDatabase()
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"file_path": ("STRING", {
"default": "",
"tooltip": (
"Absolute path to the file to import. "
"Supports .txt, .csv, and .json."
),
}),
"file_format": (["auto", "txt_line", "txt_paragraph", "csv", "json"], {
"default": "auto",
"tooltip": (
"auto = detect from extension. "
"txt_line = one prompt per line. "
"txt_paragraph = prompts separated by blank lines."
),
}),
"default_category": (CATEGORIES, {
"default": "any",
"tooltip": "Category to assign when the file doesn't specify one.",
}),
"default_platform": (PLATFORMS, {
"default": "any",
"tooltip": "Platform to assign when the file doesn't specify one.",
}),
"default_tags": ("STRING", {
"default": "",
"tooltip": "Comma-separated tags to apply to every imported prompt.",
}),
"skip_duplicates": ("BOOLEAN", {
"default": True,
"tooltip": "Skip prompts that already exist in the database.",
}),
},
}
RETURN_TYPES = ("INT", "INT", "STRING", "STRING")
RETURN_NAMES = ("imported_count", "skipped_count", "status", "errors")
FUNCTION = "import_prompts"
CATEGORY = "Eric Prompt Enhancers/Database"
OUTPUT_NODE = True
def import_prompts(
self,
file_path: str,
file_format: str,
default_category: str,
default_platform: str,
default_tags: str,
skip_duplicates: bool,
):
file_path = file_path.strip()
if not file_path:
return (0, 0, "No file path provided.", "")
if not os.path.isfile(file_path):
return (0, 0, f"File not found: {file_path}", "")
# Detect format from extension when set to auto
fmt = file_format
if fmt == "auto":
ext = os.path.splitext(file_path)[1].lower()
if ext == ".csv":
fmt = "csv"
elif ext == ".json":
fmt = "json"
elif ext in (".txt", ".text", ".md", ".prompt", ".prompts"):
fmt = "txt_line"
else:
fmt = "txt_line" # sensible fallback
try:
if fmt == "csv":
imported, skipped, errors = self.db.import_from_csv(
file_path=file_path,
category=default_category,
platform=default_platform,
tags=default_tags,
skip_duplicates=skip_duplicates,
)
elif fmt == "json":
imported, skipped, errors = self.db.import_from_json(
file_path=file_path,
category=default_category,
platform=default_platform,
tags=default_tags,
skip_duplicates=skip_duplicates,
)
elif fmt == "txt_paragraph":
imported, skipped, errors = self.db.import_from_text_file(
file_path=file_path,
category=default_category,
platform=default_platform,
tags=default_tags,
delimiter="double_newline",
skip_duplicates=skip_duplicates,
)
else: # txt_line
imported, skipped, errors = self.db.import_from_text_file(
file_path=file_path,
category=default_category,
platform=default_platform,
tags=default_tags,
delimiter="newline",
skip_duplicates=skip_duplicates,
)
stats = self.db.stats()
status = (
f"Imported {imported} prompts, skipped {skipped} | "
f"DB total: {stats['total_prompts']} prompts"
)
error_text = "\n".join(errors) if errors else ""
logger.info(f"Import complete: {imported} added, {skipped} skipped from {file_path}")
return (imported, skipped, status, error_text)
except Exception as e:
logger.error(f"Import error: {e}")
return (0, 0, f"Import failed: {e}", str(e))