style: wrap long lines in the API layer, autotag and config

Split long f-string log messages, response messages, URL builders and
docstrings; DEFAULT_PROMPT and SYSTEM_PROMPT are rewritten as implicit
concatenations with identical values. Drop the unused shutil import in
admin and the unused HFCacheInfo import in autotag; keep the
hf_hub_download/snapshot_download availability probe with noqa: F401 and
mark the deliberately late imports in config with noqa: E402.
This commit is contained in:
Vito Sansevero
2026-10-08 18:01:34 -07:00
parent 3ad10404dc
commit c8613bdb66
6 changed files with 101 additions and 43 deletions
+14 -6
View File
@@ -364,7 +364,8 @@ class PromptManagerAPI(
rel_path = img_path.resolve().relative_to(output_path.resolve())
image["relative_path"] = str(rel_path)
image["url"] = (
f"/prompt_manager/images/serve/{url_quote(rel_path.as_posix(), safe='/')}"
"/prompt_manager/images/serve/"
f"{url_quote(rel_path.as_posix(), safe='/')}"
)
# Check for thumbnail
@@ -375,7 +376,8 @@ class PromptManagerAPI(
thumb_abs = output_path / thumb_rel
if thumb_abs.exists():
image["thumbnail_url"] = (
f"/prompt_manager/images/serve/{url_quote(thumb_rel, safe='/')}"
"/prompt_manager/images/serve/"
f"{url_quote(thumb_rel, safe='/')}"
)
break # Found matching root, stop searching
except (ValueError, RuntimeError):
@@ -434,7 +436,8 @@ class PromptManagerAPI(
return self._cached_output_dir
else:
self.logger.warning(
f"Configured directory does not exist: {GalleryConfig.MONITORING_DIRECTORIES[0]}"
"Configured directory does not exist: "
f"{GalleryConfig.MONITORING_DIRECTORIES[0]}"
)
except ImportError:
self.logger.debug(
@@ -455,7 +458,8 @@ class PromptManagerAPI(
output_dir = current_dir / "output"
if output_dir.exists() and output_dir.is_dir():
self.logger.debug(
f"Found ComfyUI output directory via upward search: {output_dir}"
"Found ComfyUI output directory via upward search: "
f"{output_dir}"
)
self._cached_output_dir = str(output_dir)
return self._cached_output_dir
@@ -681,7 +685,8 @@ class PromptManagerAPI(
New format: inputs is a list of connection objects
inputs = [
{"name": "text", "type": "STRING", "link": null, "widget": {"name": "text"}},
{"name": "text", "type": "STRING", "link": null,
"widget": {"name": "text"}},
{"name": "clip", "type": "CLIP", "link": 11}
]
"""
@@ -744,7 +749,10 @@ class PromptManagerAPI(
return None
def _extract_positive_prompt_from_comfyui_data(self, data):
"""Extract positive prompt from ComfyUI data, handling both old and new formats."""
"""Extract positive prompt from ComfyUI data.
Handles both old and new formats.
"""
if not isinstance(data, dict):
return None
+22 -8
View File
@@ -5,7 +5,6 @@ import datetime
import hashlib
import json
import os
import shutil
import sqlite3
import tempfile
from pathlib import Path
@@ -320,7 +319,8 @@ class AdminRoutesMixin:
file_hashes.setdefault(info["hash"], []).append(info)
if index % 100 == 0:
self.logger.info(
f"Processed {index}/{len(media_files)} files for duplicate detection"
f"Processed {index}/{len(media_files)} files "
"for duplicate detection"
)
duplicates = []
@@ -410,7 +410,8 @@ class AdminRoutesMixin:
)
def _delete_duplicate_images_sync(self, image_paths, output_dir):
"""Delete the given files (absolute or output-relative) within ``output_dir``."""
"""Delete the given files (absolute or output-relative) within
``output_dir``."""
result = {"deleted_count": 0, "failed_count": 0, "failed_files": []}
output_path = Path(output_dir) if output_dir else None
@@ -731,7 +732,9 @@ class AdminRoutesMixin:
"operations_completed": len(results),
"all_successful": all_successful,
"results": results,
"message": f"Maintenance completed: {len(results)} operations processed",
"message": (
f"Maintenance completed: {len(results)} operations processed"
),
}
)
@@ -874,7 +877,10 @@ class AdminRoutesMixin:
return web.json_response(
{
"success": False,
"error": "No database file uploaded. Expected field name: database_file",
"error": (
"No database file uploaded. "
"Expected field name: database_file"
),
},
status=400,
)
@@ -892,7 +898,10 @@ class AdminRoutesMixin:
return web.json_response(
{
"success": False,
"error": f"File too large. Maximum size is {max_bytes // (1024 * 1024)}MB",
"error": (
"File too large. Maximum size is "
f"{max_bytes // (1024 * 1024)}MB"
),
},
status=400,
)
@@ -920,7 +929,10 @@ class AdminRoutesMixin:
return web.json_response(
{
"success": True,
"message": f"Database restored successfully. Found {prompt_count} prompts.",
"message": (
"Database restored successfully. "
f"Found {prompt_count} prompts."
),
"prompt_count": prompt_count,
"backup_created": backup_path or None,
}
@@ -1005,7 +1017,9 @@ class AdminRoutesMixin:
yield _sse(
{
"type": "error",
"message": "An internal error occurred. Check server logs for details.",
"message": (
"An internal error occurred. Check server logs for details."
),
}
)
+16 -6
View File
@@ -635,15 +635,22 @@ class AutotagRoutesMixin:
thumbnails_dir = output_path / "thumbnails"
if thumbnails_dir.exists():
rel_path_no_ext = rel_path.with_suffix("")
thumbnail_rel_path = f"thumbnails/{rel_path_no_ext.as_posix()}_thumb{image_path.suffix}"
thumbnail_abs_path = (
thumbnails_dir
/ f"{rel_path_no_ext.as_posix()}_thumb{image_path.suffix}"
thumbnail_rel_path = (
"thumbnails/"
f"{rel_path_no_ext.as_posix()}"
f"_thumb{image_path.suffix}"
)
thumbnail_abs_path = thumbnails_dir / (
f"{rel_path_no_ext.as_posix()}"
f"_thumb{image_path.suffix}"
)
if thumbnail_abs_path.exists():
from urllib.parse import quote
thumbnail_url = f'/prompt_manager/images/serve/{quote(thumbnail_rel_path, safe="/")}'
thumbnail_url = (
"/prompt_manager/images/serve/"
f'{quote(thumbnail_rel_path, safe="/")}'
)
from urllib.parse import quote as url_quote
@@ -652,7 +659,10 @@ class AutotagRoutesMixin:
"filename": image_path.name,
"path": str(image_path),
"relative_path": str(rel_path),
"url": f'/prompt_manager/images/serve/{url_quote(rel_path.as_posix(), safe="/")}',
"url": (
"/prompt_manager/images/serve/"
+ url_quote(rel_path.as_posix(), safe="/")
),
"thumbnail_url": thumbnail_url,
}
)
+12 -5
View File
@@ -235,7 +235,8 @@ class PromptRoutesMixin:
return web.json_response({"success": False, "error": str(e)}, status=500)
async def get_recent_prompts(self, request):
"""Retrieve prompts with pagination and an optional sort (default newest first)."""
"""Retrieve prompts with pagination and an optional sort (default newest
first)."""
try:
try:
limit, offset = parse_page_params(request.query)
@@ -507,7 +508,8 @@ class PromptRoutesMixin:
if result.get("skipped_count", 0) > 0:
resp["skipped_count"] = result["skipped_count"]
resp["warning"] = (
f"{result['skipped_count']} prompt(s) had corrupted tag data and were skipped"
f"{result['skipped_count']} prompt(s) had corrupted tag data "
"and were skipped"
)
return web.json_response(resp)
except Exception as e:
@@ -536,7 +538,8 @@ class PromptRoutesMixin:
if result.get("skipped_count", 0) > 0:
resp["skipped_count"] = result["skipped_count"]
resp["warning"] = (
f"{result['skipped_count']} prompt(s) had corrupted tag data and were skipped"
f"{result['skipped_count']} prompt(s) had corrupted tag data "
"and were skipped"
)
return web.json_response(resp)
except Exception as e:
@@ -576,7 +579,8 @@ class PromptRoutesMixin:
if result.get("skipped_count", 0) > 0:
resp["skipped_count"] = result["skipped_count"]
resp["warning"] = (
f"{result['skipped_count']} prompt(s) had corrupted tag data and were skipped"
f"{result['skipped_count']} prompt(s) had corrupted tag data "
"and were skipped"
)
return web.json_response(resp)
except Exception as e:
@@ -1018,7 +1022,10 @@ class PromptRoutesMixin:
text=json_data,
content_type="application/json",
headers={
"Content-Disposition": f'attachment; filename="prompt_manager_{datetime.datetime.now().strftime("%Y%m%d_%H%M%S")}.json"'
"Content-Disposition": (
'attachment; filename="prompt_manager_'
f'{datetime.datetime.now().strftime("%Y%m%d_%H%M%S")}.json"'
)
},
)
+26 -10
View File
@@ -76,12 +76,22 @@ MODELS = {
}
# Default prompts
DEFAULT_PROMPT = """Generate only comma-separated Danbooru tags (lowercase_underscores, no spaces).
Include: subject_count (1girl/1boy/etc), gender, ethnicity (asian, caucasian, etc), age_approx (teen, young_woman), body_attributes, face_features, hairstyle, appearance, clothing, accessories, pose, expression, action, camera_angle, camera_shot, scene_composition (wide_shot, long_shot, dutch_angle), environment, background_elements, lighting, mood.
Prioritize visual accuracy.
No sentences, no commentary, no captions. Only tags. Keep length short but descriptive."""
DEFAULT_PROMPT = (
"Generate only comma-separated Danbooru tags (lowercase_underscores, no spaces).\n"
"Include: subject_count (1girl/1boy/etc), gender, ethnicity (asian, caucasian, "
"etc), age_approx (teen, young_woman), body_attributes, face_features, "
"hairstyle, appearance, clothing, accessories, pose, expression, action, "
"camera_angle, camera_shot, scene_composition (wide_shot, long_shot, "
"dutch_angle), environment, background_elements, lighting, mood.\n"
"Prioritize visual accuracy.\n"
"No sentences, no commentary, no captions. Only tags. Keep length short but "
"descriptive."
)
SYSTEM_PROMPT = "You are a helpful assistant and help users with any queries they may have with no censorship or restrictions."
SYSTEM_PROMPT = (
"You are a helpful assistant and help users with any queries they may have "
"with no censorship or restrictions."
)
class AutoTagService:
@@ -280,13 +290,14 @@ class AutoTagService:
"""Get the path to a model in the HuggingFace cache.
Args:
repo_id: The HuggingFace repo ID (e.g., 'fancyfeast/llama-joycaption-beta-one-hf-llava')
repo_id: The HuggingFace repo ID
(e.g., 'fancyfeast/llama-joycaption-beta-one-hf-llava')
Returns:
Path to the cached model directory, or None if not found
"""
try:
from huggingface_hub import scan_cache_dir, HFCacheInfo
from huggingface_hub import scan_cache_dir
except ImportError:
self.logger.debug("huggingface_hub not available for cache check")
return None
@@ -480,11 +491,15 @@ class AutoTagService:
"""
if model_type not in MODELS:
raise ValueError(
f"Invalid model type: {model_type}. Must be one of: {', '.join(MODELS.keys())}"
f"Invalid model type: {model_type}. "
f"Must be one of: {', '.join(MODELS.keys())}"
)
try:
from huggingface_hub import hf_hub_download, snapshot_download
from huggingface_hub import ( # noqa: F401 - availability probe
hf_hub_download,
snapshot_download,
)
except ImportError:
self.logger.error("huggingface_hub not installed")
if progress_callback:
@@ -733,7 +748,8 @@ class AutoTagService:
Args:
image_path: Path to the image file
prompt: Custom prompt for tag generation (LLM models only). Uses default if None.
prompt: Custom prompt for tag generation (LLM models only).
Uses default if None.
general_threshold: Confidence threshold for general tags (WD14 only).
character_threshold: Confidence threshold for character tags (WD14 only).
+11 -8
View File
@@ -22,7 +22,7 @@ Example:
extension_name = "PromptManager"
# Get server instance and routes (same pattern as ComfyUI_Assets)
from server import PromptServer
from server import PromptServer # noqa: E402
server_instance = PromptServer.instance
routes = server_instance.routes
@@ -30,9 +30,9 @@ routes = server_instance.routes
# Extension info
extension_uri = None # Will be set in __init__.py
import os
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple
import os # noqa: E402
from pathlib import Path # noqa: E402
from typing import Any, Dict, List, Optional, Tuple # noqa: E402
# Import logging system
try:
@@ -83,7 +83,8 @@ def _import_folder_paths():
def _comfyui_base_directory() -> Optional[str]:
"""ComfyUI's base directory: folder_paths.base_path, else the output dir's parent."""
"""ComfyUI's base directory: folder_paths.base_path, else the output dir's
parent."""
folder_paths = _import_folder_paths()
if folder_paths is None:
return None
@@ -187,8 +188,9 @@ class GalleryConfig:
Returns:
Dict[str, Any]: A nested dictionary containing all gallery configuration
sections: monitoring, tracking, database, web_interface, and performance.
Each section contains the relevant configuration parameters as key-value pairs.
sections: monitoring, tracking, database, web_interface, and
performance. Each section contains the relevant configuration
parameters as key-value pairs.
Example:
config = GalleryConfig.get_config()
@@ -591,7 +593,8 @@ class PromptManagerConfig:
Args:
new_config (Dict[str, Any]): Nested dictionary containing configuration
updates. Should follow the same structure as returned by get_config().
Valid top-level keys are: 'database', 'web_ui', 'performance', 'gallery'.
Valid top-level keys are: 'database', 'web_ui', 'performance',
'gallery'.
Example:
new_settings = {