Files
2026-05-12 23:37:12 +08:00

334 lines
11 KiB
Python

"""
ComfyUI PromptServer 适配层
所有 ComfyUI 特定的 API 路由注册都在这里
支持热重载:设置环境变量 SIMPLE_PROMPT_DEV=1 启用开发模式
"""
import logging
import os
from aiohttp import web
logger = logging.getLogger("SimplePrompt")
MAX_SEARCH_LIMIT = 200
MAX_LIST_LIMIT = 500
# 检测开发模式
DEV_MODE = os.environ.get("SIMPLE_PROMPT_DEV", "").lower() in ("1", "true", "yes")
if DEV_MODE:
logger.info("[SimplePrompt] Development mode enabled - hot reload active")
def _maybe_reload():
"""
开发模式下重新加载核心模块
这使得修改代码后不需要重启 ComfyUI
"""
if not DEV_MODE:
return
import importlib
try:
# 重新加载核心模块
from simple_prompt.core import config, utils, database, tags, categories, presets
from simple_prompt import core
from simple_prompt.api import handlers
from simple_prompt import api
importlib.reload(config)
importlib.reload(utils)
importlib.reload(database)
importlib.reload(tags)
importlib.reload(categories)
importlib.reload(presets)
importlib.reload(core)
importlib.reload(handlers)
importlib.reload(api)
logger.debug("[DEV] Core modules reloaded")
except Exception as e:
logger.error(f"[DEV] Failed to reload modules: {e}")
def _get_handlers():
"""
获取处理器模块(开发模式下会先重载)
"""
_maybe_reload()
from simple_prompt.api import handlers
return handlers
def _parse_int_query(request, name: str, default: int, minimum: int = 0, maximum: int | None = None) -> int:
raw_value = request.query.get(name, str(default))
try:
value = int(raw_value)
except (TypeError, ValueError):
raise ValueError(f"Invalid '{name}' query parameter")
if value < minimum:
raise ValueError(f"'{name}' must be at least {minimum}")
if maximum is not None:
value = min(value, maximum)
return value
def _parse_categories(categories_str: str) -> list[int]:
if not categories_str:
return []
try:
return [int(c) for c in categories_str.split(",") if c.strip()]
except ValueError:
raise ValueError("Invalid 'categories' query parameter")
# --------------------------------------------------------------------------------
# 路由注册
# --------------------------------------------------------------------------------
try:
from server import PromptServer
# -------------------------
# Tags API
# -------------------------
@PromptServer.instance.routes.get("/simple-prompt/search-tags")
async def search_tags_api(request):
"""搜索标签"""
handlers = _get_handlers()
try:
query = request.query.get("q", "")
limit = _parse_int_query(request, "limit", 50, minimum=1, maximum=MAX_SEARCH_LIMIT)
use_aliases = request.query.get("use_aliases", "false").lower() == "true"
categories = _parse_categories(request.query.get("categories", ""))
results = await handlers.handle_search_tags(query, limit, use_aliases, categories)
return web.json_response(results)
except ValueError as e:
return web.json_response({"error": str(e)}, status=400)
except Exception as e:
logger.error(f"Search API error: {e}")
return web.json_response({"error": str(e)}, status=500)
@PromptServer.instance.routes.post("/simple-prompt/get-tags-details")
async def get_tags_details_api(request):
"""获取标签详情"""
handlers = _get_handlers()
try:
data = await request.json()
names = data.get("names", [])
fast = data.get("fast", False)
if not names:
return web.json_response({})
results = await handlers.handle_get_tags_details(names, fast)
return web.json_response(results)
except Exception as e:
logger.error(f"Get tags details API error: {e}")
return web.json_response({"error": str(e)}, status=500)
@PromptServer.instance.routes.get("/simple-prompt/tags/list")
async def tags_list_api(request):
"""列出标签"""
handlers = _get_handlers()
try:
source = request.query.get("source", "user")
limit = _parse_int_query(request, "limit", 50, minimum=1, maximum=MAX_LIST_LIMIT)
offset = _parse_int_query(request, "offset", 0, minimum=0)
query = request.query.get("q", "")
results = await handlers.handle_list_tags(source, limit, offset, query)
return web.json_response(results)
except ValueError as e:
return web.json_response({"error": str(e)}, status=400)
except Exception as e:
logger.error(f"Tags list error: {e}")
return web.json_response({"error": str(e)}, status=500)
@PromptServer.instance.routes.delete("/simple-prompt/tags/delete")
async def tags_delete_api(request):
"""删除标签"""
handlers = _get_handlers()
try:
data = await request.json()
name = data.get("name")
source = data.get("source")
result = await handlers.handle_delete_tag(name, source)
return web.json_response(result)
except ValueError as e:
return web.json_response({"error": str(e)}, status=400)
except Exception as e:
logger.error(f"Delete tag failed: {e}")
return web.json_response({"error": str(e)}, status=500)
@PromptServer.instance.routes.post("/simple-prompt/add-custom-tag")
async def add_custom_tag_api(request):
"""添加自定义标签"""
handlers = _get_handlers()
try:
data = await request.json()
result = await handlers.handle_add_custom_tag(data)
return web.json_response(result)
except ValueError as e:
return web.json_response({"error": str(e)}, status=400)
except Exception as e:
logger.error(f"Add custom tag failed: {e}")
return web.json_response({"error": str(e)}, status=500)
@PromptServer.instance.routes.post("/simple-prompt/toggle-like-tag")
async def toggle_like_tag_api(request):
"""切换点赞标签"""
handlers = _get_handlers()
try:
data = await request.json()
result = await handlers.handle_toggle_like_tag(data)
return web.json_response(result)
except ValueError as e:
return web.json_response({"error": str(e)}, status=400)
except Exception as e:
logger.error(f"Toggle like failed: {e}")
return web.json_response({"error": str(e)}, status=500)
# -------------------------
# Categories API
# -------------------------
@PromptServer.instance.routes.get("/simple-prompt/categories/list")
async def list_categories_api(request):
"""列出分类"""
handlers = _get_handlers()
try:
result = await handlers.handle_list_categories()
return web.json_response(result)
except Exception as e:
logger.error(f"List categories error: {e}")
return web.json_response({"error": str(e)}, status=500)
@PromptServer.instance.routes.post("/simple-prompt/categories/save")
async def save_categories_api(request):
"""保存分类"""
handlers = _get_handlers()
try:
data = await request.json()
categories = data.get("categories", [])
result = await handlers.handle_save_categories(categories)
return web.json_response(result)
except Exception as e:
logger.error(f"Save categories error: {e}")
return web.json_response({"error": str(e)}, status=500)
# -------------------------
# Presets API
# -------------------------
@PromptServer.instance.routes.get("/simple-prompt/presets/list")
async def list_presets_api(request):
"""列出预设"""
handlers = _get_handlers()
try:
result = await handlers.handle_list_presets()
return web.json_response(result)
except Exception as e:
logger.error(f"List presets error: {e}")
return web.json_response({"error": str(e)}, status=500)
@PromptServer.instance.routes.post("/simple-prompt/presets/save")
async def save_presets_api(request):
"""保存预设"""
handlers = _get_handlers()
try:
data = await request.json()
presets = data.get("presets", [])
result = await handlers.handle_save_presets(presets)
return web.json_response(result)
except Exception as e:
logger.error(f"Save presets error: {e}")
return web.json_response({"error": str(e)}, status=500)
# -------------------------
# Health & Update API
# -------------------------
@PromptServer.instance.routes.get("/simple-prompt/health")
async def health_check_api(request):
"""健康检查"""
handlers = _get_handlers()
try:
result = await handlers.handle_health_check()
return web.json_response(result)
except Exception as e:
return web.json_response({"error": str(e)}, status=500)
@PromptServer.instance.routes.get("/simple-prompt/check-update")
async def check_update_api(request):
"""检查更新"""
handlers = _get_handlers()
try:
result = await handlers.handle_check_update()
return web.json_response(result)
except Exception as e:
logger.error(f"Check update error: {e}")
return web.json_response({"error": str(e)}, status=500)
@PromptServer.instance.routes.post("/simple-prompt/update-tags")
async def update_tags_api(request):
"""更新标签数据"""
handlers = _get_handlers()
try:
try:
data = await request.json()
except Exception:
data = {}
url = data.get("url")
result = await handlers.handle_update_tags(url)
return web.json_response(result)
except ValueError as e:
return web.json_response({"error": str(e)}, status=400)
except Exception as e:
logger.error(f"Update tags error: {e}")
return web.json_response({"error": str(e)}, status=500)
@PromptServer.instance.routes.post("/simple-prompt/update-data")
async def update_data_api(request):
"""批量更新数据"""
handlers = _get_handlers()
try:
data = await request.json()
action = data.get("action")
result = await handlers.handle_update_data(action)
return web.json_response(result)
except ValueError as e:
return web.json_response({"error": str(e)}, status=400)
except Exception as e:
logger.error(f"Update data failed: {e}")
return web.json_response({"error": str(e)}, status=500)
logger.info("[SimplePrompt] API routes registered successfully")
except ImportError:
logger.warning("[SimplePrompt] PromptServer not available - running outside ComfyUI")