Spaces:
Build error
Build error
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 {} | |
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 |