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 |