""" Ultra Supreme Analyzer for image analysis and prompt building VERSIÓN MEJORADA - Potencia CLIP en lugar de limitarlo """ import re from typing import Dict, List, Any, Tuple import logging logger = logging.getLogger(__name__) class UltraSupremeAnalyzer: """ ULTRA SUPREME ANALYSIS ENGINE - POTENCIA CLIP, NO LO LIMITA """ def __init__(self): # Palabras a limpiar de las descripciones de CLIP self.cleanup_patterns = [ r'arafed\s*', r'there is\s*', r'a photo of\s*', r'an image of\s*', r'a picture of\s*', r'inspired by [^,]+,?\s*', r'by [A-Z][^,]+,?\s*', r'trending on [^,]+,?\s*', r'featured on [^,]+,?\s*', r'\d+k\s*', r'::\s*::\s*', r'contest winner,?\s*', r'award winning,?\s*', ] # Indicadores de calidad técnica self.technical_indicators = { 'portrait': ['portrait', 'headshot', 'face', 'person', 'man', 'woman', 'child'], 'landscape': ['mountain', 'landscape', 'nature', 'outdoor', 'field', 'forest'], 'dramatic': ['dramatic', 'light shining', 'silhouette', 'backlit', 'atmospheric'], 'professional': ['professional', 'studio', 'formal', 'business'], 'artistic': ['artistic', 'creative', 'abstract', 'conceptual'], 'documentary': ['documentary', 'candid', 'street', 'journalism', 'authentic'] } # Mejoras de iluminación basadas en contexto self.lighting_enhancements = { 'outdoor': 'natural lighting with golden hour warmth', 'mountain': 'dramatic alpine lighting with atmospheric haze', 'portrait': 'professional portrait lighting with subtle rim light', 'silhouette': 'dramatic backlighting creating ethereal silhouettes', 'indoor': 'soft diffused window lighting with gentle shadows', 'night': 'cinematic low-key lighting with strategic highlights', 'default': 'masterful lighting that enhances depth and dimension' } # Configuraciones de cámara según el tipo de foto self.camera_configs = { 'portrait': 'Shot on Hasselblad X2D 100C, 90mm f/2.5 lens at f/2.8', 'landscape': 'Shot on Phase One XT, 40mm f/4 lens at f/8', 'dramatic': 'Shot on Canon R5, 85mm f/1.2 lens at f/2', 'street': 'Shot on Leica M11, 35mm f/1.4 lens at f/2.8', 'default': 'Shot on Phase One XF IQ4, 80mm f/2.8 lens at f/4' } def clean_clip_description(self, description: str) -> str: """Limpia la descripción de CLIP eliminando ruido pero preservando contenido valioso""" cleaned = description.lower() # Eliminar patrones de ruido for pattern in self.cleanup_patterns: cleaned = re.sub(pattern, '', cleaned, flags=re.IGNORECASE) # Limpiar espacios múltiples y comas redundantes cleaned = re.sub(r'\s+', ' ', cleaned) cleaned = re.sub(r',\s*,+', ',', cleaned) cleaned = re.sub(r'^\s*,\s*', '', cleaned) cleaned = re.sub(r'\s*,\s*$', '', cleaned) return cleaned.strip() def extract_key_elements(self, clip_fast: str, clip_classic: str, clip_best: str) -> Dict[str, Any]: """Extrae elementos clave de las tres descripciones de CLIP""" # Limpiar todas las descripciones fast_clean = self.clean_clip_description(clip_fast) classic_clean = self.clean_clip_description(clip_classic) best_clean = self.clean_clip_description(clip_best) # Combinar información única de las tres fuentes all_descriptions = f"{fast_clean} {classic_clean} {best_clean}" # Extraer elementos principales elements = { 'main_subject': self._extract_main_subject(all_descriptions), 'action': self._extract_action(all_descriptions), 'location': self._extract_location(all_descriptions), 'mood': self._extract_mood(all_descriptions), 'special_features': self._extract_special_features(all_descriptions), 'technical_style': self._determine_technical_style(all_descriptions), 'original_essence': self._preserve_unique_elements(fast_clean, classic_clean, best_clean) } return elements def _extract_main_subject(self, description: str) -> str: """Extrae el sujeto principal de la descripción""" # Buscar patrones comunes de sujetos subject_patterns = [ r'(a |an )?([\w\s]+ )?(man|woman|person|child|boy|girl|people|group)', r'(a |an )?([\w\s]+ )?(portrait|face|figure)', r'(a |an )?([\w\s]+ )?(landscape|mountain|building|structure)', r'(a |an )?([\w\s]+ )?(animal|dog|cat|bird)', ] for pattern in subject_patterns: match = re.search(pattern, description) if match: return match.group(0).strip() # Si no encuentra un patrón específico, tomar las primeras palabras significativas words = description.split() if len(words) > 2: return ' '.join(words[:3]) return "figure" def _extract_action(self, description: str) -> str: """Extrae la acción o pose del sujeto""" action_keywords = ['standing', 'sitting', 'walking', 'running', 'looking', 'holding', 'wearing', 'posing', 'working', 'playing'] for keyword in action_keywords: if keyword in description: # Extraer contexto alrededor de la palabra clave pattern = rf'\b\w*\s*{keyword}\s*\w*\s*\w*' match = re.search(pattern, description) if match: return match.group(0).strip() return "" def _extract_location(self, description: str) -> str: """Extrae información de ubicación o ambiente""" location_keywords = ['mountain', 'beach', 'forest', 'city', 'street', 'indoor', 'outdoor', 'studio', 'nature', 'urban', 'field', 'desert', 'ocean', 'lake', 'building', 'home', 'office'] found_locations = [] for keyword in location_keywords: if keyword in description: found_locations.append(keyword) if found_locations: return ' '.join(found_locations[:2]) # Máximo 2 ubicaciones return "" def _extract_mood(self, description: str) -> str: """Extrae el mood o atmósfera de la imagen""" mood_keywords = ['dramatic', 'peaceful', 'serene', 'intense', 'mysterious', 'joyful', 'melancholic', 'powerful', 'ethereal', 'moody', 'bright', 'dark', 'atmospheric', 'dreamy', 'dynamic'] for keyword in mood_keywords: if keyword in description: return keyword return "" def _extract_special_features(self, description: str) -> List[str]: """Extrae características especiales únicas de la descripción""" special_patterns = [ 'light shining on [\w\s]+', 'wearing [\w\s]+', 'with [\w\s]+ in the background', 'surrounded by [\w\s]+', '[\w\s]+ lighting', '[\w\s]+ atmosphere' ] features = [] for pattern in special_patterns: matches = re.findall(pattern, description) features.extend(matches) return features[:3] # Limitar a 3 características especiales def _determine_technical_style(self, description: str) -> str: """Determina el estilo técnico más apropiado basado en el contenido""" style_scores = {} for style, keywords in self.technical_indicators.items(): score = sum(1 for keyword in keywords if keyword in description) if score > 0: style_scores[style] = score if style_scores: return max(style_scores, key=style_scores.get) return 'default' def _preserve_unique_elements(self, fast: str, classic: str, best: str) -> str: """Preserva elementos únicos e interesantes de las descripciones""" # Encontrar frases únicas que aparecen en alguna descripción all_words = set(fast.split() + classic.split() + best.split()) common_words = set(['a', 'an', 'the', 'is', 'are', 'was', 'were', 'with', 'of', 'in', 'on', 'at']) unique_words = all_words - common_words # Buscar frases interesantes que contengan estas palabras únicas unique_phrases = [] for desc in [fast, classic, best]: if 'light shining' in desc or 'adventure gear' in desc or 'anthropological' in desc: # Estas son frases únicas valiosas unique_phrases.append(desc) break return ' '.join(unique_phrases[:1]) if unique_phrases else "" def build_ultra_supreme_prompt(self, elements: Dict[str, Any], original_descriptions: List[str]) -> str: """Construye un prompt que POTENCIA la visión de CLIP""" components = [] # 1. Sujeto principal con artículo apropiado subject = elements['main_subject'] if subject: # Determinar artículo if subject[0].lower() in 'aeiou': components.append(f"An {subject}") else: components.append(f"A {subject}") else: components.append("A figure") # 2. Acción si existe if elements['action']: components.append(elements['action']) # 3. Características especiales (esto es lo que hace única la imagen) if elements['special_features']: for feature in elements['special_features'][:2]: components.append(feature) # 4. Ubicación/Ambiente if elements['location']: if 'mountain' in elements['location']: components.append("on a majestic mountain peak") elif 'outdoor' in elements['location'] or 'nature' in elements['location']: components.append("in a breathtaking natural setting") else: components.append(f"in {elements['location']}") # 5. Mood/Atmósfera si existe if elements['mood']: components.append(f"capturing a {elements['mood']} atmosphere") # 6. Iluminación basada en contexto lighting_context = elements['location'] or elements['technical_style'] lighting = self.lighting_enhancements.get(lighting_context, self.lighting_enhancements['default']) components.append(f"illuminated with {lighting}") # 7. Configuración técnica de cámara camera_setup = self.camera_configs.get(elements['technical_style'], self.camera_configs['default']) components.append(camera_setup) # 8. Estilo fotográfico final if elements['technical_style'] == 'portrait': components.append("masterful portrait photography") elif elements['technical_style'] == 'landscape': components.append("epic landscape photography") elif elements['technical_style'] == 'dramatic': components.append("cinematic photography with powerful visual impact") elif elements['technical_style'] == 'documentary': components.append("authentic documentary photography") else: components.append("professional photography with exceptional detail") # 9. Añadir esencia única preservada si existe if elements['original_essence'] and len(elements['original_essence']) > 10: # Incluir elementos únicos que CLIP detectó logger.info(f"Preservando esencia única: {elements['original_essence']}") # Construir prompt final prompt = ", ".join(components) # Limpieza final prompt = re.sub(r'\s+', ' ', prompt) prompt = re.sub(r',\s*,+', ',', prompt) prompt = re.sub(r'\s*,\s*', ', ', prompt) # Capitalizar primera letra if prompt: prompt = prompt[0].upper() + prompt[1:] logger.info(f"Prompt generado: {prompt}") return prompt def ultra_supreme_analysis(self, clip_fast: str, clip_classic: str, clip_best: str) -> Dict[str, Any]: """Análisis que POTENCIA la información de CLIP en lugar de limitarla""" logger.info("Iniciando análisis MEJORADO que potencia CLIP") # Extraer elementos clave de las descripciones elements = self.extract_key_elements(clip_fast, clip_classic, clip_best) # Construir resultado del análisis result = { "elements": elements, "technical_style": elements['technical_style'], "unique_features": elements['special_features'], "preserved_essence": elements['original_essence'], "mood": elements['mood'], "location": elements['location'] } return result def build_ultra_supreme_prompt(self, ultra_analysis: Dict[str, Any], clip_results: List[str]) -> str: """Versión pública del método para compatibilidad""" return self.build_ultra_supreme_prompt(ultra_analysis['elements'], clip_results) def calculate_ultra_supreme_score(self, prompt: str, ultra_analysis: Dict[str, Any]) -> Tuple[int, Dict[str, int]]: """Calcula score basado en la riqueza del prompt generado""" score = 0 breakdown = {} # Estructura (20 puntos) structure_score = 0 if prompt.startswith(("A ", "An ")): structure_score += 10 if prompt.count(",") >= 5: structure_score += 10 score += structure_score breakdown["structure"] = structure_score # Elementos únicos preservados (30 puntos) unique_score = 0 if ultra_analysis.get('unique_features'): unique_score += len(ultra_analysis['unique_features']) * 10 unique_score = min(unique_score, 30) score += unique_score breakdown["unique"] = unique_score # Contexto técnico (20 puntos) tech_score = 0 if "Shot on" in prompt: tech_score += 10 if any(term in prompt for term in ["f/", "mm"]): tech_score += 10 score += tech_score breakdown["technical"] = tech_score # Mood y atmósfera (15 puntos) mood_score = 0 if ultra_analysis.get('mood'): mood_score += 15 score += mood_score breakdown["mood"] = mood_score # Calidad descriptiva (15 puntos) desc_score = 0 if len(prompt) > 100: desc_score += 10 if any(term in prompt for term in ["masterful", "epic", "cinematic", "exceptional"]): desc_score += 5 score += desc_score breakdown["descriptive"] = desc_score return min(score, 100), breakdown