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:
+14
-6
@@ -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
@@ -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."
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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 = {
|
||||
|
||||
Reference in New Issue
Block a user