| |
| 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") |
|
|
| |
| |
| |
| try: |
| from groq import Groq |
| except Exception: |
| Groq = None |
|
|
| try: |
| import google.genai as genai |
| except Exception: |
| genai = None |
|
|
| |
| |
| |
| MONITOR_TOKEN = os.environ.get("MONITOR_TOKEN") |
| UPLOAD_TOKEN = os.environ.get("UPLOAD_TOKEN") |
| UPLOAD_URL = os.environ.get("UPLOAD_URL") |
|
|
| |
| |
| |
| 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." |
|
|
|
|
| |
| |
| |
| 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) |
| |
| 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 "<p>No page selected.</p>" |
| 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"<p>Error loading page: {e}</p>" |
|
|
|
|
| |
| |
| |
| 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: |
| |
| 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") |
|
|
| |
| upload_result = _upload_file(zip_path) |
| print("Automatic upload result:", upload_result) |
|
|
| return zip_path, html_code |
|
|
|
|
| |
| |
| |
| 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) |
|
|
| |
| |
| |
| with gr.Tabs(): |
| |
| |
| |
| with gr.TabItem("Editor"): |
| gr.Markdown("# Editor Inteligente") |
| |
| 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) |
|
|
| |
| 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) |
|
|
| |
| |
| |
| 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) |
|
|
| |
| |
| |
| 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) |
|
|
| |
| |
| |
| 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, |
| ) |
|
|
| |
| |
| |
| 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], |
| ) |
|
|
| |
| |
| |
| demo.queue() |
| demo.launch(server_name="0.0.0.0", server_port=7860) |