Merlintxu's picture
new file: configs/frame_templates.yaml
206183d
import openai
import time
import logging
from tenacity import retry, wait_exponential, stop_after_attempt
from PIL import Image
import requests
from io import BytesIO
import yaml
class FrameGenerator:
def __init__(self, api_key, config_path='configs/frame_templates.yaml'):
openai.api_key = api_key
self.logger = logging.getLogger(__name__)
self.templates = self._load_templates(config_path)
self.rate_limit = 5 # Llamadas por minuto
self.last_call = 0
def _load_templates(self, config_path):
try:
with open(config_path) as f:
return yaml.safe_load(f)['styles']
except Exception as e:
self.logger.error(f"Error loading templates: {str(e)}")
return {}
@retry(
wait=wait_exponential(multiplier=1, min=4, max=60),
stop=stop_after_attempt(3),
reraise=True
)
def generate_frame(self, image_url, metadata):
self._throttle_requests()
style = metadata.get('style', 'minimalista')
template = self.templates.get(style, self.templates['minimalista'])
prompt = self._build_prompt(template, metadata)
try:
response = openai.images.generate(
model="dall-e-3",
prompt=prompt,
size="1024x1024",
quality="hd",
n=1,
response_format="url"
)
return self._composite_frame(
image_url,
response.data[0].url,
template['mask_size']
)
except openai.RateLimitError:
self.logger.warning("Rate limit exceeded, retrying...")
time.sleep(60)
raise
except Exception as e:
self.logger.error(f"Generation failed: {str(e)}")
return None
def _build_prompt(self, template, metadata):
color_str = ", ".join(metadata['colors'][:3])
return (
f"High-quality frame for {metadata['style']} painting, "
f"main colors: {color_str}. {template['prompt']} "
"No text, no signatures, pure decorative frame."
)
def _throttle_requests(self):
elapsed = time.time() - self.last_call
if elapsed < 60 / self.rate_limit:
time.sleep(60 / self.rate_limit - elapsed)
self.last_call = time.time()
def _composite_frame(self, original_url, frame_url, mask_size=800):
try:
original = Image.open(requests.get(original_url, stream=True).raw)
frame = Image.open(requests.get(frame_url, stream=True).raw)
original = original.resize((mask_size, mask_size))
position = ((frame.width - original.width) // 2,
(frame.height - original.height) // 2)
composite = frame.copy()
composite.paste(original, position)
return composite
except Exception as e:
self.logger.error(f"Compositing failed: {str(e)}")
return None