Code review fixes: wardrobe migration, response validation, path traversal guard, deduplication
- Migrate 11 character JSONs from old wardrobe keys to _BODY_GROUP_KEYS format - Add is_favourite/is_nsfw columns to Preset model - Add HTTP response validation and timeouts to ComfyUI client - Add path traversal protection on replace cover route - Deduplicate services/mcp.py (4 functions → 2 generic + 2 wrappers) - Extract apply_library_filters() and clean_html_text() shared helpers - Add named constants for 17 ComfyUI workflow node IDs - Fix bare except clauses in services/llm.py - Fix tags schema in ensure_default_outfit() (list → dict) - Convert f-string logging to lazy % formatting - Add 5-minute polling timeout to frontend waitForJob() - Improve migration error handling (non-duplicate errors log at WARNING) - Update CLAUDE.md to reflect all changes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@ import json
|
||||
import logging
|
||||
import requests
|
||||
from flask import current_app
|
||||
from services.workflow import NODE_CHECKPOINT
|
||||
|
||||
logger = logging.getLogger('gaze')
|
||||
|
||||
@@ -14,9 +15,11 @@ def get_loaded_checkpoint():
|
||||
if resp.ok:
|
||||
history = resp.json()
|
||||
if history:
|
||||
latest = max(history.values(), key=lambda j: j.get('status', {}).get('status_str', ''))
|
||||
# Sort by prompt ID (numeric string) to get the most recent job
|
||||
latest_id = max(history.keys())
|
||||
latest = history[latest_id]
|
||||
nodes = latest.get('prompt', [None, None, {}])[2]
|
||||
return nodes.get('4', {}).get('inputs', {}).get('ckpt_name')
|
||||
return nodes.get(NODE_CHECKPOINT, {}).get('inputs', {}).get('ckpt_name')
|
||||
except Exception:
|
||||
pass
|
||||
return None
|
||||
@@ -34,26 +37,27 @@ def _ensure_checkpoint_loaded(checkpoint_path):
|
||||
if resp.ok:
|
||||
history = resp.json()
|
||||
if history:
|
||||
latest = max(history.values(), key=lambda j: j.get('status', {}).get('status_str', ''))
|
||||
latest_id = max(history.keys())
|
||||
latest = history[latest_id]
|
||||
nodes = latest.get('prompt', [None, None, {}])[2]
|
||||
loaded_ckpt = nodes.get('4', {}).get('inputs', {}).get('ckpt_name')
|
||||
loaded_ckpt = nodes.get(NODE_CHECKPOINT, {}).get('inputs', {}).get('ckpt_name')
|
||||
|
||||
# If the loaded checkpoint matches what we want, no action needed
|
||||
if loaded_ckpt == checkpoint_path:
|
||||
logger.info(f"Checkpoint {checkpoint_path} already loaded in ComfyUI")
|
||||
logger.info("Checkpoint %s already loaded in ComfyUI", checkpoint_path)
|
||||
return
|
||||
|
||||
# Checkpoint doesn't match or couldn't determine - force unload all models
|
||||
logger.info(f"Forcing ComfyUI to unload models to ensure {checkpoint_path} loads")
|
||||
logger.info("Forcing ComfyUI to unload models to ensure %s loads", checkpoint_path)
|
||||
requests.post(f'{url}/free', json={'unload_models': True}, timeout=5)
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to check/force checkpoint reload: {e}")
|
||||
logger.warning("Failed to check/force checkpoint reload: %s", e)
|
||||
|
||||
|
||||
def queue_prompt(prompt_workflow, client_id=None):
|
||||
"""POST a workflow to ComfyUI's /prompt endpoint."""
|
||||
# Ensure the checkpoint in the workflow is loaded in ComfyUI
|
||||
checkpoint_path = prompt_workflow.get('4', {}).get('inputs', {}).get('ckpt_name')
|
||||
checkpoint_path = prompt_workflow.get(NODE_CHECKPOINT, {}).get('inputs', {}).get('ckpt_name')
|
||||
_ensure_checkpoint_loaded(checkpoint_path)
|
||||
|
||||
p = {"prompt": prompt_workflow}
|
||||
@@ -72,7 +76,10 @@ def queue_prompt(prompt_workflow, client_id=None):
|
||||
logger.debug("=" * 80)
|
||||
|
||||
data = json.dumps(p).encode('utf-8')
|
||||
response = requests.post(f"{url}/prompt", data=data)
|
||||
response = requests.post(f"{url}/prompt", data=data, timeout=30)
|
||||
if not response.ok:
|
||||
logger.error("ComfyUI returned HTTP %s: %s", response.status_code, response.text[:500])
|
||||
raise RuntimeError(f"ComfyUI returned HTTP {response.status_code}")
|
||||
response_json = response.json()
|
||||
|
||||
# Log the response from ComfyUI
|
||||
@@ -90,7 +97,7 @@ def queue_prompt(prompt_workflow, client_id=None):
|
||||
def get_history(prompt_id):
|
||||
"""Poll ComfyUI /history for results of a given prompt_id."""
|
||||
url = current_app.config['COMFYUI_URL']
|
||||
response = requests.get(f"{url}/history/{prompt_id}")
|
||||
response = requests.get(f"{url}/history/{prompt_id}", timeout=10)
|
||||
history_json = response.json()
|
||||
|
||||
# Log detailed history response for debugging
|
||||
@@ -128,6 +135,6 @@ def get_image(filename, subfolder, folder_type):
|
||||
data = {"filename": filename, "subfolder": subfolder, "type": folder_type}
|
||||
logger.debug("Fetching image from ComfyUI: filename=%s, subfolder=%s, type=%s",
|
||||
filename, subfolder, folder_type)
|
||||
response = requests.get(f"{url}/view", params=data)
|
||||
response = requests.get(f"{url}/view", params=data, timeout=30)
|
||||
logger.debug("Image retrieved: %d bytes (status: %s)", len(response.content), response.status_code)
|
||||
return response.content
|
||||
|
||||
Reference in New Issue
Block a user