"""
BuildAI - AI Engine v7 — ULTRA UPGRADE
New providers: Cerebras (ultra-fast), Gemini Flash (smart), DeepSeek (reasoning)
Pipeline: Cerebras → Gemini → Groq, with deep fallback chains
Higher quality output: v0/Lovable-level websites
"""
import os
import json
import asyncio
import httpx
from typing import AsyncGenerator
try:
from google import genai as genai_new
_GENAI_AVAILABLE = True
_GENAI_NEW = True
except ImportError:
try:
import google.generativeai as genai
_GENAI_AVAILABLE = True
_GENAI_NEW = False
except ImportError:
_GENAI_AVAILABLE = False
_GENAI_NEW = False
# ─────────────────────────────────────────────────────────────────
# REFERENCE FILE LOADER
# ─────────────────────────────────────────────────────────────────
_ref_cache = {}
def load_ref(filename: str) -> str:
global _ref_cache
if filename in _ref_cache:
return _ref_cache[filename]
# Search root, designs subfolder, and common app paths
paths = [
filename,
f"./{filename}",
f"/home/user/app/{filename}",
f"./designs/{filename}",
f"/home/user/app/designs/{filename}",
]
for path in paths:
try:
with open(path, "r", encoding="utf-8") as f:
content = f.read()
_ref_cache[filename] = content
print(f"[BuildAI] ✓ Loaded {filename} from {path} ({len(content)} chars)")
return content
except FileNotFoundError:
continue
print(f"[BuildAI] ⚠ Not found: {filename} (checked {len(paths)} paths)")
return ""
def get_references(prompt: str) -> tuple[str, str]:
p = prompt.lower()
# ── E-Commerce & Retail ──────────────────────────────────────────
if any(k in p for k in ['ecommerce','e-commerce','store','shop','product','cart','buy','sell',
'marketplace','clothing','fashion','sneaker','brand','retail','boutique']):
return load_ref("ref_ecommerce.html"), "E-COMMERCE"
# ── Restaurant & Food ────────────────────────────────────────────
elif any(k in p for k in ['restaurant','cafe','coffee','food','menu','kitchen','chef','dining',
'pizza','burger','sushi','bakery','bistro','bar','catering','eatery']):
return load_ref("ref_restaurant.html"), "RESTAURANT"
# ── Gym, Fitness & Wellness ──────────────────────────────────────
elif any(k in p for k in ['gym','fitness','workout','sport','yoga','spa','wellness','pilates',
'crossfit','training','health club','athletic','bodybuilding']):
return load_ref("ref_gym.html"), "FITNESS & WELLNESS"
# ── Music, Band & Artist ─────────────────────────────────────────
elif any(k in p for k in ['music','band','artist','concert','album','singer','rapper','dj',
'podcast','studio','sound','beats','producer','musician']):
return load_ref("ref_music.html"), "MUSIC & ARTIST"
# ── Photography & Visual Arts ────────────────────────────────────
elif any(k in p for k in ['photography','photographer','photo','gallery','wedding photo',
'portrait','shoot','lens','lightroom','visual artist']):
return load_ref("ref_photography.html"), "PHOTOGRAPHY"
# ── Travel & Hospitality ─────────────────────────────────────────
elif any(k in p for k in ['travel','tourism','hotel','resort','airbnb','hostel','vacation',
'trip','destination','adventure','tour','booking','flights']):
return load_ref("ref_travel.html"), "TRAVEL & HOSPITALITY"
# ── Crypto, Web3 & Fintech ───────────────────────────────────────
elif any(k in p for k in ['crypto','blockchain','defi','nft','web3','token','bitcoin','ethereum',
'fintech','trading','wallet','exchange','dao','solana']):
return load_ref("ref_crypto.html"), "CRYPTO & WEB3"
# ── Medical, Healthcare & Clinic ─────────────────────────────────
elif any(k in p for k in ['medical','clinic','hospital','doctor','healthcare','dentist','therapy',
'mental health','pharmacy','wellness clinic','telehealth','patient']):
return load_ref("ref_medical.html"), "HEALTHCARE"
# ── Education & E-Learning ───────────────────────────────────────
elif any(k in p for k in ['education','school','university','course','learning','teaching',
'elearning','tutoring','bootcamp','academy','lms','classroom']):
return load_ref("ref_education.html"), "EDUCATION"
# ── Real Estate & Property ───────────────────────────────────────
elif any(k in p for k in ['real estate','property','realty','housing','apartment','mortgage',
'home listing','interior design','architecture','construction']):
return load_ref("ref_real_estate.html"), "REAL ESTATE"
# ── Agency, Studio & Creative ────────────────────────────────────
elif any(k in p for k in ['agency','creative agency','design studio','marketing agency',
'advertising','branding','production house','creative studio']):
return load_ref("ref_agency.html"), "CREATIVE AGENCY"
# ── Startup & SaaS App ───────────────────────────────────────────
elif any(k in p for k in ['startup','app','saas app','mobile app','platform','tool','software',
'product launch','mvp','tech startup','b2b']):
return load_ref("ref_startup.html"), "STARTUP"
# ── Blog & Content ───────────────────────────────────────────────
elif any(k in p for k in ['blog','news','magazine','newsletter','content','editorial',
'publication','media','journal','articles','writing']):
return load_ref("ref_blog.html"), "BLOG & MEDIA"
# ── Portfolio & Personal ─────────────────────────────────────────
elif any(k in p for k in ['portfolio','designer','developer','cv','resume','case study',
'my work','showcase','freelance','personal site','personal brand']):
return load_ref("ref_portfolio.html"), "PORTFOLIO"
# ── Dashboard & Analytics ────────────────────────────────────────
elif any(k in p for k in ['dashboard','admin','analytics','crm','chart','kpi','metric',
'report','data','fintech dashboard','saas dashboard']):
return load_ref("ref_dashboard.html"), "DASHBOARD"
# ── Default: SaaS Landing ────────────────────────────────────────
else:
return load_ref("ref_saas_app.html") or load_ref("ref_landing.html"), "SAAS LANDING PAGE"
# ─────────────────────────────────────────────────────────────────
# SMART IMAGE KEYWORD EXTRACTOR
# ─────────────────────────────────────────────────────────────────
IMAGE_KEYWORDS = {
"cafe": ["coffee,cafe,cup", "barista,coffee,making", "cafe,interior,cozy", "coffee,latte,art"],
"coffee": ["coffee,espresso,cup", "coffee,beans,roasted", "barista,coffee,brewing", "coffee,cafe,table"],
"restaurant": ["restaurant,food,plating", "restaurant,interior,dining", "chef,cooking,kitchen", "food,gourmet,dish"],
"pizza": ["pizza,italian,fresh", "pizza,oven,baking", "pizza,toppings,cheese", "pizzeria,italian,food"],
"burger": ["burger,beef,fresh", "hamburger,restaurant,juicy", "burger,fries,meal", "fast,food,burger"],
"sushi": ["sushi,japanese,fresh", "sushi,roll,seafood", "sushi,chef,making", "japanese,food,restaurant"],
"bakery": ["bakery,bread,fresh", "pastry,croissant,baked", "cake,decoration,bakery", "bread,oven,baking"],
"tea": ["tea,cup,hot", "tea,leaves,herbal", "teapot,ceramic,drink", "tea,ceremony,japan"],
"bar": ["bar,cocktail,drinks", "bartender,mixing,cocktail", "whiskey,glass,bar", "nightlife,bar,drinks"],
"fashion": ["fashion,clothing,style", "model,outfit,trendy", "clothes,boutique,store", "fashion,designer,wear"],
"sneaker": ["sneakers,shoes,white", "athletic,shoes,sport", "sneaker,collection,display", "shoes,fashion,urban"],
"clothing": ["clothing,fashion,store", "outfit,stylish,model", "wardrobe,clothes,fashion", "apparel,shopping,retail"],
"jewelry": ["jewelry,gold,elegant", "necklace,diamond,luxury", "ring,jewelry,sparkle", "bracelet,fashion,accessories"],
"saas": ["technology,software,laptop", "office,team,collaboration", "startup,tech,modern", "dashboard,analytics,screen"],
"startup": ["startup,office,modern", "team,meeting,business", "entrepreneur,laptop,coffee", "tech,office,workspace"],
"agency": ["office,creative,team", "agency,design,creative", "meeting,business,professional", "workspace,modern,office"],
"tech": ["technology,innovation,laptop", "coding,developer,screen", "tech,startup,modern", "software,computer,code"],
"gym": ["gym,workout,fitness", "exercise,weights,strong", "fitness,training,athlete", "gym,equipment,sport"],
"yoga": ["yoga,meditation,peace", "yoga,pose,wellness", "mindfulness,yoga,calm", "yoga,studio,class"],
"spa": ["spa,relaxation,wellness", "massage,therapy,calm", "beauty,spa,treatment", "wellness,retreat,peaceful"],
"medical": ["doctor,medical,hospital", "healthcare,professional,clinic", "medical,team,care", "hospital,health,medicine"],
"real estate": ["house,modern,architecture", "interior,luxury,home", "property,real,estate", "living,room,design"],
"interior": ["interior,design,modern", "furniture,home,decor", "living,space,elegant", "home,decoration,style"],
"education": ["education,students,learning", "classroom,school,teaching", "university,campus,study", "books,learning,knowledge"],
"course": ["online,learning,laptop", "education,course,digital", "student,studying,desk", "elearning,digital,course"],
"travel": ["travel,destination,adventure", "landscape,beautiful,nature", "tourism,city,explore", "travel,photography,world"],
"hotel": ["hotel,luxury,room", "resort,pool,vacation", "hotel,lobby,elegant", "travel,accommodation,comfort"],
"portfolio": ["designer,creative,workspace", "creative,studio,modern", "photographer,camera,art", "design,portfolio,work"],
"photography": ["camera,photography,lens", "photo,shoot,studio", "photographer,nature,outdoor", "portrait,photography,light"],
"music": ["music,studio,recording", "guitar,musician,performance", "concert,music,stage", "headphones,music,listening"],
"gaming": ["gaming,computer,setup", "game,controller,neon", "esports,gaming,tournament", "game,developer,screen"],
"finance": ["finance,investment,chart", "money,banking,professional", "stock,market,trading", "wealth,management,business"],
"law": ["law,office,professional", "lawyer,justice,court", "legal,business,meeting", "attorney,desk,documents"],
"default_hero": ["modern,business,professional", "office,team,success", "technology,innovation,future", "startup,growth,success"],
"default_product": ["product,design,modern", "item,display,showcase", "product,photography,clean", "goods,retail,store"],
"default_person": ["professional,portrait,business", "person,team,corporate", "headshot,professional,smile", "team,member,office"],
}
def extract_image_keywords(prompt: str, website_type: str) -> dict:
p = prompt.lower()
keywords = {"hero": None, "section": None, "card": None, "person": None}
for topic, kw_list in IMAGE_KEYWORDS.items():
if topic in p:
if not keywords["hero"]:
keywords["hero"] = kw_list[0]
if not keywords["section"] and len(kw_list) > 1:
keywords["section"] = kw_list[1]
if not keywords["card"] and len(kw_list) > 2:
keywords["card"] = kw_list[2]
break
if not keywords["hero"]:
type_defaults = {
"E-COMMERCE": "product,fashion,store",
"RESTAURANT": "restaurant,food,dining",
"PORTFOLIO": "creative,designer,workspace",
"DASHBOARD": "office,technology,business",
"SAAS LANDING PAGE": "technology,startup,modern",
}
keywords["hero"] = type_defaults.get(website_type, "business,modern,professional")
if not keywords["section"]:
keywords["section"] = keywords["hero"]
if not keywords["card"]:
keywords["card"] = keywords["hero"]
keywords["person"] = "professional,portrait,person"
return keywords
def get_photo_instructions(prompt: str, website_type: str) -> str:
kw = extract_image_keywords(prompt, website_type)
h = kw["hero"].replace(",", "%20").replace(" ", "%20")
s = kw["section"].replace(",", "%20").replace(" ", "%20")
c = kw["card"].replace(",", "%20").replace(" ", "%20")
p = kw["person"].replace(",", "%20").replace(" ", "%20")
return f"""
━━━ REAL PHOTOS — USE UNSPLASH (FREE, NO API KEY, ALWAYS LOADS) ━━━
URL FORMAT: https://source.unsplash.com/WIDTHxHEIGHT/?keyword,keyword&sig=N
Hero background (full-width behind text):
style="background-image: url('https://source.unsplash.com/1600x900/?{h.replace(',','%2C')}&sig=1'); background-size: cover; background-position: center; background-repeat: no-repeat;"
Section/feature image:
Card/product image:
Person/team avatar:
Change seed=1 seed=2 seed=3 etc for each image to get variety.
STRICT RULES:
- Use class NOT className on all img tags
- Use style="background-image: url('...')" NOT style={{{{...}}}}
- 6 to 8 images MINIMUM in the site — more is better
- EVERY product card, blog card, testimonial MUST have an image
- Hero MUST have background-image photo
- NEVER use placeholder.com or loremflickr — gray boxes kill design
- ALWAYS add loading="lazy" decoding="async" alt="description"
"""
# ─────────────────────────────────────────────────────────────────
# PYTHON-LEVEL SCRIPT INJECTION
# These scripts are GUARANTEED to be injected by Python.
# Even if the AI forgets them, the site will still work.
# ─────────────────────────────────────────────────────────────────
_NAVIGATE_SCRIPT = """
"""
_INIT_SCRIPT = """
"""
def inject_required_scripts(html: str, pages: list) -> str:
"""
Python-level guarantee: inject navigate() and init scripts before
. Called on EVERY round output. Even if AI forgets these, the site works. """ if not html or "" not in html: return html to_inject = [] # 1. navigate() — only for multi-page sites if pages and len(pages) > 1 and "function navigate" not in html: to_inject.append(_NAVIGATE_SCRIPT) print(f"[BuildAI] Injected navigate() for pages: {pages}") # 2. AOS.init() — CRITICAL: without this all data-aos elements are INVISIBLE forever if "AOS.init" not in html: to_inject.append(_INIT_SCRIPT) print("[BuildAI] Injected AOS/GSAP init script (was missing from AI output)") elif "gsap.registerPlugin" not in html and "gsap" in html: to_inject.append("""""") if to_inject: injection = "\n".join(to_inject) html = html.replace("", injection + "\n", 1) return html CDN_STACK = """ ━━━ TECHNOLOGY STACK — VANILLA HTML + GSAP + AOS ━━━ PUT IN
: ━━━ DO NOT PUT ANY INIT SCRIPT — BuildAI injects it automatically ━━━ ━━━ VANILLA JS RULES ━━━ - Pure HTML5 + CSS + vanilla JavaScript — NO React, NO Babel, NO JSX - Use class NOT className; use for NOT htmlFor; inline style="..." NOT style={{}} - All interactivity via vanilla JS addEventListener or onclick="..." on buttons - GSAP and AOS will be initialized automatically — just use data-aos="fade-up" on elements - Add data-aos="fade-up" to EVERY feature card, section header, testimonial, and content div - Add data-aos-delay="0" "100" "200" for staggered grid items - Hero section: wrap content in