refactor: split api.py monolith into 19 route modules (Phase B)
Split 3,598-line api.py into thin orchestrator (128 lines) + 19 route
modules in bot/routes/:
core.py (7 routes), mood.py (10), language.py (3), evil_mode.py (6),
bipolar_mode.py (9), gpu.py (2), bot_actions.py (4), autonomous.py (13),
profile_picture.py (26), manual_send.py (3), servers.py (6),
figurines.py (5), dms.py (18), image_generation.py (4), chat.py (1),
config.py (7), logging_config.py (9), voice.py (3), memory.py (10)
All 146 routes verified present via test_route_split.py (149 tests).
21/21 regression tests (test_config_state.py) pass.
Monolith backup: bot/api_monolith_backup.py (revert: cp it to api.py).
2026-04-15 11:38:14 +03:00
|
|
|
"""Image generation routes: generate, status, test-detection, view."""
|
|
|
|
|
|
|
|
|
|
import os
|
|
|
|
|
from fastapi import APIRouter
|
2026-04-15 15:43:18 +03:00
|
|
|
from fastapi.responses import FileResponse, JSONResponse
|
refactor: split api.py monolith into 19 route modules (Phase B)
Split 3,598-line api.py into thin orchestrator (128 lines) + 19 route
modules in bot/routes/:
core.py (7 routes), mood.py (10), language.py (3), evil_mode.py (6),
bipolar_mode.py (9), gpu.py (2), bot_actions.py (4), autonomous.py (13),
profile_picture.py (26), manual_send.py (3), servers.py (6),
figurines.py (5), dms.py (18), image_generation.py (4), chat.py (1),
config.py (7), logging_config.py (9), voice.py (3), memory.py (10)
All 146 routes verified present via test_route_split.py (149 tests).
21/21 regression tests (test_config_state.py) pass.
Monolith backup: bot/api_monolith_backup.py (revert: cp it to api.py).
2026-04-15 11:38:14 +03:00
|
|
|
from utils.logger import get_logger
|
|
|
|
|
|
|
|
|
|
logger = get_logger('api')
|
|
|
|
|
|
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/image/generate")
|
|
|
|
|
async def manual_image_generation(req: dict):
|
|
|
|
|
"""Manually trigger image generation for testing"""
|
|
|
|
|
try:
|
|
|
|
|
prompt = req.get("prompt", "").strip()
|
|
|
|
|
if not prompt:
|
2026-04-15 15:43:18 +03:00
|
|
|
return JSONResponse(status_code=400, content={"status": "error", "message": "Prompt is required"})
|
refactor: split api.py monolith into 19 route modules (Phase B)
Split 3,598-line api.py into thin orchestrator (128 lines) + 19 route
modules in bot/routes/:
core.py (7 routes), mood.py (10), language.py (3), evil_mode.py (6),
bipolar_mode.py (9), gpu.py (2), bot_actions.py (4), autonomous.py (13),
profile_picture.py (26), manual_send.py (3), servers.py (6),
figurines.py (5), dms.py (18), image_generation.py (4), chat.py (1),
config.py (7), logging_config.py (9), voice.py (3), memory.py (10)
All 146 routes verified present via test_route_split.py (149 tests).
21/21 regression tests (test_config_state.py) pass.
Monolith backup: bot/api_monolith_backup.py (revert: cp it to api.py).
2026-04-15 11:38:14 +03:00
|
|
|
|
|
|
|
|
from utils.image_generation import generate_image_with_comfyui
|
|
|
|
|
image_path = await generate_image_with_comfyui(prompt)
|
|
|
|
|
|
|
|
|
|
if image_path:
|
|
|
|
|
return {"status": "ok", "message": f"Image generated successfully", "image_path": image_path}
|
|
|
|
|
else:
|
2026-04-15 15:43:18 +03:00
|
|
|
return JSONResponse(status_code=500, content={"status": "error", "message": "Failed to generate image"})
|
refactor: split api.py monolith into 19 route modules (Phase B)
Split 3,598-line api.py into thin orchestrator (128 lines) + 19 route
modules in bot/routes/:
core.py (7 routes), mood.py (10), language.py (3), evil_mode.py (6),
bipolar_mode.py (9), gpu.py (2), bot_actions.py (4), autonomous.py (13),
profile_picture.py (26), manual_send.py (3), servers.py (6),
figurines.py (5), dms.py (18), image_generation.py (4), chat.py (1),
config.py (7), logging_config.py (9), voice.py (3), memory.py (10)
All 146 routes verified present via test_route_split.py (149 tests).
21/21 regression tests (test_config_state.py) pass.
Monolith backup: bot/api_monolith_backup.py (revert: cp it to api.py).
2026-04-15 11:38:14 +03:00
|
|
|
|
|
|
|
|
except Exception as e:
|
2026-04-15 15:43:18 +03:00
|
|
|
return JSONResponse(status_code=500, content={"status": "error", "message": f"Error: {e}"})
|
refactor: split api.py monolith into 19 route modules (Phase B)
Split 3,598-line api.py into thin orchestrator (128 lines) + 19 route
modules in bot/routes/:
core.py (7 routes), mood.py (10), language.py (3), evil_mode.py (6),
bipolar_mode.py (9), gpu.py (2), bot_actions.py (4), autonomous.py (13),
profile_picture.py (26), manual_send.py (3), servers.py (6),
figurines.py (5), dms.py (18), image_generation.py (4), chat.py (1),
config.py (7), logging_config.py (9), voice.py (3), memory.py (10)
All 146 routes verified present via test_route_split.py (149 tests).
21/21 regression tests (test_config_state.py) pass.
Monolith backup: bot/api_monolith_backup.py (revert: cp it to api.py).
2026-04-15 11:38:14 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("/image/status")
|
|
|
|
|
async def get_image_generation_status():
|
|
|
|
|
"""Get status of image generation system"""
|
|
|
|
|
try:
|
|
|
|
|
from utils.image_generation import check_comfyui_status
|
|
|
|
|
status = await check_comfyui_status()
|
|
|
|
|
return {"status": "ok", **status}
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
2026-04-15 15:43:18 +03:00
|
|
|
return JSONResponse(status_code=500, content={"status": "error", "message": f"Error: {e}"})
|
refactor: split api.py monolith into 19 route modules (Phase B)
Split 3,598-line api.py into thin orchestrator (128 lines) + 19 route
modules in bot/routes/:
core.py (7 routes), mood.py (10), language.py (3), evil_mode.py (6),
bipolar_mode.py (9), gpu.py (2), bot_actions.py (4), autonomous.py (13),
profile_picture.py (26), manual_send.py (3), servers.py (6),
figurines.py (5), dms.py (18), image_generation.py (4), chat.py (1),
config.py (7), logging_config.py (9), voice.py (3), memory.py (10)
All 146 routes verified present via test_route_split.py (149 tests).
21/21 regression tests (test_config_state.py) pass.
Monolith backup: bot/api_monolith_backup.py (revert: cp it to api.py).
2026-04-15 11:38:14 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/image/test-detection")
|
|
|
|
|
async def test_image_detection(req: dict):
|
|
|
|
|
"""Test the natural language image detection system"""
|
|
|
|
|
try:
|
|
|
|
|
message = req.get("message", "").strip()
|
|
|
|
|
if not message:
|
2026-04-15 15:43:18 +03:00
|
|
|
return JSONResponse(status_code=400, content={"status": "error", "message": "Message is required"})
|
refactor: split api.py monolith into 19 route modules (Phase B)
Split 3,598-line api.py into thin orchestrator (128 lines) + 19 route
modules in bot/routes/:
core.py (7 routes), mood.py (10), language.py (3), evil_mode.py (6),
bipolar_mode.py (9), gpu.py (2), bot_actions.py (4), autonomous.py (13),
profile_picture.py (26), manual_send.py (3), servers.py (6),
figurines.py (5), dms.py (18), image_generation.py (4), chat.py (1),
config.py (7), logging_config.py (9), voice.py (3), memory.py (10)
All 146 routes verified present via test_route_split.py (149 tests).
21/21 regression tests (test_config_state.py) pass.
Monolith backup: bot/api_monolith_backup.py (revert: cp it to api.py).
2026-04-15 11:38:14 +03:00
|
|
|
|
|
|
|
|
from utils.image_generation import detect_image_request
|
|
|
|
|
is_image_request, extracted_prompt = await detect_image_request(message)
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
"status": "ok",
|
|
|
|
|
"is_image_request": is_image_request,
|
|
|
|
|
"extracted_prompt": extracted_prompt,
|
|
|
|
|
"original_message": message
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
2026-04-15 15:43:18 +03:00
|
|
|
return JSONResponse(status_code=500, content={"status": "error", "message": f"Error: {e}"})
|
refactor: split api.py monolith into 19 route modules (Phase B)
Split 3,598-line api.py into thin orchestrator (128 lines) + 19 route
modules in bot/routes/:
core.py (7 routes), mood.py (10), language.py (3), evil_mode.py (6),
bipolar_mode.py (9), gpu.py (2), bot_actions.py (4), autonomous.py (13),
profile_picture.py (26), manual_send.py (3), servers.py (6),
figurines.py (5), dms.py (18), image_generation.py (4), chat.py (1),
config.py (7), logging_config.py (9), voice.py (3), memory.py (10)
All 146 routes verified present via test_route_split.py (149 tests).
21/21 regression tests (test_config_state.py) pass.
Monolith backup: bot/api_monolith_backup.py (revert: cp it to api.py).
2026-04-15 11:38:14 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("/image/view/{filename}")
|
|
|
|
|
async def view_generated_image(filename: str):
|
|
|
|
|
"""Serve generated images from ComfyUI output directory"""
|
|
|
|
|
try:
|
|
|
|
|
logger.debug(f"Image view request for: {filename}")
|
|
|
|
|
|
|
|
|
|
# Try multiple possible paths for ComfyUI output
|
|
|
|
|
possible_paths = [
|
|
|
|
|
f"/app/ComfyUI/output/{filename}",
|
|
|
|
|
f"/home/koko210Serve/ComfyUI/output/{filename}",
|
|
|
|
|
f"./ComfyUI/output/{filename}",
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
image_path = None
|
|
|
|
|
for path in possible_paths:
|
|
|
|
|
if os.path.exists(path):
|
|
|
|
|
image_path = path
|
|
|
|
|
logger.debug(f"Found image at: {path}")
|
|
|
|
|
break
|
|
|
|
|
else:
|
|
|
|
|
logger.debug(f"Not found at: {path}")
|
|
|
|
|
|
|
|
|
|
if not image_path:
|
|
|
|
|
logger.warning(f"Image not found anywhere: {filename}")
|
2026-04-15 15:43:18 +03:00
|
|
|
return JSONResponse(status_code=404, content={"status": "error", "message": f"Image not found: {filename}"})
|
refactor: split api.py monolith into 19 route modules (Phase B)
Split 3,598-line api.py into thin orchestrator (128 lines) + 19 route
modules in bot/routes/:
core.py (7 routes), mood.py (10), language.py (3), evil_mode.py (6),
bipolar_mode.py (9), gpu.py (2), bot_actions.py (4), autonomous.py (13),
profile_picture.py (26), manual_send.py (3), servers.py (6),
figurines.py (5), dms.py (18), image_generation.py (4), chat.py (1),
config.py (7), logging_config.py (9), voice.py (3), memory.py (10)
All 146 routes verified present via test_route_split.py (149 tests).
21/21 regression tests (test_config_state.py) pass.
Monolith backup: bot/api_monolith_backup.py (revert: cp it to api.py).
2026-04-15 11:38:14 +03:00
|
|
|
|
|
|
|
|
# Determine content type based on file extension
|
|
|
|
|
ext = filename.lower().split('.')[-1]
|
|
|
|
|
content_type = "image/png"
|
|
|
|
|
if ext == "jpg" or ext == "jpeg":
|
|
|
|
|
content_type = "image/jpeg"
|
|
|
|
|
elif ext == "gif":
|
|
|
|
|
content_type = "image/gif"
|
|
|
|
|
elif ext == "webp":
|
|
|
|
|
content_type = "image/webp"
|
|
|
|
|
|
|
|
|
|
logger.info(f"Serving image: {image_path} as {content_type}")
|
|
|
|
|
return FileResponse(image_path, media_type=content_type)
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
logger.error(f"Error serving image: {e}")
|
2026-04-15 15:43:18 +03:00
|
|
|
return JSONResponse(status_code=500, content={"status": "error", "message": f"Error serving image: {e}"})
|