fix: Fix YAML syntax errors and validator prompt formatting

- Fix YAML files with unquoted strings containing quotes
- Export singleton instances in ai/__init__.py
- Fix validator scoring prompt to use replace() instead of format()
  to avoid conflicts with JSON curly braces

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-28 21:13:58 +00:00
parent 11b0ba46fa
commit e32885afc5
19 changed files with 3440 additions and 4186 deletions

View File

@@ -0,0 +1,194 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Dashboard{% endblock %} - Social Media Automation</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#6366f1',
secondary: '#8b5cf6',
accent: '#d4a574',
dark: {
50: '#f8fafc',
100: '#f1f5f9',
200: '#e2e8f0',
300: '#cbd5e1',
400: '#94a3b8',
500: '#64748b',
600: '#475569',
700: '#334155',
800: '#1e293b',
900: '#0f172a',
950: '#020617'
}
},
fontFamily: {
sans: ['Inter', 'sans-serif']
}
}
}
}
</script>
<style>
body { font-family: 'Inter', sans-serif; }
.gradient-bg { background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%); }
.card { background: rgba(30, 41, 59, 0.8); backdrop-filter: blur(10px); border: 1px solid rgba(99, 102, 241, 0.1); }
.card:hover { border-color: rgba(99, 102, 241, 0.3); }
.btn-primary { background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%); }
.btn-primary:hover { background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%); transform: translateY(-1px); }
.btn-secondary { background: rgba(99, 102, 241, 0.1); border: 1px solid rgba(99, 102, 241, 0.3); }
.btn-secondary:hover { background: rgba(99, 102, 241, 0.2); }
.sidebar-link { transition: all 0.2s ease; }
.sidebar-link:hover { background: rgba(99, 102, 241, 0.1); transform: translateX(4px); }
.sidebar-link.active { background: rgba(99, 102, 241, 0.2); border-left: 3px solid #6366f1; }
.stat-card { transition: all 0.3s ease; }
.stat-card:hover { transform: translateY(-4px); box-shadow: 0 10px 40px rgba(99, 102, 241, 0.2); }
.glow { box-shadow: 0 0 20px rgba(99, 102, 241, 0.3); }
::-webkit-scrollbar { width: 8px; }
::-webkit-scrollbar-track { background: #1e293b; }
::-webkit-scrollbar-thumb { background: #475569; border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background: #6366f1; }
.animate-fade-in { animation: fadeIn 0.3s ease-out; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
</style>
{% block extra_head %}{% endblock %}
</head>
<body class="gradient-bg min-h-screen text-gray-100">
<div class="flex">
<!-- Sidebar -->
<aside class="w-64 min-h-screen bg-dark-900/50 backdrop-blur-xl border-r border-dark-700/50 fixed">
<div class="p-6">
<div class="flex items-center gap-3 mb-8">
<div class="w-10 h-10 rounded-xl bg-gradient-to-br from-primary to-secondary flex items-center justify-center">
<span class="text-xl">📱</span>
</div>
<div>
<h1 class="font-bold text-lg">Social Media</h1>
<p class="text-xs text-gray-500">Automation</p>
</div>
</div>
<nav class="space-y-1">
<a href="/" class="sidebar-link flex items-center gap-3 px-4 py-3 rounded-lg text-gray-300 hover:text-white {% if request.url.path == '/' %}active{% endif %}">
<span class="text-xl">🏠</span>
<span>Dashboard</span>
</a>
<a href="/compose" class="sidebar-link flex items-center gap-3 px-4 py-3 rounded-lg text-gray-300 hover:text-white {% if request.url.path == '/compose' %}active{% endif %}">
<span class="text-xl">✍️</span>
<span>Crear Post</span>
</a>
<a href="/posts" class="sidebar-link flex items-center gap-3 px-4 py-3 rounded-lg text-gray-300 hover:text-white {% if request.url.path == '/posts' %}active{% endif %}">
<span class="text-xl">📝</span>
<span>Posts</span>
</a>
<a href="/calendar" class="sidebar-link flex items-center gap-3 px-4 py-3 rounded-lg text-gray-300 hover:text-white {% if request.url.path == '/calendar' %}active{% endif %}">
<span class="text-xl">📅</span>
<span>Calendario</span>
</a>
<a href="/interactions" class="sidebar-link flex items-center gap-3 px-4 py-3 rounded-lg text-gray-300 hover:text-white {% if request.url.path == '/interactions' %}active{% endif %}">
<span class="text-xl">💬</span>
<span>Interacciones</span>
</a>
<div class="pt-4 mt-4 border-t border-dark-700/50">
<p class="px-4 text-xs text-gray-500 uppercase tracking-wider mb-2">Catálogo</p>
</div>
<a href="/products" class="sidebar-link flex items-center gap-3 px-4 py-3 rounded-lg text-gray-300 hover:text-white {% if request.url.path == '/products' %}active{% endif %}">
<span class="text-xl">📦</span>
<span>Productos</span>
</a>
<a href="/services" class="sidebar-link flex items-center gap-3 px-4 py-3 rounded-lg text-gray-300 hover:text-white {% if request.url.path == '/services' %}active{% endif %}">
<span class="text-xl">🛠️</span>
<span>Servicios</span>
</a>
<div class="pt-4 mt-4 border-t border-dark-700/50">
<p class="px-4 text-xs text-gray-500 uppercase tracking-wider mb-2">Analytics</p>
</div>
<a href="/analytics" class="sidebar-link flex items-center gap-3 px-4 py-3 rounded-lg text-gray-300 hover:text-white {% if request.url.path == '/analytics' %}active{% endif %}">
<span class="text-xl">📊</span>
<span>Analytics</span>
</a>
<a href="/leads" class="sidebar-link flex items-center gap-3 px-4 py-3 rounded-lg text-gray-300 hover:text-white {% if request.url.path == '/leads' %}active{% endif %}">
<span class="text-xl">🎯</span>
<span>Leads</span>
</a>
<div class="pt-4 mt-4 border-t border-dark-700/50">
<p class="px-4 text-xs text-gray-500 uppercase tracking-wider mb-2">Sistema</p>
</div>
<a href="/settings" class="sidebar-link flex items-center gap-3 px-4 py-3 rounded-lg text-gray-300 hover:text-white {% if request.url.path == '/settings' %}active{% endif %}">
<span class="text-xl">⚙️</span>
<span>Configuración</span>
</a>
</nav>
</div>
<!-- User Section -->
<div class="absolute bottom-0 left-0 right-0 p-4 border-t border-dark-700/50 bg-dark-900/50">
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<div class="w-8 h-8 rounded-full bg-gradient-to-br from-primary to-secondary flex items-center justify-center text-sm">
{{ user.username[0]|upper if user else '?' }}
</div>
<div class="text-sm">
<p class="font-medium">{{ user.username if user else 'Usuario' }}</p>
<p class="text-xs text-gray-500">Admin</p>
</div>
</div>
<a href="/logout" class="text-gray-400 hover:text-red-400 transition-colors" title="Cerrar sesión">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"></path>
</svg>
</a>
</div>
</div>
</aside>
<!-- Main Content -->
<main class="flex-1 ml-64 p-8">
{% block content %}{% endblock %}
</main>
</div>
<!-- Modal -->
<div id="modal" class="fixed inset-0 bg-black/50 backdrop-blur-sm hidden items-center justify-center z-50">
<div class="card rounded-2xl p-6 max-w-md w-full mx-4 animate-fade-in">
<div id="modal-content"></div>
<button onclick="closeModal()" class="mt-4 w-full btn-secondary px-4 py-2 rounded-lg">Cerrar</button>
</div>
</div>
<script>
function showModal(content, loading = false) {
const modal = document.getElementById('modal');
const modalContent = document.getElementById('modal-content');
modalContent.innerHTML = loading
? `<div class="flex items-center gap-3"><div class="animate-spin w-5 h-5 border-2 border-primary border-t-transparent rounded-full"></div><span>${content}</span></div>`
: content;
modal.classList.remove('hidden');
modal.classList.add('flex');
}
function closeModal() {
const modal = document.getElementById('modal');
modal.classList.add('hidden');
modal.classList.remove('flex');
}
// Close modal on outside click
document.getElementById('modal').addEventListener('click', function(e) {
if (e.target === this) closeModal();
});
</script>
{% block extra_scripts %}{% endblock %}
</body>
</html>