Cristobal299 commited on
Commit
8da132a
·
1 Parent(s): 1f97c2e

Primera version del clonador de webs

Browse files
Files changed (4) hide show
  1. Dockerfile +7 -0
  2. app.py +57 -0
  3. index.html +85 -0
  4. 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
+