305 lines
10 KiB
Python
305 lines
10 KiB
Python
"""Image Studio Manager - Main orchestration service for all image operations."""
|
|
|
|
from typing import Optional, Dict, Any, List
|
|
|
|
from .create_service import CreateStudioService, CreateStudioRequest
|
|
from .edit_service import EditStudioService, EditStudioRequest
|
|
from .upscale_service import UpscaleStudioService, UpscaleStudioRequest
|
|
from .templates import Platform, TemplateCategory, ImageTemplate
|
|
from utils.logger_utils import get_service_logger
|
|
|
|
|
|
logger = get_service_logger("image_studio.manager")
|
|
|
|
|
|
class ImageStudioManager:
|
|
"""Main manager for Image Studio operations."""
|
|
|
|
def __init__(self):
|
|
"""Initialize Image Studio Manager."""
|
|
self.create_service = CreateStudioService()
|
|
self.edit_service = EditStudioService()
|
|
self.upscale_service = UpscaleStudioService()
|
|
logger.info("[Image Studio Manager] Initialized successfully")
|
|
|
|
# ====================
|
|
# CREATE STUDIO
|
|
# ====================
|
|
|
|
async def create_image(
|
|
self,
|
|
request: CreateStudioRequest,
|
|
user_id: Optional[str] = None
|
|
) -> Dict[str, Any]:
|
|
"""Create/generate image using Create Studio.
|
|
|
|
Args:
|
|
request: Create studio request
|
|
user_id: User ID for validation
|
|
|
|
Returns:
|
|
Dictionary with generation results
|
|
"""
|
|
logger.info("[Image Studio] Create image request from user: %s", user_id)
|
|
return await self.create_service.generate(request, user_id=user_id)
|
|
|
|
# ====================
|
|
# EDIT STUDIO
|
|
# ====================
|
|
|
|
async def edit_image(
|
|
self,
|
|
request: EditStudioRequest,
|
|
user_id: Optional[str] = None,
|
|
) -> Dict[str, Any]:
|
|
"""Run Edit Studio operations."""
|
|
logger.info("[Image Studio] Edit image request from user: %s", user_id)
|
|
return await self.edit_service.process_edit(request, user_id=user_id)
|
|
|
|
def get_edit_operations(self) -> Dict[str, Any]:
|
|
"""Expose edit operations for UI."""
|
|
return self.edit_service.list_operations()
|
|
|
|
# ====================
|
|
# UPSCALE STUDIO
|
|
# ====================
|
|
|
|
async def upscale_image(
|
|
self,
|
|
request: UpscaleStudioRequest,
|
|
user_id: Optional[str] = None,
|
|
) -> Dict[str, Any]:
|
|
"""Run Upscale Studio operations."""
|
|
logger.info("[Image Studio] Upscale request from user: %s", user_id)
|
|
return await self.upscale_service.process_upscale(request, user_id=user_id)
|
|
|
|
def get_templates(
|
|
self,
|
|
platform: Optional[Platform] = None,
|
|
category: Optional[TemplateCategory] = None
|
|
) -> List[ImageTemplate]:
|
|
"""Get available templates.
|
|
|
|
Args:
|
|
platform: Filter by platform
|
|
category: Filter by category
|
|
|
|
Returns:
|
|
List of templates
|
|
"""
|
|
return self.create_service.get_templates(platform=platform, category=category)
|
|
|
|
def search_templates(self, query: str) -> List[ImageTemplate]:
|
|
"""Search templates by query.
|
|
|
|
Args:
|
|
query: Search query
|
|
|
|
Returns:
|
|
List of matching templates
|
|
"""
|
|
return self.create_service.search_templates(query)
|
|
|
|
def recommend_templates(
|
|
self,
|
|
use_case: str,
|
|
platform: Optional[Platform] = None
|
|
) -> List[ImageTemplate]:
|
|
"""Recommend templates based on use case.
|
|
|
|
Args:
|
|
use_case: Use case description
|
|
platform: Optional platform filter
|
|
|
|
Returns:
|
|
List of recommended templates
|
|
"""
|
|
return self.create_service.recommend_templates(use_case, platform)
|
|
|
|
def get_providers(self) -> Dict[str, Any]:
|
|
"""Get available image providers and their capabilities.
|
|
|
|
Returns:
|
|
Dictionary of providers with capabilities
|
|
"""
|
|
return {
|
|
"stability": {
|
|
"name": "Stability AI",
|
|
"models": ["ultra", "core", "sd3.5-large"],
|
|
"capabilities": ["text-to-image", "editing", "upscaling", "control", "3d"],
|
|
"max_resolution": (2048, 2048),
|
|
"cost_range": "3-8 credits per image",
|
|
},
|
|
"wavespeed": {
|
|
"name": "WaveSpeed AI",
|
|
"models": ["ideogram-v3-turbo", "qwen-image"],
|
|
"capabilities": ["text-to-image", "photorealistic", "fast-generation"],
|
|
"max_resolution": (1024, 1024),
|
|
"cost_range": "$0.05-$0.10 per image",
|
|
},
|
|
"huggingface": {
|
|
"name": "HuggingFace",
|
|
"models": ["FLUX.1-Krea-dev", "RunwayML"],
|
|
"capabilities": ["text-to-image", "image-to-image"],
|
|
"max_resolution": (1024, 1024),
|
|
"cost_range": "Free tier available",
|
|
},
|
|
"gemini": {
|
|
"name": "Google Gemini",
|
|
"models": ["imagen-3.0"],
|
|
"capabilities": ["text-to-image", "conversational-editing"],
|
|
"max_resolution": (1024, 1024),
|
|
"cost_range": "Free tier available",
|
|
}
|
|
}
|
|
|
|
# ====================
|
|
# COST ESTIMATION
|
|
# ====================
|
|
|
|
def estimate_cost(
|
|
self,
|
|
provider: str,
|
|
model: Optional[str],
|
|
operation: str,
|
|
num_images: int = 1,
|
|
resolution: Optional[tuple[int, int]] = None
|
|
) -> Dict[str, Any]:
|
|
"""Estimate cost for image operations.
|
|
|
|
Args:
|
|
provider: Provider name
|
|
model: Model name
|
|
operation: Operation type (generate, edit, upscale, etc.)
|
|
num_images: Number of images
|
|
resolution: Image resolution (width, height)
|
|
|
|
Returns:
|
|
Cost estimation details
|
|
"""
|
|
# Base costs (adjust based on actual pricing)
|
|
base_costs = {
|
|
"stability": {
|
|
"ultra": 0.08, # 8 credits
|
|
"core": 0.03, # 3 credits
|
|
"sd3": 0.065, # 6.5 credits
|
|
},
|
|
"wavespeed": {
|
|
"ideogram-v3-turbo": 0.10,
|
|
"qwen-image": 0.05,
|
|
},
|
|
"huggingface": {
|
|
"default": 0.0, # Free tier
|
|
},
|
|
"gemini": {
|
|
"default": 0.0, # Free tier
|
|
}
|
|
}
|
|
|
|
# Get base cost
|
|
provider_costs = base_costs.get(provider, {})
|
|
cost_per_image = provider_costs.get(model, provider_costs.get("default", 0.0))
|
|
|
|
# Calculate total
|
|
total_cost = cost_per_image * num_images
|
|
|
|
return {
|
|
"provider": provider,
|
|
"model": model,
|
|
"operation": operation,
|
|
"num_images": num_images,
|
|
"resolution": f"{resolution[0]}x{resolution[1]}" if resolution else "default",
|
|
"cost_per_image": cost_per_image,
|
|
"total_cost": total_cost,
|
|
"currency": "USD",
|
|
"estimated": True,
|
|
}
|
|
|
|
# ====================
|
|
# PLATFORM SPECS
|
|
# ====================
|
|
|
|
def get_platform_specs(self, platform: Platform) -> Dict[str, Any]:
|
|
"""Get platform specifications and requirements.
|
|
|
|
Args:
|
|
platform: Platform to get specs for
|
|
|
|
Returns:
|
|
Platform specifications
|
|
"""
|
|
specs = {
|
|
Platform.INSTAGRAM: {
|
|
"name": "Instagram",
|
|
"formats": [
|
|
{"name": "Feed Post (Square)", "ratio": "1:1", "size": "1080x1080"},
|
|
{"name": "Feed Post (Portrait)", "ratio": "4:5", "size": "1080x1350"},
|
|
{"name": "Story", "ratio": "9:16", "size": "1080x1920"},
|
|
{"name": "Reel", "ratio": "9:16", "size": "1080x1920"},
|
|
],
|
|
"file_types": ["JPG", "PNG"],
|
|
"max_file_size": "30MB",
|
|
},
|
|
Platform.FACEBOOK: {
|
|
"name": "Facebook",
|
|
"formats": [
|
|
{"name": "Feed Post", "ratio": "1.91:1", "size": "1200x630"},
|
|
{"name": "Feed Post (Square)", "ratio": "1:1", "size": "1080x1080"},
|
|
{"name": "Story", "ratio": "9:16", "size": "1080x1920"},
|
|
{"name": "Cover Photo", "ratio": "16:9", "size": "820x312"},
|
|
],
|
|
"file_types": ["JPG", "PNG"],
|
|
"max_file_size": "30MB",
|
|
},
|
|
Platform.TWITTER: {
|
|
"name": "Twitter/X",
|
|
"formats": [
|
|
{"name": "Post", "ratio": "16:9", "size": "1200x675"},
|
|
{"name": "Card", "ratio": "2:1", "size": "1200x600"},
|
|
{"name": "Header", "ratio": "3:1", "size": "1500x500"},
|
|
],
|
|
"file_types": ["JPG", "PNG", "GIF"],
|
|
"max_file_size": "5MB",
|
|
},
|
|
Platform.LINKEDIN: {
|
|
"name": "LinkedIn",
|
|
"formats": [
|
|
{"name": "Feed Post", "ratio": "1.91:1", "size": "1200x628"},
|
|
{"name": "Feed Post (Square)", "ratio": "1:1", "size": "1080x1080"},
|
|
{"name": "Article", "ratio": "2:1", "size": "1200x627"},
|
|
{"name": "Company Cover", "ratio": "4:1", "size": "1128x191"},
|
|
],
|
|
"file_types": ["JPG", "PNG"],
|
|
"max_file_size": "8MB",
|
|
},
|
|
Platform.YOUTUBE: {
|
|
"name": "YouTube",
|
|
"formats": [
|
|
{"name": "Thumbnail", "ratio": "16:9", "size": "1280x720"},
|
|
{"name": "Channel Art", "ratio": "16:9", "size": "2560x1440"},
|
|
],
|
|
"file_types": ["JPG", "PNG"],
|
|
"max_file_size": "2MB",
|
|
},
|
|
Platform.PINTEREST: {
|
|
"name": "Pinterest",
|
|
"formats": [
|
|
{"name": "Pin", "ratio": "2:3", "size": "1000x1500"},
|
|
{"name": "Story Pin", "ratio": "9:16", "size": "1080x1920"},
|
|
],
|
|
"file_types": ["JPG", "PNG"],
|
|
"max_file_size": "20MB",
|
|
},
|
|
Platform.TIKTOK: {
|
|
"name": "TikTok",
|
|
"formats": [
|
|
{"name": "Video Cover", "ratio": "9:16", "size": "1080x1920"},
|
|
],
|
|
"file_types": ["JPG", "PNG"],
|
|
"max_file_size": "10MB",
|
|
},
|
|
}
|
|
|
|
return specs.get(platform, {})
|
|
|