Spaces:
Running
Running
| import gradio as gr | |
| import subprocess | |
| import os | |
| import sys | |
| from pathlib import Path | |
| # Paths (Relative to Space root) | |
| # In HF Spaces, we'll upload the Paper-KG-Pipeline folder | |
| PIPELINE_SCRIPT = Path("Paper-KG-Pipeline/scripts/idea2story_pipeline.py") | |
| OUTPUT_RESULT = Path("Paper-KG-Pipeline/output/pipeline_result.json") | |
| def run_pipeline(idea, progress=gr.Progress()): | |
| """ | |
| Runs the Idea2Story pipeline script as a subprocess and streams output. | |
| """ | |
| logs = [] | |
| try: | |
| if not idea.strip(): | |
| logs.append("⚠️ Por favor ingresa una idea.") | |
| yield "\n".join(logs), None | |
| return | |
| # Locate Python executable | |
| # In HF Spaces, we use the system python | |
| python_exec = Path(sys.executable) | |
| script_path = PIPELINE_SCRIPT.absolute() | |
| if not script_path.exists(): | |
| logs.append(f"❌ No se encontró el script en: {script_path}") | |
| yield "\n".join(logs), None | |
| return | |
| logs.append(f"🚀 Iniciando pipeline...") | |
| logs.append(f"📂 Carpeta actual: {os.getcwd()}") | |
| logs.append(f"📜 Script: {script_path}") | |
| yield "\n".join(logs), None | |
| command = [ | |
| str(python_exec), | |
| str(script_path), | |
| idea | |
| ] | |
| # Ensure UTF-8 environment limits encoding errors | |
| env = os.environ.copy() | |
| env["PYTHONIOENCODING"] = "utf-8" | |
| # HF specific: add to pythonpath | |
| env["PYTHONPATH"] = os.path.join(os.getcwd(), "Paper-KG-Pipeline", "src") | |
| # --- CONFIGURACIÓN AUTOMÁTICA PARA DEPLOY --- | |
| # 1. Inyectar configuración de Gemini | |
| env["LLM_PROVIDER"] = "openai_compatible_chat" | |
| env["LLM_BASE_URL"] = "https://generativelanguage.googleapis.com/v1beta/openai/" | |
| env["LLM_MODEL"] = "gemini-2.0-flash" | |
| env["EMBEDDING_API_URL"] = "https://generativelanguage.googleapis.com/v1beta/openai/embeddings" | |
| env["EMBEDDING_MODEL"] = "gemini-embedding-001" | |
| # 2. Configurar reintentos para el Preflight (evitar fallo rápido) | |
| env["I2P_PREFLIGHT_LLM_RETRIES"] = "10" | |
| env["I2P_PREFLIGHT_EMB_RETRIES"] = "10" | |
| # 3. Mapear clave API | |
| if "GEMINI_API_KEY" in env: | |
| env["LLM_API_KEY"] = env["GEMINI_API_KEY"] | |
| env["EMBEDDING_API_KEY"] = env["GEMINI_API_KEY"] | |
| logs.append("✅ GEMINI_API_KEY encontrada e inyectada.") | |
| elif "LLM_API_KEY" not in env: | |
| logs.append("⚠️ ADVERTENCIA: No se encontró GEMINI_API_KEY.") | |
| logs.append(f"🔍 DEBUG: LLM_MODEL={env.get('LLM_MODEL')}") | |
| # 4. (HOTFIX) Parchear common.py en el servidor para aumentar reintentos globales | |
| # Esto evita tener que subir carpetas enteras de nuevo. | |
| try: | |
| common_py = Path("Paper-KG-Pipeline/src/idea2paper/infra/llm_providers/common.py") | |
| if common_py.exists(): | |
| with open(common_py, "r", encoding="utf-8") as f: | |
| content = f.read() | |
| # Si tiene pocos reintentos, lo subimos a 15 y backoff a 4 | |
| if "total=8" not in content and "total=15" not in content: | |
| logs.append("🔧 Parcheando common.py para mejorar resistencia a Rate Limits...") | |
| # Reemplazamos configuraciones antiguas o por defecto | |
| import re | |
| content = re.sub(r"total=\d+", "total=15", content) | |
| content = re.sub(r"backoff_factor=\d+", "backoff_factor=4", content) | |
| content = re.sub(r"status_forcelist=\[.*?\]", "status_forcelist=[429, 500, 502, 503, 504]", content) | |
| with open(common_py, "w", encoding="utf-8") as f: | |
| f.write(content) | |
| logs.append("✅ common.py parcheado con éxito.") | |
| except Exception as e: | |
| logs.append(f"⚠️ No se pudo parchear common.py: {e}") | |
| # -------------------------------------------- | |
| process = subprocess.Popen( | |
| command, | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.STDOUT, | |
| text=True, | |
| encoding='utf-8', | |
| errors='replace', | |
| env=env, | |
| cwd=os.getcwd() | |
| ) | |
| # Stream output | |
| for line in iter(process.stdout.readline, ''): | |
| logs.append(line.rstrip()) | |
| if len(logs) % 1 == 0: | |
| yield "\n".join(logs), None | |
| process.wait() | |
| if process.returncode == 0: | |
| logs.append("\n✅ Pipeline completado con éxito!") | |
| # Load result | |
| if OUTPUT_RESULT.exists(): | |
| try: | |
| import json | |
| with open(OUTPUT_RESULT, "r", encoding="utf-8") as f: | |
| result_data = json.load(f) | |
| yield "\n".join(logs), result_data | |
| except Exception as e: | |
| logs.append(f"\n⚠️ Error leyendo resultado: {e}") | |
| yield "\n".join(logs), None | |
| else: | |
| logs.append("\n⚠️ Archivo de resultado no encontrado.") | |
| yield "\n".join(logs), None | |
| else: | |
| logs.append(f"\n❌ Pipeline falló con código {process.returncode}") | |
| yield "\n".join(logs), None | |
| except Exception as e: | |
| import traceback | |
| logs.append(f"\n❌ Error GUI: {str(e)}") | |
| logs.append(traceback.format_exc()) | |
| yield "\n".join(logs), None | |
| # GUI Layout | |
| with gr.Blocks(title="Conversor de ideas en papers") as demo: | |
| gr.Markdown("# 🚀 Conversor de ideas en papers") | |
| gr.Markdown("Transforme su idea de investigación en una historia/documento estructurado utilizando gráficos de conocimiento y LLM.") | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| idea_input = gr.Textbox( | |
| label="Tu idea a investigar", | |
| placeholder="ej: Razonamiento automatizado en grandes modelos de lenguaje...", | |
| lines=3 | |
| ) | |
| run_btn = gr.Button("Generar Historia", variant="primary") | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| logs_output = gr.Textbox( | |
| label="Registros de Ejecución", | |
| interactive=False, | |
| lines=20, | |
| autoscroll=True | |
| ) | |
| with gr.Column(scale=1): | |
| result_output = gr.JSON( | |
| label="Resultado Generado", | |
| ) | |
| run_btn.click( | |
| fn=run_pipeline, | |
| inputs=[idea_input], | |
| outputs=[logs_output, result_output] | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() | |