""" 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(theme, css, js): with gr.Blocks(title="LetXipu Beta SX", theme=theme, css=css, js=js) as app: # ─── Theme Toggle Button ─── gr.HTML(""" """) # ─── Header ─── gr.HTML(f"""
""") # ─── Status ─── gr.HTML(""" """) # ─── 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""" """) 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() 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() 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", ) app = create_app(theme, custom_css, custom_js) app.launch( server_name="0.0.0.0", share=False, show_error=True, show_api=False, allowed_paths=[assets_dir] )