#!/usr/bin/env python3
"""
RealWebLearner: learned char n-gram intent model + compositional HTML/CSS/JS generator.
It learns web-development intent from many generated examples and then composes code.
It is designed for this tiny CPU workspace and integrates with unified_learning_ai.py.
Usage:
python real_web_learner.py --mode train --out outputs/real_web_learner
python real_web_learner.py --mode ask --out outputs/real_web_learner --prompt "create a responsive landing page with dark mode"
"""
from __future__ import annotations
import argparse
import json
import re
from pathlib import Path
from typing import List, Tuple
from real_python_learner import NBIntent
WEB_LABELS = [
"full_page", "landing_page", "portfolio", "navbar", "hero", "responsive_grid",
"card", "form_validation", "todo_app", "dark_mode", "modal", "tabs",
"accordion", "carousel", "css_animation", "dashboard", "fetch_api",
"counter", "canvas", "explain_web"
]
TEMPLATES = {
"full_page": ["complete web page", "full html css javascript page", "entire website", "single page app"],
"landing_page": ["landing page", "marketing page", "startup page", "product page", "saas landing"],
"portfolio": ["portfolio", "personal website", "developer portfolio", "resume website"],
"navbar": ["navbar", "navigation bar", "responsive menu", "mobile menu", "hamburger menu"],
"hero": ["hero section", "main banner", "header section", "call to action"],
"responsive_grid": ["responsive grid", "css grid layout", "gallery grid", "cards grid"],
"card": ["card component", "pricing card", "profile card", "glass card"],
"form_validation": ["form validation", "validate form", "contact form", "email validation"],
"todo_app": ["todo app", "task list", "add remove tasks", "local storage todos"],
"dark_mode": ["dark mode", "theme toggle", "light dark theme", "css variables theme"],
"modal": ["modal", "popup", "dialog", "overlay"],
"tabs": ["tabs", "tab component", "tabbed interface"],
"accordion": ["accordion", "faq accordion", "collapsible sections"],
"carousel": ["carousel", "slider", "image slider"],
"css_animation": ["css animation", "advanced css", "keyframes", "animated button", "loading spinner"],
"dashboard": ["dashboard", "admin dashboard", "analytics layout", "sidebar dashboard"],
"fetch_api": ["fetch api", "load data from api", "javascript fetch", "async await web"],
"counter": ["counter app", "increment decrement", "button counter"],
"canvas": ["canvas", "draw with canvas", "html5 canvas"],
"explain_web": ["explain html", "explain css", "explain javascript", "what is flexbox", "what is css grid"],
}
PREFIXES = [
"create", "build", "write", "make", "generate", "show me", "i need",
"dame", "crea", "haz", "construye", "escribe"
]
def build_training_examples(mult: int = 45) -> List[Tuple[str, str]]:
examples: List[Tuple[str, str]] = []
modifiers = [
"responsive", "modern", "animated", "accessible", "mobile first", "with css variables",
"with flexbox", "with css grid", "with javascript", "dark theme", "glassmorphism",
"clean", "advanced css", "semantic html", "sin librerias", "vanilla javascript"
]
for label, phrases in TEMPLATES.items():
for phrase in phrases:
for pref in PREFIXES:
examples.append((f"{pref} {phrase}", label))
for mod in modifiers[:8]:
examples.append((f"{pref} {mod} {phrase}", label))
examples.append((f"{pref} {phrase} {mod}", label))
return examples * mult
def html_shell(title: str, body: str, css: str, js: str = "") -> str:
return f'''
{title}
{body}
'''
BASE_CSS = ''' :root {
--bg: #0f172a;
--panel: rgba(255,255,255,.08);
--text: #e5e7eb;
--muted: #94a3b8;
--brand: #7c3aed;
--brand-2: #06b6d4;
--ring: rgba(124,58,237,.45);
--radius: 22px;
--shadow: 0 24px 70px rgba(0,0,0,.35);
}
* { box-sizing: border-box; }
body {
margin: 0;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, Segoe UI, sans-serif;
background: radial-gradient(circle at top left, rgba(124,58,237,.25), transparent 30%), var(--bg);
color: var(--text);
min-height: 100vh;
}
a { color: inherit; text-decoration: none; }
button, input, textarea { font: inherit; }
'''
def code_for(label: str, prompt: str) -> str:
p = prompt.lower()
if label in {"full_page", "landing_page", "portfolio"}:
title = "Portfolio" if label == "portfolio" or "portfolio" in p else "Nova Landing"
body = '''
Modern Web Experience
Build beautiful interfaces with HTML, CSS and JavaScript.
Responsive layout, animated gradient, glass cards, semantic HTML and a tiny vanilla JS theme switcher.
CSS Grid + Variables
Fast, accessible, and easy to customize.
Responsive
Uses grid, clamp and media queries.
Animated
Subtle keyframes create depth.
Vanilla JS
No frameworks required.
'''
css = BASE_CSS + '''
.nav { display:flex; align-items:center; justify-content:space-between; gap:1rem; padding:1.2rem clamp(1rem,4vw,4rem); position:sticky; top:0; backdrop-filter: blur(16px); background:rgba(15,23,42,.72); z-index:10; }
.logo { font-weight:900; letter-spacing:.04em; }
nav { display:flex; gap:1rem; color:var(--muted); }
.ghost { border:1px solid rgba(255,255,255,.16); background:transparent; color:var(--text); border-radius:999px; padding:.65rem 1rem; cursor:pointer; }
.hero { min-height:76vh; display:grid; grid-template-columns:1.1fr .9fr; align-items:center; gap:clamp(2rem,6vw,6rem); padding:clamp(2rem,6vw,6rem); }
.eyebrow { color:var(--brand-2); text-transform:uppercase; letter-spacing:.18em; font-size:.78rem; font-weight:800; }
h1 { font-size:clamp(2.4rem,7vw,6rem); line-height:.95; margin:.2em 0; }
.lead { color:var(--muted); font-size:clamp(1rem,2vw,1.25rem); max-width:65ch; }
.actions { display:flex; flex-wrap:wrap; gap:1rem; margin-top:2rem; }
.btn { background:linear-gradient(135deg,var(--brand),var(--brand-2)); padding:.9rem 1.2rem; border-radius:999px; font-weight:800; box-shadow:0 14px 35px var(--ring); }
.btn.secondary { background:rgba(255,255,255,.08); box-shadow:none; }
.orb-card { position:relative; overflow:hidden; border:1px solid rgba(255,255,255,.14); background:var(--panel); border-radius:var(--radius); padding:2rem; box-shadow:var(--shadow); min-height:360px; backdrop-filter:blur(20px); }
.orb { width:220px; height:220px; border-radius:50%; background:linear-gradient(135deg,var(--brand),var(--brand-2)); filter:blur(2px); animation:float 5s ease-in-out infinite; }
.grid { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:1rem; padding:clamp(1rem,4vw,4rem); }
.card { border:1px solid rgba(255,255,255,.12); background:var(--panel); border-radius:var(--radius); padding:1.4rem; transition:transform .25s ease, border-color .25s ease; }
.card:hover { transform:translateY(-6px); border-color:var(--brand-2); }
body.light { --bg:#f8fafc; --panel:rgba(15,23,42,.06); --text:#0f172a; --muted:#475569; }
body.light .nav { background:rgba(248,250,252,.76); }
@keyframes float { 0%,100%{ transform:translateY(0) rotate(0deg);} 50%{ transform:translateY(-18px) rotate(8deg);} }
@media (max-width: 800px) { .hero { grid-template-columns:1fr; } .grid { grid-template-columns:1fr; } nav { display:none; } }
'''
js = ''' const btn = document.querySelector('#themeBtn');
btn.addEventListener('click', () => document.body.classList.toggle('light'));
'''
return "```html\n" + html_shell(title, body, css, js) + "\n```"
if label == "navbar":
return '''```html
```'''
if label == "responsive_grid":
return '''```html
```'''
if label == "form_validation":
return '''```html
```'''
if label == "todo_app":
return '''```html
```'''
if label == "modal":
return '''```html
Hello
This is an accessible modal pattern.
```'''
if label == "tabs":
return '''```html
```'''
if label == "accordion":
return '''```html
What is HTML?
Semantic structure for web content.
What is CSS?
Presentation, layout and animation.
```'''
if label == "css_animation":
return '''```html
```'''
if label == "fetch_api":
return '''```html
```'''
if label == "counter":
return '''```html
0
```'''
if label == "canvas":
return '''```html
```'''
if label == "explain_web":
return "HTML gives semantic structure, CSS controls layout/visual design, and JavaScript adds behavior. Advanced CSS includes Grid, Flexbox, custom properties, clamp(), container/media queries, transforms, transitions, keyframes, and accessibility-aware responsive design."
# default component/card/dashboard/carousel fallback
return '''```html
Modern Card
Reusable component with advanced CSS variables and hover motion.
```'''
def train(out: Path):
out.mkdir(parents=True, exist_ok=True)
examples = build_training_examples(mult=35)
model = NBIntent(); model.fit(examples); model.save(out / 'web_intent_nb.json')
report = {"examples": len(examples), "features": len(model.vocab), "labels": WEB_LABELS, "type": "char_ngram_web_intent_plus_compositional_generator"}
(out / 'report.json').write_text(json.dumps(report, indent=2), encoding='utf-8')
(out / 'training_examples_sample.json').write_text(json.dumps(examples[:2000], indent=2, ensure_ascii=False), encoding='utf-8')
print(json.dumps(report, indent=2))
def ask(out: Path, prompt: str):
model = NBIntent.load(out / 'web_intent_nb.json')
probs = model.predict_proba(prompt)
label = probs[0][0]
print('## Learned web reasoning')
print('- Read request with character n-grams and web-development fragments.')
print('- Top intents: ' + ', '.join(f'{l}={p:.2f}' for l,p in probs[:4]))
print(f'- Selected intent: {label}')
print('\n## Answer')
print(code_for(label, prompt))
def main():
ap = argparse.ArgumentParser()
ap.add_argument('--mode', choices=['train','ask'], default='ask')
ap.add_argument('--out', default='outputs/real_web_learner')
ap.add_argument('--prompt', default='create a responsive landing page with dark mode')
args = ap.parse_args(); out = Path(args.out)
if args.mode == 'train': train(out)
else: ask(out, args.prompt)
if __name__ == '__main__':
main()