Major refactor: deduplicate routes, sync, JS, and fix bugs

- Extract 8 common route patterns into factory functions in routes/shared.py
  (favourite, upload, replace cover, save defaults, clone, save JSON,
  get missing, clear covers) — removes ~1,100 lines across 9 route files
- Extract generic _sync_category() in sync.py — 7 sync functions become
  one-liner wrappers, removing ~350 lines
- Extract shared detail page JS into static/js/detail-common.js — all 9
  detail templates now call initDetailPage() with minimal config
- Extract layout inline JS into static/js/layout-utils.js (~185 lines)
- Extract library toolbar JS into static/js/library-toolbar.js
- Fix finalize missing-image bug: raise RuntimeError instead of logging
  warning so job is marked failed
- Fix missing scheduler default in _default_checkpoint_data()
- Fix N+1 query in Character.get_available_outfits() with batch IN query
- Convert all print() to logger across services and routes
- Add missing tags display to styles, scenes, detailers, checkpoints detail
- Update delete buttons to use trash.png icon with solid red background
- Update CLAUDE.md to reflect new architecture

Net reduction: ~1,600 lines

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Aodhan Collins
2026-03-21 23:06:58 +00:00
parent ed9a7b4b11
commit 55ff58aba6
42 changed files with 1493 additions and 3105 deletions

View File

@@ -1,12 +1,15 @@
import os
import json
import asyncio
import logging
import requests
from flask import has_request_context, request as flask_request
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from models import Settings
logger = logging.getLogger('gaze')
DANBOORU_TOOLS = [
{
"type": "function",
@@ -73,7 +76,7 @@ def call_mcp_tool(name, arguments):
try:
return asyncio.run(_run_mcp_tool(name, arguments))
except Exception as e:
print(f"MCP Tool Error: {e}")
logger.error("MCP Tool Error: %s", e)
return json.dumps({"error": str(e)})
@@ -95,7 +98,7 @@ def call_character_mcp_tool(name, arguments):
try:
return asyncio.run(_run_character_mcp_tool(name, arguments))
except Exception as e:
print(f"Character MCP Tool Error: {e}")
logger.error("Character MCP Tool Error: %s", e)
return None
@@ -164,7 +167,7 @@ def call_llm(prompt, system_prompt="You are a creative assistant."):
# If 400 Bad Request and we were using tools, try once without tools
if response.status_code == 400 and use_tools:
print(f"LLM Provider {settings.llm_provider} rejected tools. Retrying without tool calling...")
logger.warning("LLM Provider %s rejected tools. Retrying without tool calling...", settings.llm_provider)
use_tools = False
max_turns += 1 # Reset turn for the retry
continue
@@ -186,7 +189,7 @@ def call_llm(prompt, system_prompt="You are a creative assistant."):
for tool_call in message['tool_calls']:
name = tool_call['function']['name']
args = json.loads(tool_call['function']['arguments'])
print(f"Executing MCP tool: {name}({args})")
logger.debug("Executing MCP tool: %s(%s)", name, args)
tool_result = call_mcp_tool(name, args)
messages.append({
"role": "tool",
@@ -195,7 +198,7 @@ def call_llm(prompt, system_prompt="You are a creative assistant."):
"content": tool_result
})
if tool_turns_remaining <= 0:
print("Tool turn limit reached — next request will not offer tools")
logger.warning("Tool turn limit reached — next request will not offer tools")
continue
return message['content']
@@ -209,7 +212,7 @@ def call_llm(prompt, system_prompt="You are a creative assistant."):
raw = ""
try: raw = response.text[:500]
except: pass
print(f"Unexpected LLM response format (key={e}). Raw response: {raw}")
logger.warning("Unexpected LLM response format (key=%s). Raw response: %s", e, raw)
if format_retries > 0:
format_retries -= 1
max_turns += 1 # don't burn a turn on a format error
@@ -222,7 +225,7 @@ def call_llm(prompt, system_prompt="You are a creative assistant."):
"Do not include any explanation or markdown — only the raw JSON object."
)
})
print(f"Retrying after format error ({format_retries} retries left)…")
logger.info("Retrying after format error (%d retries left)…", format_retries)
continue
raise RuntimeError(f"Unexpected LLM response format after retries: {str(e)}") from e