Upload 6 files
Browse files- interfaz_sara_directo_ui.py +1 -1
- sara_v3_parte_4_gen4_carga.py +195 -179
interfaz_sara_directo_ui.py
CHANGED
|
@@ -7,10 +7,10 @@
|
|
| 7 |
# ✅ Event handlers solo para sistema técnico
|
| 8 |
|
| 9 |
import gradio as gr
|
| 10 |
-
from sara_v3_interfaz_core import sara_optimized
|
| 11 |
|
| 12 |
# Importar funciones core SOLO GEN-4
|
| 13 |
from interfaz_sara_directo_core import (
|
|
|
|
| 14 |
analyze_image_step1,
|
| 15 |
generate_prompts_step2,
|
| 16 |
update_system_info,
|
|
|
|
| 7 |
# ✅ Event handlers solo para sistema técnico
|
| 8 |
|
| 9 |
import gradio as gr
|
|
|
|
| 10 |
|
| 11 |
# Importar funciones core SOLO GEN-4
|
| 12 |
from interfaz_sara_directo_core import (
|
| 13 |
+
sara_optimized,
|
| 14 |
analyze_image_step1,
|
| 15 |
generate_prompts_step2,
|
| 16 |
update_system_info,
|
sara_v3_parte_4_gen4_carga.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
-
# PARTE
|
| 2 |
# Sistema completo de carga y gestión del modelo Gen-4 con parser corregido
|
| 3 |
# Usa HuggingFaceH4/zephyr-7b-beta con reglas inteligentes y extracción optimizada
|
| 4 |
-
# ARREGLADO: Parser
|
| 5 |
|
| 6 |
import time
|
| 7 |
import re
|
|
@@ -117,8 +117,8 @@ def generate_technical_prompts_gen4(image_description: str, user_idea: str = "")
|
|
| 117 |
# Log de la respuesta raw para debug
|
| 118 |
sara_v3_state.logger.info(f"🔍 Respuesta Gen-4 raw: {generated_text[:200]}...")
|
| 119 |
|
| 120 |
-
# Parsear prompts técnicos con extracción
|
| 121 |
-
prompts =
|
| 122 |
|
| 123 |
generation_time = time.time() - start_time
|
| 124 |
|
|
@@ -144,220 +144,267 @@ def generate_technical_prompts_gen4(image_description: str, user_idea: str = "")
|
|
| 144 |
'method': 'fallback_technical'
|
| 145 |
}
|
| 146 |
|
| 147 |
-
def
|
| 148 |
"""
|
| 149 |
-
Parser
|
| 150 |
-
ARREGLADO:
|
| 151 |
"""
|
| 152 |
|
| 153 |
if not response.strip():
|
| 154 |
sara_v3_state.logger.warning("⚠️ Respuesta vacía de Gen-4")
|
| 155 |
return _generate_fallback_prompts_from_empty()
|
| 156 |
|
| 157 |
-
sara_v3_state.logger.info("📝 Parseando respuesta Gen-4 con
|
| 158 |
|
| 159 |
-
# Limpiar respuesta completa
|
| 160 |
-
cleaned_response =
|
| 161 |
|
| 162 |
-
#
|
| 163 |
-
sections =
|
| 164 |
-
|
| 165 |
-
# Estrategia 2: Si no hay párrafos, dividir por líneas
|
| 166 |
-
if len(sections) < 2:
|
| 167 |
-
lines = [l.strip() for l in cleaned_response.split('\n') if l.strip() and len(l.strip()) > 20]
|
| 168 |
-
sections = lines
|
| 169 |
|
| 170 |
-
#
|
| 171 |
-
|
| 172 |
-
sentences = [s.strip() + '.' for s in cleaned_response.split('.') if s.strip() and len(s.strip()) > 20]
|
| 173 |
-
sections = sentences
|
| 174 |
-
|
| 175 |
-
# Limpiar y validar cada sección
|
| 176 |
-
valid_prompts = []
|
| 177 |
for section in sections:
|
| 178 |
-
|
| 179 |
-
if
|
| 180 |
-
|
| 181 |
|
| 182 |
-
sara_v3_state.logger.info(f"🧹 Extraídos {len(
|
| 183 |
|
| 184 |
-
#
|
| 185 |
levels = ['basic', 'intermediate', 'advanced', 'experimental']
|
| 186 |
final_prompts = {}
|
| 187 |
|
| 188 |
for i, level in enumerate(levels):
|
| 189 |
-
if i < len(
|
| 190 |
-
# Usar prompt extraído
|
| 191 |
-
final_prompts[level] =
|
| 192 |
else:
|
| 193 |
-
# Generar prompt faltante
|
| 194 |
-
final_prompts[level] =
|
| 195 |
|
| 196 |
-
# Log final para
|
| 197 |
for level, prompt in final_prompts.items():
|
| 198 |
sara_v3_state.logger.info(f"📝 {level.upper()}: {prompt[:60]}...")
|
| 199 |
|
| 200 |
return final_prompts
|
| 201 |
|
| 202 |
-
def
|
| 203 |
-
"""
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
r'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 212 |
]
|
| 213 |
|
| 214 |
-
|
|
|
|
|
|
|
|
|
|
| 215 |
response = re.sub(pattern, '', response, flags=re.IGNORECASE | re.MULTILINE)
|
| 216 |
|
| 217 |
-
# Limpiar saltos de línea excesivos
|
| 218 |
response = re.sub(r'\n{3,}', '\n\n', response)
|
|
|
|
| 219 |
response = response.strip()
|
| 220 |
|
|
|
|
|
|
|
| 221 |
return response
|
| 222 |
|
| 223 |
-
def
|
| 224 |
"""
|
| 225 |
-
|
| 226 |
-
ARREGLADO: Menos destructiva, preserva contenido válido
|
| 227 |
"""
|
| 228 |
|
| 229 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 230 |
return ""
|
| 231 |
|
| 232 |
original_text = text
|
| 233 |
|
| 234 |
-
#
|
| 235 |
-
|
| 236 |
-
r'^\d+\
|
| 237 |
-
r'^
|
| 238 |
-
r'^
|
| 239 |
-
r'^
|
| 240 |
-
r'^
|
| 241 |
-
r'^
|
| 242 |
-
r'^
|
| 243 |
-
r'^
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 244 |
]
|
| 245 |
|
| 246 |
-
|
|
|
|
| 247 |
text = re.sub(pattern, '', text, flags=re.IGNORECASE)
|
| 248 |
|
| 249 |
-
# Limpiar comillas
|
| 250 |
-
text = re.sub(r'^["\']|["\']$', '', text)
|
| 251 |
-
text = re.sub(r'["\']([^"\']*)["\']', r'\1', text)
|
| 252 |
-
|
| 253 |
-
# Normalizar espacios
|
| 254 |
text = re.sub(r'\s+', ' ', text)
|
| 255 |
text = text.strip()
|
| 256 |
|
| 257 |
-
#
|
| 258 |
-
if
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 259 |
# Buscar contenido después de dos puntos
|
| 260 |
if ':' in original_text:
|
| 261 |
parts = original_text.split(':', 1)
|
| 262 |
-
if len(parts) > 1 and len(parts[1].strip()) >
|
| 263 |
text = parts[1].strip()
|
| 264 |
text = re.sub(r'^["\'\s]+|["\'\s]+$', '', text)
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
if text and len(text) > 10:
|
| 268 |
-
if not text[0].isupper():
|
| 269 |
-
text = text[0].upper() + text[1:]
|
| 270 |
-
|
| 271 |
-
if not text.endswith(('.', '!', '?')):
|
| 272 |
-
text += '.'
|
| 273 |
|
| 274 |
return text.strip()
|
| 275 |
|
| 276 |
-
def
|
| 277 |
"""
|
| 278 |
-
Validación
|
| 279 |
"""
|
| 280 |
|
| 281 |
-
if not text or len(text) <
|
| 282 |
return False
|
| 283 |
|
| 284 |
-
#
|
| 285 |
-
|
| 286 |
-
r'
|
| 287 |
-
r'
|
| 288 |
-
r'
|
| 289 |
-
r'^
|
|
|
|
| 290 |
]
|
| 291 |
|
| 292 |
-
for pattern in
|
| 293 |
-
if re.
|
| 294 |
return False
|
| 295 |
|
| 296 |
-
# Debe tener al menos
|
| 297 |
video_keywords = [
|
| 298 |
'camera', 'shot', 'movement', 'lighting', 'frame', 'focus',
|
| 299 |
'moves', 'tracks', 'follows', 'reveals', 'transitions',
|
| 300 |
-
'smoothly', 'slowly', 'gently', 'steadily', '
|
| 301 |
-
'
|
| 302 |
-
'cinematic', 'dramatic', 'golden', 'natural', 'professional'
|
| 303 |
]
|
| 304 |
|
| 305 |
text_lower = text.lower()
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
# Muy permisivo: solo necesita 1 palabra clave
|
| 309 |
-
has_keywords = keyword_count >= 1
|
| 310 |
-
|
| 311 |
-
# Debe tener longitud razonable
|
| 312 |
-
reasonable_length = 10 <= len(text) <= 1000
|
| 313 |
|
| 314 |
-
|
| 315 |
-
has_words = len(text.split()) >= 3
|
| 316 |
-
|
| 317 |
-
return has_keywords and reasonable_length and has_words
|
| 318 |
|
| 319 |
-
def
|
| 320 |
"""
|
| 321 |
-
Generar prompt para nivel específico
|
| 322 |
-
ARREGLADO: Mejor integración con prompts reales extraídos
|
| 323 |
"""
|
| 324 |
|
| 325 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 326 |
if existing_prompts:
|
| 327 |
base_prompt = existing_prompts[0]
|
| 328 |
|
| 329 |
-
# Extraer
|
| 330 |
base_lower = base_prompt.lower()
|
| 331 |
-
|
| 332 |
if 'woman' in base_lower:
|
| 333 |
-
subject = "
|
| 334 |
elif 'man' in base_lower:
|
| 335 |
-
subject = "
|
| 336 |
elif 'person' in base_lower:
|
| 337 |
-
subject = "
|
| 338 |
else:
|
| 339 |
-
subject = "
|
| 340 |
-
|
| 341 |
-
# Generar prompts escalados basados en el contenido real
|
| 342 |
-
level_templates = {
|
| 343 |
-
'basic': f"Camera tracks {subject.lower()} with steady movement, natural lighting creates professional framing.",
|
| 344 |
-
|
| 345 |
-
'intermediate': f"Steadicam follows {subject.lower()} with controlled precision, enhanced lighting creates cinematic depth and visual storytelling.",
|
| 346 |
-
|
| 347 |
-
'advanced': f"Sophisticated crane shot reveals {subject.lower()} through complex staging techniques, dramatic lighting transitions with color grading create compelling visual narrative using advanced cinematographic elements.",
|
| 348 |
-
|
| 349 |
-
'experimental': f"Time-lapse sequences transform conventional reality as {subject.lower()} transcends physical boundaries through innovative camera approaches and experimental lighting techniques."
|
| 350 |
-
}
|
| 351 |
|
| 352 |
-
|
|
|
|
|
|
|
|
|
|
| 353 |
|
| 354 |
-
|
| 355 |
-
return f"Camera moves smoothly while subject performs natural movement, professional lighting creates cinematic atmosphere."
|
| 356 |
|
| 357 |
def _generate_fallback_prompts_from_empty() -> dict:
|
| 358 |
-
"""Generar prompts cuando la respuesta está
|
| 359 |
|
| 360 |
-
sara_v3_state.logger.warning("⚠️ Generando prompts desde respuesta vacía")
|
| 361 |
|
| 362 |
return {
|
| 363 |
'basic': "Camera tracks steadily while subject moves naturally, professional lighting creates clean visual foundation.",
|
|
@@ -367,7 +414,7 @@ def _generate_fallback_prompts_from_empty() -> dict:
|
|
| 367 |
}
|
| 368 |
|
| 369 |
def _generate_technical_fallback_gen4(image_description: str, user_idea: str = "") -> dict:
|
| 370 |
-
"""Fallback técnico mejorado para Gen-4"""
|
| 371 |
|
| 372 |
sara_v3_state.logger.info("🔄 Generando fallback técnico Gen-4...")
|
| 373 |
|
|
@@ -387,7 +434,6 @@ def _generate_technical_fallback_gen4(image_description: str, user_idea: str = "
|
|
| 387 |
|
| 388 |
# Procesar e integrar user_idea si existe
|
| 389 |
if user_idea.strip():
|
| 390 |
-
# Limpiar user_idea
|
| 391 |
clean_idea = user_idea.strip()
|
| 392 |
|
| 393 |
# Remover artículos en español
|
|
@@ -406,9 +452,7 @@ def _generate_technical_fallback_gen4(image_description: str, user_idea: str = "
|
|
| 406 |
'se acerca': 'approaches',
|
| 407 |
'lentamente': 'slowly',
|
| 408 |
'rápidamente': 'quickly',
|
| 409 |
-
'suavemente': 'gently'
|
| 410 |
-
'movimiento': 'movement',
|
| 411 |
-
'iluminación': 'lighting'
|
| 412 |
}
|
| 413 |
|
| 414 |
for spanish, english in translation_map.items():
|
|
@@ -418,7 +462,7 @@ def _generate_technical_fallback_gen4(image_description: str, user_idea: str = "
|
|
| 418 |
else:
|
| 419 |
action_base = "moves naturally"
|
| 420 |
|
| 421 |
-
# Generar prompts técnicos
|
| 422 |
return {
|
| 423 |
'basic': f"{subject} {action_base} while camera tracks steadily, {clean_description}, professional lighting setup creates clean visual foundation.",
|
| 424 |
|
|
@@ -464,7 +508,7 @@ def get_gen4_info() -> dict:
|
|
| 464 |
info = {
|
| 465 |
'status': get_gen4_status(),
|
| 466 |
'model': 'HuggingFaceH4/zephyr-7b-beta',
|
| 467 |
-
'system': 'Reglas Inteligentes + Parser
|
| 468 |
}
|
| 469 |
|
| 470 |
if hasattr(sara_v3_state, 'gen4_load_time'):
|
|
@@ -479,35 +523,9 @@ def get_gen4_info() -> dict:
|
|
| 479 |
|
| 480 |
return info
|
| 481 |
|
| 482 |
-
# Función principal para integración con sistema existente
|
| 483 |
-
def integrate_gen4_with_existing_system():
|
| 484 |
-
"""Integrar Gen-4 con sistema SARA existente sin romper compatibilidad"""
|
| 485 |
-
|
| 486 |
-
sara_v3_state.logger.info("🔗 Integrando Gen-4 con sistema existente...")
|
| 487 |
-
|
| 488 |
-
# Verificar que sistema actual esté disponible
|
| 489 |
-
try:
|
| 490 |
-
from sara_v3_parte_4 import is_sara_ready
|
| 491 |
-
|
| 492 |
-
if is_sara_ready():
|
| 493 |
-
sara_v3_state.logger.info("✅ Sistema poético SARA-v2 disponible")
|
| 494 |
-
else:
|
| 495 |
-
sara_v3_state.logger.info("⚠️ Sistema poético no disponible")
|
| 496 |
-
except ImportError:
|
| 497 |
-
sara_v3_state.logger.info("⚠️ Sistema poético no disponible")
|
| 498 |
-
|
| 499 |
-
if is_gen4_ready():
|
| 500 |
-
sara_v3_state.logger.info("✅ Sistema técnico Gen-4 disponible")
|
| 501 |
-
else:
|
| 502 |
-
sara_v3_state.logger.info("⚠️ Sistema técnico no disponible")
|
| 503 |
-
|
| 504 |
-
# Marcar integración completada
|
| 505 |
-
sara_v3_state.dual_system_ready = True
|
| 506 |
-
sara_v3_state.logger.info("🎯 Sistema dual SARA disponible: Poético + Técnico")
|
| 507 |
-
|
| 508 |
if __name__ == "__main__":
|
| 509 |
-
# Test del sistema Gen-4
|
| 510 |
-
print("🧪 Probando carga SARA Gen-4...")
|
| 511 |
|
| 512 |
success = load_sara_gen4_complete()
|
| 513 |
|
|
@@ -524,25 +542,23 @@ if __name__ == "__main__":
|
|
| 524 |
if test_result['success']:
|
| 525 |
print("🎬 Test generación exitoso:")
|
| 526 |
for level, prompt in test_result['prompts'].items():
|
| 527 |
-
print(f" {level.upper()}: {prompt
|
| 528 |
else:
|
| 529 |
print(f"❌ Test generación falló: {test_result['error']}")
|
| 530 |
else:
|
| 531 |
print("❌ Error cargando Gen-4")
|
| 532 |
|
| 533 |
-
print("✅ Test Gen-4 completado")
|
| 534 |
|
| 535 |
-
# FINAL SARA V3 PARTE 4-GEN4 CARGA: PARSER
|
| 536 |
#
|
| 537 |
# CORRECCIONES IMPLEMENTADAS:
|
| 538 |
-
# ✅
|
| 539 |
-
# ✅
|
| 540 |
-
# ✅
|
| 541 |
-
# ✅
|
| 542 |
-
# ✅
|
| 543 |
-
# ✅
|
| 544 |
-
# ✅
|
| 545 |
-
# ✅ Logging
|
| 546 |
-
# ✅
|
| 547 |
-
# ✅ Un prompt limpio por nivel garantizado
|
| 548 |
-
# ✅ Preservación de contenido válido durante limpieza
|
|
|
|
| 1 |
+
# PARTE COMPLETA: SARA V3 PARTE 4-GEN4 CARGA - PARSER COMPLETAMENTE ARREGLADO
|
| 2 |
# Sistema completo de carga y gestión del modelo Gen-4 con parser corregido
|
| 3 |
# Usa HuggingFaceH4/zephyr-7b-beta con reglas inteligentes y extracción optimizada
|
| 4 |
+
# ARREGLADO: Parser agresivo que ELIMINA todas las etiquetas técnicas
|
| 5 |
|
| 6 |
import time
|
| 7 |
import re
|
|
|
|
| 117 |
# Log de la respuesta raw para debug
|
| 118 |
sara_v3_state.logger.info(f"🔍 Respuesta Gen-4 raw: {generated_text[:200]}...")
|
| 119 |
|
| 120 |
+
# Parsear prompts técnicos con extracción SUPER AGRESIVA
|
| 121 |
+
prompts = _parse_technical_response_super_aggressive(generated_text)
|
| 122 |
|
| 123 |
generation_time = time.time() - start_time
|
| 124 |
|
|
|
|
| 144 |
'method': 'fallback_technical'
|
| 145 |
}
|
| 146 |
|
| 147 |
+
def _parse_technical_response_super_aggressive(response: str) -> dict:
|
| 148 |
"""
|
| 149 |
+
Parser SUPER AGRESIVO para respuestas técnicas Gen-4
|
| 150 |
+
ARREGLADO: Elimina TODAS las etiquetas técnicas automáticamente
|
| 151 |
"""
|
| 152 |
|
| 153 |
if not response.strip():
|
| 154 |
sara_v3_state.logger.warning("⚠️ Respuesta vacía de Gen-4")
|
| 155 |
return _generate_fallback_prompts_from_empty()
|
| 156 |
|
| 157 |
+
sara_v3_state.logger.info("📝 Parseando respuesta Gen-4 con LIMPIEZA SUPER AGRESIVA...")
|
| 158 |
|
| 159 |
+
# PASO 1: Limpiar respuesta completa de etiquetas obvias
|
| 160 |
+
cleaned_response = _super_aggressive_cleaning(response)
|
| 161 |
|
| 162 |
+
# PASO 2: Dividir en secciones
|
| 163 |
+
sections = _extract_sections_multiple_strategies(cleaned_response)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 164 |
|
| 165 |
+
# PASO 3: Limpiar cada sección individualmente y ELIMINAR ETIQUETAS
|
| 166 |
+
clean_prompts = []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 167 |
for section in sections:
|
| 168 |
+
cleaned_prompt = _eliminate_all_technical_labels(section)
|
| 169 |
+
if _is_valid_clean_prompt(cleaned_prompt):
|
| 170 |
+
clean_prompts.append(cleaned_prompt)
|
| 171 |
|
| 172 |
+
sara_v3_state.logger.info(f"🧹 Extraídos {len(clean_prompts)} prompts LIMPIOS de {len(sections)} secciones")
|
| 173 |
|
| 174 |
+
# PASO 4: Asignar a niveles - UN PROMPT LIMPIO POR NIVEL
|
| 175 |
levels = ['basic', 'intermediate', 'advanced', 'experimental']
|
| 176 |
final_prompts = {}
|
| 177 |
|
| 178 |
for i, level in enumerate(levels):
|
| 179 |
+
if i < len(clean_prompts):
|
| 180 |
+
# Usar prompt limpio extraído
|
| 181 |
+
final_prompts[level] = clean_prompts[i]
|
| 182 |
else:
|
| 183 |
+
# Generar prompt faltante sin etiquetas
|
| 184 |
+
final_prompts[level] = _generate_clean_level_prompt(level, clean_prompts, cleaned_response)
|
| 185 |
|
| 186 |
+
# Log final para verificar limpieza
|
| 187 |
for level, prompt in final_prompts.items():
|
| 188 |
sara_v3_state.logger.info(f"📝 {level.upper()}: {prompt[:60]}...")
|
| 189 |
|
| 190 |
return final_prompts
|
| 191 |
|
| 192 |
+
def _super_aggressive_cleaning(response: str) -> str:
|
| 193 |
+
"""
|
| 194 |
+
Limpieza SUPER AGRESIVA de etiquetas técnicas de la respuesta completa
|
| 195 |
+
ARREGLADO: Elimina TODO lo que parezca etiqueta técnica
|
| 196 |
+
"""
|
| 197 |
+
|
| 198 |
+
# Lista completa de patrones a eliminar AGRESIVAMENTE
|
| 199 |
+
aggressive_patterns = [
|
| 200 |
+
# Patrones específicos que vimos en los logs
|
| 201 |
+
r'Prompt\s*\d+\s*\([^)]+\):\s*', # "Prompt 1 (Basic): "
|
| 202 |
+
r'Prompt\s*\d+\s*\(.*?\):\s*', # "Prompt 1 (cualquier cosa): "
|
| 203 |
+
r'Prompt\s*\d+:\s*', # "Prompt 1: "
|
| 204 |
+
|
| 205 |
+
# Patrones generales de etiquetas
|
| 206 |
+
r'^\d+\.\s*', # "1. "
|
| 207 |
+
r'^Basic:\s*', # "Basic: "
|
| 208 |
+
r'^Intermediate:\s*', # "Intermediate: "
|
| 209 |
+
r'^Advanced:\s*', # "Advanced: "
|
| 210 |
+
r'^Experimental:\s*', # "Experimental: "
|
| 211 |
+
r'^Level\s*\d+:\s*', # "Level 1: "
|
| 212 |
+
r'^[\-\*\•]\s*', # "- ", "* ", "• "
|
| 213 |
+
|
| 214 |
+
# Patrones más agresivos
|
| 215 |
+
r'Based on.*?here are.*?:', # Textos introductorios
|
| 216 |
+
r'Here are.*?prompts.*?:', # "Here are the prompts:"
|
| 217 |
+
r'Generate.*?prompts.*?:', # "Generate 4 prompts:"
|
| 218 |
+
r'.*?four prompts.*?:', # "Here are four prompts:"
|
| 219 |
+
r'.*?increasing complexity.*?:', # "with increasing complexity:"
|
| 220 |
+
|
| 221 |
+
# Eliminar numeración al inicio
|
| 222 |
+
r'^\s*\d+\)\s*', # "1) "
|
| 223 |
+
r'^\s*\(\d+\)\s*', # "(1) "
|
| 224 |
+
|
| 225 |
+
# Eliminar comillas mal formadas
|
| 226 |
+
r'^["\']|["\']$', # Comillas al inicio/final
|
| 227 |
]
|
| 228 |
|
| 229 |
+
original_response = response
|
| 230 |
+
|
| 231 |
+
# Aplicar todos los patrones de limpieza
|
| 232 |
+
for pattern in aggressive_patterns:
|
| 233 |
response = re.sub(pattern, '', response, flags=re.IGNORECASE | re.MULTILINE)
|
| 234 |
|
| 235 |
+
# Limpiar espacios múltiples y saltos de línea excesivos
|
| 236 |
response = re.sub(r'\n{3,}', '\n\n', response)
|
| 237 |
+
response = re.sub(r'\s+', ' ', response)
|
| 238 |
response = response.strip()
|
| 239 |
|
| 240 |
+
sara_v3_state.logger.info(f"🧹 Limpieza agresiva: {len(original_response)} → {len(response)} caracteres")
|
| 241 |
+
|
| 242 |
return response
|
| 243 |
|
| 244 |
+
def _extract_sections_multiple_strategies(text: str) -> list:
|
| 245 |
"""
|
| 246 |
+
Extraer secciones usando múltiples estrategias
|
|
|
|
| 247 |
"""
|
| 248 |
|
| 249 |
+
# Estrategia 1: Dividir por párrafos dobles
|
| 250 |
+
sections = [s.strip() for s in text.split('\n\n') if s.strip() and len(s.strip()) > 15]
|
| 251 |
+
|
| 252 |
+
if len(sections) >= 4:
|
| 253 |
+
return sections[:4] # Tomar los primeros 4
|
| 254 |
+
|
| 255 |
+
# Estrategia 2: Dividir por líneas individuales
|
| 256 |
+
if len(sections) < 4:
|
| 257 |
+
lines = [l.strip() for l in text.split('\n') if l.strip() and len(l.strip()) > 15]
|
| 258 |
+
if len(lines) >= 4:
|
| 259 |
+
return lines[:4]
|
| 260 |
+
sections.extend(lines)
|
| 261 |
+
|
| 262 |
+
# Estrategia 3: Dividir por puntos
|
| 263 |
+
if len(sections) < 4:
|
| 264 |
+
sentences = [s.strip() + '.' for s in text.split('.') if s.strip() and len(s.strip()) > 15]
|
| 265 |
+
sections.extend(sentences)
|
| 266 |
+
|
| 267 |
+
# Retornar al menos 4 secciones (rellenar si es necesario)
|
| 268 |
+
while len(sections) < 4:
|
| 269 |
+
sections.append("Camera moves smoothly while subject performs natural action, professional lighting creates cinematic atmosphere.")
|
| 270 |
+
|
| 271 |
+
return sections[:4]
|
| 272 |
+
|
| 273 |
+
def _eliminate_all_technical_labels(text: str) -> str:
|
| 274 |
+
"""
|
| 275 |
+
Eliminar TODAS las etiquetas técnicas de un prompt individual
|
| 276 |
+
ARREGLADO: Más agresivo con la limpieza
|
| 277 |
+
"""
|
| 278 |
+
|
| 279 |
+
if not text or len(text) < 5:
|
| 280 |
return ""
|
| 281 |
|
| 282 |
original_text = text
|
| 283 |
|
| 284 |
+
# Patrones específicos para eliminar etiquetas restantes
|
| 285 |
+
label_elimination_patterns = [
|
| 286 |
+
r'^Prompt\s*\d+\s*\([^)]+\):\s*', # "Prompt 1 (Basic): "
|
| 287 |
+
r'^Prompt\s*\d+\s*\(.*?\):\s*', # "Prompt 1 (...): "
|
| 288 |
+
r'^Prompt\s*\d+:\s*', # "Prompt 1: "
|
| 289 |
+
r'^\d+\.\s*Basic:\s*', # "1. Basic: "
|
| 290 |
+
r'^\d+\.\s*Intermediate:\s*', # "2. Intermediate: "
|
| 291 |
+
r'^\d+\.\s*Advanced:\s*', # "3. Advanced: "
|
| 292 |
+
r'^\d+\.\s*Experimental:\s*', # "4. Experimental: "
|
| 293 |
+
r'^Basic\s*Level:\s*', # "Basic Level: "
|
| 294 |
+
r'^Intermediate\s*Level:\s*', # "Intermediate Level: "
|
| 295 |
+
r'^Advanced\s*Level:\s*', # "Advanced Level: "
|
| 296 |
+
r'^Experimental\s*Level:\s*', # "Experimental Level: "
|
| 297 |
+
r'^\d+\.\s*', # "1. ", "2. ", etc.
|
| 298 |
+
r'^[\-\*\•]\s*', # "- ", "* ", "• "
|
| 299 |
]
|
| 300 |
|
| 301 |
+
# Aplicar limpieza de etiquetas
|
| 302 |
+
for pattern in label_elimination_patterns:
|
| 303 |
text = re.sub(pattern, '', text, flags=re.IGNORECASE)
|
| 304 |
|
| 305 |
+
# Limpiar comillas y espacios
|
| 306 |
+
text = re.sub(r'^["\'\s]+|["\'\s]+$', '', text)
|
|
|
|
|
|
|
|
|
|
| 307 |
text = re.sub(r'\s+', ' ', text)
|
| 308 |
text = text.strip()
|
| 309 |
|
| 310 |
+
# Asegurar capitalización y terminación
|
| 311 |
+
if text and len(text) > 5:
|
| 312 |
+
# Capitalizar primera letra
|
| 313 |
+
text = text[0].upper() + text[1:] if len(text) > 1 else text.upper()
|
| 314 |
+
|
| 315 |
+
# Asegurar terminación con punto
|
| 316 |
+
if not text.endswith(('.', '!', '?')):
|
| 317 |
+
text += '.'
|
| 318 |
+
|
| 319 |
+
# Si se vació demasiado, intentar recuperar contenido útil
|
| 320 |
+
if len(text) < 10 and len(original_text) > 20:
|
| 321 |
# Buscar contenido después de dos puntos
|
| 322 |
if ':' in original_text:
|
| 323 |
parts = original_text.split(':', 1)
|
| 324 |
+
if len(parts) > 1 and len(parts[1].strip()) > 10:
|
| 325 |
text = parts[1].strip()
|
| 326 |
text = re.sub(r'^["\'\s]+|["\'\s]+$', '', text)
|
| 327 |
+
if text and not text.endswith(('.', '!', '?')):
|
| 328 |
+
text += '.'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 329 |
|
| 330 |
return text.strip()
|
| 331 |
|
| 332 |
+
def _is_valid_clean_prompt(text: str) -> bool:
|
| 333 |
"""
|
| 334 |
+
Validación PERMISIVA de prompts limpios
|
| 335 |
"""
|
| 336 |
|
| 337 |
+
if not text or len(text) < 8:
|
| 338 |
return False
|
| 339 |
|
| 340 |
+
# NO debe contener etiquetas técnicas residuales
|
| 341 |
+
bad_patterns = [
|
| 342 |
+
r'Prompt\s*\d+',
|
| 343 |
+
r'Basic:|Intermediate:|Advanced:|Experimental:',
|
| 344 |
+
r'Level\s*\d+',
|
| 345 |
+
r'^\d+\.',
|
| 346 |
+
r'^[\-\*\•]'
|
| 347 |
]
|
| 348 |
|
| 349 |
+
for pattern in bad_patterns:
|
| 350 |
+
if re.search(pattern, text, re.IGNORECASE):
|
| 351 |
return False
|
| 352 |
|
| 353 |
+
# Debe tener al menos alguna palabra relacionada con video
|
| 354 |
video_keywords = [
|
| 355 |
'camera', 'shot', 'movement', 'lighting', 'frame', 'focus',
|
| 356 |
'moves', 'tracks', 'follows', 'reveals', 'transitions',
|
| 357 |
+
'smoothly', 'slowly', 'gently', 'steadily', 'subject',
|
| 358 |
+
'cinematic', 'dramatic', 'natural', 'professional'
|
|
|
|
| 359 |
]
|
| 360 |
|
| 361 |
text_lower = text.lower()
|
| 362 |
+
has_video_keyword = any(keyword in text_lower for keyword in video_keywords)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 363 |
|
| 364 |
+
return has_video_keyword and len(text.split()) >= 5
|
|
|
|
|
|
|
|
|
|
| 365 |
|
| 366 |
+
def _generate_clean_level_prompt(level: str, existing_prompts: list, original_response: str) -> str:
|
| 367 |
"""
|
| 368 |
+
Generar prompt limpio para nivel específico SIN etiquetas técnicas
|
|
|
|
| 369 |
"""
|
| 370 |
|
| 371 |
+
# Templates limpios sin etiquetas
|
| 372 |
+
clean_templates = {
|
| 373 |
+
'basic': "Camera tracks steadily while subject moves naturally, professional lighting creates clean visual foundation.",
|
| 374 |
+
|
| 375 |
+
'intermediate': "Steadicam follows subject with controlled movement, enhanced lighting creates cinematic depth and atmospheric storytelling.",
|
| 376 |
+
|
| 377 |
+
'advanced': "Sophisticated camera work employs complex staging techniques, dramatic lighting transitions with color grading create compelling visual narrative using advanced cinematographic elements.",
|
| 378 |
+
|
| 379 |
+
'experimental': "Time-lapse sequences transform conventional reality through innovative camera approaches, experimental lighting techniques create transcendent visual poetry."
|
| 380 |
+
}
|
| 381 |
+
|
| 382 |
+
# Si hay prompts existentes, intentar extrapolar el contenido
|
| 383 |
if existing_prompts:
|
| 384 |
base_prompt = existing_prompts[0]
|
| 385 |
|
| 386 |
+
# Extraer sujeto del prompt base
|
| 387 |
base_lower = base_prompt.lower()
|
|
|
|
| 388 |
if 'woman' in base_lower:
|
| 389 |
+
subject = "woman"
|
| 390 |
elif 'man' in base_lower:
|
| 391 |
+
subject = "man"
|
| 392 |
elif 'person' in base_lower:
|
| 393 |
+
subject = "person"
|
| 394 |
else:
|
| 395 |
+
subject = "subject"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 396 |
|
| 397 |
+
# Personalizar template con el sujeto
|
| 398 |
+
template = clean_templates.get(level, clean_templates['basic'])
|
| 399 |
+
personalized = template.replace('subject', subject)
|
| 400 |
+
return personalized
|
| 401 |
|
| 402 |
+
return clean_templates.get(level, clean_templates['basic'])
|
|
|
|
| 403 |
|
| 404 |
def _generate_fallback_prompts_from_empty() -> dict:
|
| 405 |
+
"""Generar prompts limpios cuando la respuesta está vacía"""
|
| 406 |
|
| 407 |
+
sara_v3_state.logger.warning("⚠️ Generando prompts limpios desde respuesta vacía")
|
| 408 |
|
| 409 |
return {
|
| 410 |
'basic': "Camera tracks steadily while subject moves naturally, professional lighting creates clean visual foundation.",
|
|
|
|
| 414 |
}
|
| 415 |
|
| 416 |
def _generate_technical_fallback_gen4(image_description: str, user_idea: str = "") -> dict:
|
| 417 |
+
"""Fallback técnico mejorado para Gen-4 SIN etiquetas"""
|
| 418 |
|
| 419 |
sara_v3_state.logger.info("🔄 Generando fallback técnico Gen-4...")
|
| 420 |
|
|
|
|
| 434 |
|
| 435 |
# Procesar e integrar user_idea si existe
|
| 436 |
if user_idea.strip():
|
|
|
|
| 437 |
clean_idea = user_idea.strip()
|
| 438 |
|
| 439 |
# Remover artículos en español
|
|
|
|
| 452 |
'se acerca': 'approaches',
|
| 453 |
'lentamente': 'slowly',
|
| 454 |
'rápidamente': 'quickly',
|
| 455 |
+
'suavemente': 'gently'
|
|
|
|
|
|
|
| 456 |
}
|
| 457 |
|
| 458 |
for spanish, english in translation_map.items():
|
|
|
|
| 462 |
else:
|
| 463 |
action_base = "moves naturally"
|
| 464 |
|
| 465 |
+
# Generar prompts técnicos LIMPIOS sin etiquetas
|
| 466 |
return {
|
| 467 |
'basic': f"{subject} {action_base} while camera tracks steadily, {clean_description}, professional lighting setup creates clean visual foundation.",
|
| 468 |
|
|
|
|
| 508 |
info = {
|
| 509 |
'status': get_gen4_status(),
|
| 510 |
'model': 'HuggingFaceH4/zephyr-7b-beta',
|
| 511 |
+
'system': 'Reglas Inteligentes + Parser SUPER AGRESIVO'
|
| 512 |
}
|
| 513 |
|
| 514 |
if hasattr(sara_v3_state, 'gen4_load_time'):
|
|
|
|
| 523 |
|
| 524 |
return info
|
| 525 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 526 |
if __name__ == "__main__":
|
| 527 |
+
# Test del sistema Gen-4 con parser agresivo
|
| 528 |
+
print("🧪 Probando carga SARA Gen-4 con parser SUPER AGRESIVO...")
|
| 529 |
|
| 530 |
success = load_sara_gen4_complete()
|
| 531 |
|
|
|
|
| 542 |
if test_result['success']:
|
| 543 |
print("🎬 Test generación exitoso:")
|
| 544 |
for level, prompt in test_result['prompts'].items():
|
| 545 |
+
print(f" {level.upper()}: {prompt}")
|
| 546 |
else:
|
| 547 |
print(f"❌ Test generación falló: {test_result['error']}")
|
| 548 |
else:
|
| 549 |
print("❌ Error cargando Gen-4")
|
| 550 |
|
| 551 |
+
print("✅ Test Gen-4 completado con parser SUPER AGRESIVO")
|
| 552 |
|
| 553 |
+
# FINAL SARA V3 PARTE 4-GEN4 CARGA: PARSER SUPER AGRESIVO IMPLEMENTADO
|
| 554 |
#
|
| 555 |
# CORRECCIONES IMPLEMENTADAS:
|
| 556 |
+
# ✅ _parse_technical_response_super_aggressive() - Parser completamente reescrito
|
| 557 |
+
# ✅ _super_aggressive_cleaning() - Limpieza SUPER agresiva de etiquetas
|
| 558 |
+
# ✅ _eliminate_all_technical_labels() - Eliminación total de "Prompt X (Level):"
|
| 559 |
+
# ✅ _is_valid_clean_prompt() - Validación que rechaza prompts con etiquetas
|
| 560 |
+
# ✅ _generate_clean_level_prompt() - Generación SIN etiquetas técnicas
|
| 561 |
+
# ✅ _extract_sections_multiple_strategies() - Extracción mejorada
|
| 562 |
+
# ✅ Todos los fallbacks generan prompts LIMPIOS sin etiquetas
|
| 563 |
+
# ✅ Logging detallado para verificar limpieza efectiva
|
| 564 |
+
# ✅ Garantía: Los prompts salen LIMPIOS sin "Prompt X (Level):"
|
|
|
|
|
|