Spaces:
Runtime error
Runtime error
| """ | |
| LetXipu Beta SX - Gradio Interface v9.0 | |
| Dark/Light Theme · Glassmorphism · Chatbot-like Interface | |
| """ | |
| import gradio as gr | |
| import sys | |
| import os | |
| sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) | |
| from dotenv import load_dotenv | |
| load_dotenv(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".env")) | |
| from modules.search_tab import create_search_tab | |
| from modules.metadata_tab import create_metadata_tab | |
| from modules.pdf_tab import create_pdf_tab | |
| from modules.research_tab import create_research_tab | |
| from modules.sources_tab import create_sources_tab | |
| from modules.prompts_config_tab import create_prompts_config_tab | |
| from modules.config.agents_tab import create_agents_tab | |
| from modules.config.sources_config_tab import create_sources_config_tab | |
| from modules.config.ai_tab import create_ai_tab | |
| from modules.config.mining_tab import create_mining_tab | |
| from modules.history_tab import create_history_tab | |
| from backend.database.models import init_db | |
| init_db() | |
| VERSION = "9.0.0" | |
| # Note: Gradio loads external CSS and JS | |
| assets_dir = os.path.join(os.path.dirname(__file__), "assets") | |
| def create_app(): | |
| with gr.Blocks(title="LetXipu Beta SX") as app: | |
| # ─── Theme Toggle Button ─── | |
| gr.HTML(""" | |
| <button class="theme-toggle" id="theme-toggle" onclick="toggleTheme()" title="Cambiar a modo claro"> | |
| ☀️ | |
| </button> | |
| """) | |
| # ─── Header ─── | |
| gr.HTML(f""" | |
| <div class="header-banner"> | |
| <div style="display: flex; justify-content: space-between; align-items: center; position: relative; z-index: 2;"> | |
| <div> | |
| <h1>🔬 LetXipu Beta SX</h1> | |
| <p>Motor de Búsqueda Académica Independiente · Python Backend</p> | |
| </div> | |
| <div style="display: flex; gap: 8px; align-items: center;"> | |
| <div class="header-badge">v{VERSION}</div> | |
| <div class="header-badge" style="background: rgba(16, 185, 129, 0.2); border-color: rgba(16, 185, 129, 0.3); color: #10b981;">17 fuentes</div> | |
| <div class="header-badge" style="background: rgba(59, 130, 246, 0.2); border-color: rgba(59, 130, 246, 0.3); color: #3b82f6;">87 modelos</div> | |
| </div> | |
| </div> | |
| </div> | |
| """) | |
| # ─── Status ─── | |
| gr.HTML(""" | |
| <div class="status-banner status-connected"> | |
| <span class="status-dot connected"></span> | |
| <span>✅ Backend Python independiente activo — Pipeline completo con 12 fases</span> | |
| </div> | |
| """) | |
| # ─── Tabs ─── | |
| with gr.Tabs(elem_id="main-tabs") as tabs: | |
| with gr.TabItem("🔍 Búsqueda y Extracción", id="search"): | |
| create_search_tab() | |
| with gr.TabItem("🔬 Agente de Research", id="research"): | |
| create_research_tab() | |
| with gr.TabItem("📄 Análisis PDF Local", id="pdf"): | |
| create_pdf_tab() | |
| with gr.TabItem("⚙️ Configuración (Core)", id="config_core"): | |
| create_sources_tab() | |
| create_prompts_config_tab() | |
| with gr.TabItem("🛠️ Ajustes Avanzados", id="config_adv"): | |
| create_agents_tab() | |
| create_sources_config_tab() | |
| create_ai_tab() | |
| create_mining_tab() | |
| with gr.TabItem("🕰️ Historial", id="history"): | |
| create_history_tab() | |
| # ─── Control Buttons ─── | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| gr.Markdown("### 🛠️ Controles del Sistema") | |
| with gr.Column(scale=2): | |
| with gr.Row(): | |
| restart_btn = gr.Button("🔄 Reiniciar App", variant="secondary", size="sm") | |
| clear_cache_btn = gr.Button("🗑️ Limpiar Cache", variant="secondary", size="sm") | |
| clear_processes_btn = gr.Button("🧹 Matar Procesos", variant="secondary", size="sm") | |
| control_output = gr.Markdown("") | |
| def do_restart(): | |
| import subprocess | |
| import sys | |
| try: | |
| # Kill all python processes except current | |
| os.system("taskkill /F /IM python.exe /T 2>nul") | |
| # Restart the app | |
| subprocess.Popen([sys.executable, "app.py"], cwd=os.path.dirname(os.path.abspath(__file__))) | |
| return "🔄 Reiniciando app... La página se recargará en unos segundos." | |
| except Exception as e: | |
| return f"❌ Error al reiniciar: {str(e)}" | |
| def do_clear_cache(): | |
| import shutil | |
| cleared = [] | |
| # Clear Gradio cache | |
| gradio_cache = os.path.join(os.path.expanduser("~"), ".cache", "gradio") | |
| if os.path.exists(gradio_cache): | |
| shutil.rmtree(gradio_cache, ignore_errors=True) | |
| cleared.append("Gradio cache") | |
| # Clear Python __pycache__ | |
| for root, dirs, files in os.walk(os.path.dirname(os.path.abspath(__file__))): | |
| for d in dirs: | |
| if d == "__pycache__": | |
| shutil.rmtree(os.path.join(root, d), ignore_errors=True) | |
| cleared.append(root) | |
| # Clear prompts config cache | |
| prompts_cache = os.path.join(os.path.dirname(os.path.abspath(__file__)), "prompts_config.json") | |
| if os.path.exists(prompts_cache): | |
| os.remove(prompts_cache) | |
| cleared.append("prompts_config.json") | |
| return f"🗑️ Cache limpiado: {', '.join(cleared) if cleared else 'nada que limpiar'}" | |
| def do_clear_processes(): | |
| import subprocess | |
| try: | |
| # Kill orphaned python processes | |
| result = subprocess.run(["taskkill", "/F", "/IM", "python.exe", "/T"], | |
| capture_output=True, text=True, shell=True) | |
| return f"🧹 Procesos limpiados: {result.stdout.strip() if result.stdout else 'completado'}" | |
| except Exception as e: | |
| return f"❌ Error: {str(e)}" | |
| restart_btn.click(fn=do_restart, outputs=[control_output]) | |
| clear_cache_btn.click(fn=do_clear_cache, outputs=[control_output]) | |
| clear_processes_btn.click(fn=do_clear_processes, outputs=[control_output]) | |
| # ─── Footer ─── | |
| gr.HTML(f""" | |
| <div class="app-footer"> | |
| <span>LetXipu Beta SX v{VERSION} · Independiente · 2026</span> | |
| <span>Backend: Python + httpx · Frontend: Gradio · 17 fuentes · 87 modelos · Pipeline de 12 fases</span> | |
| </div> | |
| """) | |
| return app | |
| if __name__ == "__main__": | |
| from backend.database.models import SessionLocal, User | |
| import hashlib | |
| # Asegurar que existe al menos un usuario administrador | |
| def init_admin(): | |
| db = SessionLocal() | |
| admin = db.query(User).filter(User.username == "admin").first() | |
| if not admin: | |
| hashed = hashlib.sha256("admin123".encode()).hexdigest() | |
| db.add(User(username="admin", hashed_password=hashed, role="admin")) | |
| db.commit() | |
| db.close() | |
| def check_auth(username, password): | |
| db = SessionLocal() | |
| user = db.query(User).filter(User.username == username).first() | |
| db.close() | |
| if user and user.hashed_password == hashlib.sha256(password.encode()).hexdigest(): | |
| return True | |
| return False | |
| init_admin() | |
| app = create_app() | |
| with open("assets/styles.css", "r", encoding="utf-8") as f: | |
| custom_css = f.read() | |
| with open("assets/custom.js", "r", encoding="utf-8") as f: | |
| custom_js = f.read() | |
| app.launch( | |
| server_name="127.0.0.1", | |
| share=False, | |
| show_error=True, | |
| allowed_paths=[assets_dir], | |
| theme=gr.themes.Base( | |
| primary_hue="purple", | |
| secondary_hue="indigo", | |
| ).set( | |
| body_background_fill="#0a0a0c", | |
| body_background_fill_dark="#0a0a0c", | |
| block_background_fill="#111827", | |
| block_background_fill_dark="#111827", | |
| block_border_color="#374151", | |
| block_border_color_dark="#374151", | |
| block_label_text_color="#9ca3af", | |
| block_label_text_color_dark="#9ca3af", | |
| block_title_text_color="#ffffff", | |
| block_title_text_color_dark="#ffffff", | |
| input_background_fill="#1f2937", | |
| input_background_fill_dark="#1f2937", | |
| input_border_color="#374151", | |
| input_border_color_dark="#374151", | |
| button_primary_background_fill="#8b5cf6", | |
| button_primary_background_fill_dark="#8b5cf6", | |
| button_primary_text_color="#ffffff", | |
| button_secondary_background_fill="#1f2937", | |
| button_secondary_background_fill_dark="#1f2937", | |
| button_secondary_text_color="#9ca3af", | |
| checkbox_background_color="#1f2937", | |
| checkbox_background_color_dark="#1f2937", | |
| slider_color="#8b5cf6", | |
| slider_color_dark="#8b5cf6", | |
| ), | |
| css=custom_css, | |
| js=custom_js | |
| ) | |