Spaces:
Running
Running
Commit ·
8da132a
1
Parent(s): 1f97c2e
Primera version del clonador de webs
Browse files- Dockerfile +7 -0
- app.py +57 -0
- index.html +85 -0
- requirements.txt +6 -0
Dockerfile
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM python:3.10
|
| 2 |
+
WORKDIR /code
|
| 3 |
+
COPY ./requirements.txt /code/requirements.txt
|
| 4 |
+
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
| 5 |
+
COPY . .
|
| 6 |
+
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
|
| 7 |
+
|
app.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os, requests, re
|
| 2 |
+
from fastapi import FastAPI
|
| 3 |
+
from fastapi.responses import HTMLResponse, JSONResponse
|
| 4 |
+
from pydantic import BaseModel
|
| 5 |
+
from bs4 import BeautifulSoup
|
| 6 |
+
|
| 7 |
+
app = FastAPI()
|
| 8 |
+
GROQ_API_KEY = os.getenv("GROQ_API_KEY")
|
| 9 |
+
|
| 10 |
+
class GenerateRequest(BaseModel):
|
| 11 |
+
url: str
|
| 12 |
+
nuevo_nombre: str
|
| 13 |
+
color_primario: str
|
| 14 |
+
|
| 15 |
+
@app.post("/api/generate")
|
| 16 |
+
async def generate_site(data: GenerateRequest):
|
| 17 |
+
try:
|
| 18 |
+
# 1. Scrapeamos la web original para entender qué hacen
|
| 19 |
+
r = requests.get(data.url, headers={'User-Agent': 'Mozilla/5.0'}, timeout=10)
|
| 20 |
+
soup = BeautifulSoup(r.text, 'html.parser')
|
| 21 |
+
texto_original = soup.get_text()[:3000] # Cogemos lo esencial
|
| 22 |
+
|
| 23 |
+
# 2. La IA actúa como Diseñador Web Pro
|
| 24 |
+
prompt = (
|
| 25 |
+
f"Actúa como un Desarrollador Frontend experto en Tailwind CSS. \n"
|
| 26 |
+
f"Debes crear una LANDING PAGE moderna y elegante basada en este negocio: {texto_original}. \n\n"
|
| 27 |
+
f"REGLAS DEL DISEÑO:\n"
|
| 28 |
+
f"1. Nombre del negocio: {data.nuevo_nombre}.\n"
|
| 29 |
+
f"2. Color principal: {data.color_primario} (usa clases de Tailwind como 'bg-{data.color_primario}-600').\n"
|
| 30 |
+
f"3. Estilo: Minimalista, con sombras (shadow-xl) y bordes redondeados (rounded-3xl).\n"
|
| 31 |
+
f"4. Estructura: Hero con imagen, sección de Servicios, sección de 'Sobre nosotros' y un Formulario de contacto.\n"
|
| 32 |
+
f"5. Fotos: Usa fotos de alta calidad de Unsplash (ej: https://images.unsplash.com/photo-XXXXX?auto=format&fit=crop&w=800).\n\n"
|
| 33 |
+
f"IMPORTANTE: Devuelve SOLO el código HTML con Tailwind (usando el CDN de Tailwind). No des explicaciones."
|
| 34 |
+
)
|
| 35 |
+
|
| 36 |
+
payload = {
|
| 37 |
+
"model": "llama-3.3-70b-versatile",
|
| 38 |
+
"messages": [{"role": "system", "content": "Eres un generador de código HTML/Tailwind."},
|
| 39 |
+
{"role": "user", "content": prompt}],
|
| 40 |
+
"max_tokens": 4000
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
headers = {"Authorization": f"Bearer {GROQ_API_KEY}"}
|
| 44 |
+
r_ia = requests.post("https://api.groq.com/openai/v1/chat/completions", json=payload, headers=headers)
|
| 45 |
+
html_generado = r_ia.json()["choices"][0]["message"]["content"]
|
| 46 |
+
|
| 47 |
+
# Limpiar posibles etiquetas de markdown que ponga la IA
|
| 48 |
+
html_final = re.sub(r'```html|```', '', html_generado).strip()
|
| 49 |
+
|
| 50 |
+
return {"status": "success", "html": html_final}
|
| 51 |
+
except Exception as e:
|
| 52 |
+
return JSONResponse({"status": "error", "detail": str(e)}, status_code=400)
|
| 53 |
+
|
| 54 |
+
@app.get("/", response_class=HTMLResponse)
|
| 55 |
+
async def index():
|
| 56 |
+
with open("index.html", "r", encoding="utf-8") as f: return f.read()
|
| 57 |
+
|
index.html
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="es">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>IA Web Re-Designer</title>
|
| 7 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
+
</head>
|
| 9 |
+
<body class="bg-slate-900 text-white min-h-screen p-4 md:p-10">
|
| 10 |
+
|
| 11 |
+
<div class="max-w-6xl mx-auto">
|
| 12 |
+
<div class="text-center mb-10">
|
| 13 |
+
<h1 class="text-4xl font-bold mb-2">IA Web Re-Designer 🚀</h1>
|
| 14 |
+
<p class="text-slate-400">Clona y mejora cualquier web en segundos</p>
|
| 15 |
+
</div>
|
| 16 |
+
|
| 17 |
+
<div class="grid md:grid-cols-3 gap-8">
|
| 18 |
+
<div class="bg-slate-800 p-6 rounded-3xl border border-slate-700 h-fit">
|
| 19 |
+
<div class="space-y-4">
|
| 20 |
+
<div>
|
| 21 |
+
<label class="block text-xs font-bold text-slate-500 uppercase mb-2">URL Original</label>
|
| 22 |
+
<input type="text" id="url" placeholder="https://web-vieja.com" class="w-full p-3 rounded-xl bg-slate-900 border border-slate-600 outline-none focus:border-blue-500">
|
| 23 |
+
</div>
|
| 24 |
+
<div>
|
| 25 |
+
<label class="block text-xs font-bold text-slate-500 uppercase mb-2">Nuevo Nombre</label>
|
| 26 |
+
<input type="text" id="nombre" placeholder="Mi Nueva Clínica" class="w-full p-3 rounded-xl bg-slate-900 border border-slate-600 outline-none focus:border-blue-500">
|
| 27 |
+
</div>
|
| 28 |
+
<div>
|
| 29 |
+
<label class="block text-xs font-bold text-slate-500 uppercase mb-2">Color (Tailwind: blue, red, emerald...)</label>
|
| 30 |
+
<input type="text" id="color" placeholder="blue" class="w-full p-3 rounded-xl bg-slate-900 border border-slate-600 outline-none focus:border-blue-500">
|
| 31 |
+
</div>
|
| 32 |
+
<button onclick="generarWeb()" id="btn" class="w-full bg-blue-600 p-4 rounded-2xl font-bold hover:bg-blue-500 transition-all shadow-lg shadow-blue-900/20">
|
| 33 |
+
REDISEÑAR AHORA
|
| 34 |
+
</button>
|
| 35 |
+
</div>
|
| 36 |
+
</div>
|
| 37 |
+
|
| 38 |
+
<div class="md:col-span-2">
|
| 39 |
+
<div class="bg-white rounded-3xl overflow-hidden shadow-2xl h-[600px] border-4 border-slate-800">
|
| 40 |
+
<iframe id="preview" class="w-full h-full" srcdoc="<div style='display:flex; height:100%; align-items:center; justify-content:center; font-family:sans-serif; color:#94a3b8'>La nueva web aparecerá aquí...</div>"></iframe>
|
| 41 |
+
</div>
|
| 42 |
+
</div>
|
| 43 |
+
</div>
|
| 44 |
+
</div>
|
| 45 |
+
|
| 46 |
+
<script>
|
| 47 |
+
async function generarWeb() {
|
| 48 |
+
const btn = document.getElementById('btn');
|
| 49 |
+
const preview = document.getElementById('preview');
|
| 50 |
+
|
| 51 |
+
const data = {
|
| 52 |
+
url: document.getElementById('url').value,
|
| 53 |
+
nuevo_nombre: document.getElementById('nombre').value,
|
| 54 |
+
color_primario: document.getElementById('color').value
|
| 55 |
+
};
|
| 56 |
+
|
| 57 |
+
if(!data.url || !data.nuevo_nombre) return alert("Rellena los datos");
|
| 58 |
+
|
| 59 |
+
btn.innerHTML = "⌛ Diseñando con IA...";
|
| 60 |
+
btn.disabled = true;
|
| 61 |
+
|
| 62 |
+
try {
|
| 63 |
+
const res = await fetch('/api/generate', {
|
| 64 |
+
method: 'POST',
|
| 65 |
+
headers: {'Content-Type': 'application/json'},
|
| 66 |
+
body: JSON.stringify(data)
|
| 67 |
+
});
|
| 68 |
+
const result = await res.json();
|
| 69 |
+
|
| 70 |
+
if(result.status === "success") {
|
| 71 |
+
preview.srcdoc = result.html;
|
| 72 |
+
} else {
|
| 73 |
+
alert("Error en la generación");
|
| 74 |
+
}
|
| 75 |
+
} catch(e) {
|
| 76 |
+
alert("Error de conexión");
|
| 77 |
+
} finally {
|
| 78 |
+
btn.innerHTML = "REDISEÑAR AHORA";
|
| 79 |
+
btn.disabled = false;
|
| 80 |
+
}
|
| 81 |
+
}
|
| 82 |
+
</script>
|
| 83 |
+
</body>
|
| 84 |
+
</html>
|
| 85 |
+
|
requirements.txt
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
fastapi
|
| 2 |
+
uvicorn
|
| 3 |
+
requests
|
| 4 |
+
beautifulsoup4
|
| 5 |
+
pydantic
|
| 6 |
+
|