# -*- coding: utf-8 -*- import os import traceback import zipfile import uuid import requests import gradio as gr os.environ["HF_HUB_DISABLE_TELEMETRY"] = "1" os.environ.setdefault("HF_SPACE_ID", "Cristobal299/mi_app") # ---------------------------------------------------------------------- # Optional external libraries # ---------------------------------------------------------------------- try: from groq import Groq except Exception: Groq = None try: import google.genai as genai except Exception: genai = None # ---------------------------------------------------------------------- # Tokens / Secrets # ---------------------------------------------------------------------- MONITOR_TOKEN = os.environ.get("MONITOR_TOKEN") # optional, set as secret UPLOAD_TOKEN = os.environ.get("UPLOAD_TOKEN") # token for automatic upload UPLOAD_URL = os.environ.get("UPLOAD_URL") # endpoint for automatic upload # ---------------------------------------------------------------------- # IA helper functions # ---------------------------------------------------------------------- def _call_groq(model: str, messages: list) -> str: """Low level call to Groq API.""" api_key = os.environ.get("GROQ_API_KEY") if not api_key: raise ValueError("GROQ_API_KEY not set") if Groq is None: raise ImportError("groq library not installed") client = Groq(api_key=api_key) response = client.chat.completions.create( model=model, messages=messages, temperature=0.7, ) return response.choices[0].message.content.strip() def _call_gemini(model: str, messages: list) -> str: """Low level call to Gemini API.""" api_key = os.environ.get("GEMINI_API_KEY") if not api_key: raise ValueError("GEMINI_API_KEY not set") if genai is None: raise ImportError("google-genai library not installed") genai.configure(api_key=api_key) gen_model = genai.GenerativeModel(model) prompt = "\n".join(messages) response = gen_model.generate_content( prompt, generation_config=genai.types.GenerationConfig(temperature=0.7), ) return response.text.strip() def _robust_ia_call(system_prompt: str, user_text: str) -> str: """Try Groq first, fallback to Gemini.""" messages = [ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_text}, ] try: return _call_groq("llama-3.3-70b-versatile", messages) except Exception as e: print("Groq error:", e) print(traceback.format_exc()) try: return _call_gemini("gemini-2.5-flash", messages) except Exception as e2: print("Gemini error:", e2) print(traceback.format_exc()) return "Error generating response. Check API keys and connectivity." def analyze_text(text: str) -> str: """Return editorial suggestions for the given text.""" if not text.strip(): return "Please provide text to analyze." system_prompt = ( "You are an intelligent editor. Analyze the text and suggest improvements " "for clarity, coherence, grammar and style. Return only the suggestions, one per line." ) return _robust_ia_call(system_prompt, text) def generate_html(request: str) -> str: """Generate HTML code based on a natural language request.""" if not request.strip(): return "Please describe the page you want." system_prompt = ( "You are a web developer assistant. Given a description of a web page, " "write the complete HTML code for a simple, responsive page that fulfills the request. " "Return only the raw HTML without any extra explanation." ) return _robust_ia_call(system_prompt, request) def get_monitor_info() -> str: """Return status of the monitor token.""" if MONITOR_TOKEN: return "Monitor token loaded correctly." return "Monitor token not configured. Add it as MONITOR_TOKEN env variable." # ---------------------------------------------------------------------- # Functions for handling uploaded HTML pages # ---------------------------------------------------------------------- def add_page(file_path: str, pages: list) -> tuple: """Add uploaded file path to the pages list and update dropdown.""" if not file_path: return pages, gr.Dropdown.update(choices=pages, value=None) # Gradio may pass a dict (e.g., {'name': '/tmp/...'}); extract the path safely if isinstance(file_path, dict): file_path = file_path.get("name") or file_path.get("path") if not file_path: return pages, gr.Dropdown.update(choices=pages, value=None) abs_path = os.path.abspath(file_path) new_pages = pages + [abs_path] return new_pages, gr.Dropdown.update(choices=new_pages, value=abs_path) def view_page(selected_page: str) -> str: """Read HTML file and return its content for display.""" if not selected_page: return "
No page selected.
" try: with open(selected_page, "r", encoding="utf-8") as f: return f.read() except Exception as e: print("Error reading page:", e) return f"Error loading page: {e}
" # ---------------------------------------------------------------------- # Functions for automatic project generation and upload # ---------------------------------------------------------------------- def _upload_file(file_path: str) -> str: """ Upload a file to a remote storage using UPLOAD_URL and UPLOAD_TOKEN. Returns the URL of the uploaded file or an error message. """ if not UPLOAD_URL or not UPLOAD_TOKEN: return "Upload not configured (UPLOAD_URL or UPLOAD_TOKEN missing)." try: with open(file_path, "rb") as f: files = {"file": (os.path.basename(file_path), f)} headers = {"Authorization": f"Bearer {UPLOAD_TOKEN}"} response = requests.post(UPLOAD_URL, files=files, headers=headers, timeout=30) if response.status_code == 200: # Assume the service returns JSON with a field 'url' data = response.json() return data.get("url", "Upload succeeded but no URL returned.") else: return f"Upload failed with status {response.status_code}: {response.text}" except Exception as e: print("Upload exception:", e) return f"Upload exception: {e}" def create_project(html_code: str, project_name: str) -> tuple: """Create a temporary folder with index.html, zip it and return zip path + preview.""" if not project_name.strip(): project_name = f"project-{uuid.uuid4().hex[:8]}" safe_name = "".join(c for c in project_name if c.isalnum() or c in "-_") base_dir = os.path.abspath(os.path.join("generated_projects", safe_name)) os.makedirs(base_dir, exist_ok=True) index_path = os.path.join(base_dir, "index.html") with open(index_path, "w", encoding="utf-8") as f: f.write(html_code) zip_path = f"{base_dir}.zip" if os.path.exists(zip_path): os.remove(zip_path) with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zipf: zipf.write(index_path, arcname="index.html") # Automatic upload (side effect) upload_result = _upload_file(zip_path) print("Automatic upload result:", upload_result) return zip_path, html_code # ---------------------------------------------------------------------- # Gradio Interface # ---------------------------------------------------------------------- with gr.Blocks() as demo: gr.Markdown("# AI Assistant Demo") btn = gr.Button("Ping") out = gr.Textbox() btn.click(lambda: "Pong", inputs=None, outputs=out) # ------------------------------------------------------------------ # Tabs # ------------------------------------------------------------------ with gr.Tabs(): # ------------------------------------------------------------------ # Tab 1: Editor + HTML Generator # ------------------------------------------------------------------ with gr.TabItem("Editor"): gr.Markdown("# Editor Inteligente") # --- Text analysis --- txt_input = gr.Textbox( label="Texto a analizar", placeholder="Escriba o pegue su contenido aqui...", lines=10, ) analyze_btn = gr.Button("Analizar") txt_output = gr.Code( label="Sugerencias del editor", language="markdown", interactive=False, ) analyze_btn.click(fn=analyze_text, inputs=txt_input, outputs=txt_output) # --- HTML generation --- gr.Markdown("## Generar codigo HTML") html_req = gr.Textbox( label="Descripcion de la pagina", placeholder="Ejemplo: una pagina de contacto con formulario", lines=4, ) gen_html_btn = gr.Button("Generar HTML") html_output = gr.Code( label="Codigo HTML generado", language="html", interactive=False, ) gen_html_btn.click(fn=generate_html, inputs=html_req, outputs=html_output) # ------------------------------------------------------------------ # Tab 2: Demo (upload & view HTML) # ------------------------------------------------------------------ with gr.TabItem("Demo"): gr.Markdown("## Subir y visualizar paginas HTML") file_input_demo = gr.File(label="Subir archivo HTML", file_count="single") dropdown_demo = gr.Dropdown(label="Paginas subidas", choices=[]) view_btn_demo = gr.Button("Ver pagina") html_output_demo = gr.HTML(label="Vista previa") file_input_demo.upload( fn=add_page, inputs=[file_input_demo, dropdown_demo], outputs=[dropdown_demo, dropdown_demo], ) view_btn_demo.click(fn=view_page, inputs=dropdown_demo, outputs=html_output_demo) # ------------------------------------------------------------------ # Tab 3: Monitor # ------------------------------------------------------------------ with gr.TabItem("Monitor"): gr.Markdown("# Monitor de la aplicacion") monitor_info = gr.Textbox( label="Estado del token", value=get_monitor_info(), interactive=False, ) refresh_btn = gr.Button("Refrescar") refresh_btn.click(fn=get_monitor_info, inputs=None, outputs=monitor_info) # ------------------------------------------------------------------ # Tab 4: Paginas (alternative upload view) # ------------------------------------------------------------------ with gr.TabItem("Paginas"): gr.Markdown("# Subir y visualizar paginas HTML") with gr.Row(): file_input_pages = gr.File( label="Archivo HTML a subir", type="filepath", file_count="single", ) upload_btn_pages = gr.Button("Subir pagina") pages_state = gr.State([]) page_dropdown = gr.Dropdown( choices=[], label="Paginas subidas", interactive=True, ) view_btn_pages = gr.Button("Ver pagina") html_view_pages = gr.HTML(label="Vista de la pagina") upload_btn_pages.click( fn=add_page, inputs=[file_input_pages, pages_state], outputs=[pages_state, page_dropdown], ) view_btn_pages.click( fn=view_page, inputs=page_dropdown, outputs=html_view_pages, ) # ------------------------------------------------------------------ # Tab 5: Generador Automatico de Proyecto # ------------------------------------------------------------------ with gr.TabItem("Generador"): gr.Markdown("# Generador Automatico de Proyecto") with gr.Row(): proj_name = gr.Textbox( label="Nombre del proyecto", placeholder="Ejemplo: mi-sitio", lines=1, ) html_code = gr.Textbox( label="Codigo HTML", placeholder="Escriba el HTML completo aqui...", lines=12, ) gen_btn = gr.Button("Crear proyecto") download_file = gr.File( label="Descargar proyecto (zip)", type="filepath", interactive=False, ) preview_html = gr.HTML(label="Vista previa del index.html") def wrapper_create(html, name): zip_path, html_content = create_project(html, name) return zip_path, html_content gen_btn.click( fn=wrapper_create, inputs=[html_code, proj_name], outputs=[download_file, preview_html], ) # ---------------------------------------------------------------------- # Launch # ---------------------------------------------------------------------- demo.queue() demo.launch(server_name="0.0.0.0", server_port=7860)