Spaces:
Running
Running
dynamic files
Browse files
app.py
CHANGED
|
@@ -428,6 +428,45 @@ Follow the same file output format and project structure as specified:
|
|
| 428 |
Use search results to apply current best practices in accessibility, semantics, responsive meta tags, and performance (preconnect, responsive images).
|
| 429 |
"""
|
| 430 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 431 |
GENERIC_SYSTEM_PROMPT_WITH_SEARCH = """You are an expert {language} developer. You have access to real-time web search. When needed, use web search to find the latest information, best practices, or specific technologies for {language}.
|
| 432 |
|
| 433 |
Write clean, idiomatic, and runnable {language} code for the user's request. If possible, include comments and best practices. Output ONLY the code inside a ``` code block, and do not include any explanations or extra text. If the user provides a file or other context, use it as a reference. If the code is for a script or app, make it as self-contained as possible. Do NOT add the language name at the top of the code output."""
|
|
@@ -1243,6 +1282,73 @@ def parse_multipage_html_output(text: str) -> Dict[str, str]:
|
|
| 1243 |
files[name] = content
|
| 1244 |
return files
|
| 1245 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1246 |
def inline_multipage_into_single_preview(files: Dict[str, str]) -> str:
|
| 1247 |
"""Inline local CSS/JS referenced by index.html for preview inside a data: iframe.
|
| 1248 |
|
|
@@ -3286,8 +3392,8 @@ def generation_code(query: Optional[str], vlm_image: Optional[gr.Image], gen_ima
|
|
| 3286 |
else:
|
| 3287 |
# Use language-specific prompt
|
| 3288 |
if language == "html":
|
| 3289 |
-
#
|
| 3290 |
-
system_prompt =
|
| 3291 |
elif language == "transformers.js":
|
| 3292 |
system_prompt = TRANSFORMERS_JS_SYSTEM_PROMPT_WITH_SEARCH if enable_search else TRANSFORMERS_JS_SYSTEM_PROMPT
|
| 3293 |
elif language == "svelte":
|
|
@@ -3358,6 +3464,7 @@ This will help me create a better design for you."""
|
|
| 3358 |
preview_val = None
|
| 3359 |
if language == "html":
|
| 3360 |
_mp = parse_multipage_html_output(clean_code)
|
|
|
|
| 3361 |
preview_val = send_to_sandbox(inline_multipage_into_single_preview(_mp)) if _mp.get('index.html') else send_to_sandbox(clean_code)
|
| 3362 |
elif language == "python" and is_streamlit_code(clean_code):
|
| 3363 |
preview_val = send_streamlit_to_stlite(clean_code)
|
|
@@ -3588,6 +3695,7 @@ This will help me create a better design for you."""
|
|
| 3588 |
preview_val = None
|
| 3589 |
if language == "html":
|
| 3590 |
_mpf2 = parse_multipage_html_output(final_content)
|
|
|
|
| 3591 |
preview_val = send_to_sandbox(inline_multipage_into_single_preview(_mpf2)) if _mpf2.get('index.html') else send_to_sandbox(final_content)
|
| 3592 |
elif language == "python" and is_streamlit_code(final_content):
|
| 3593 |
preview_val = send_streamlit_to_stlite(final_content)
|
|
@@ -3655,6 +3763,7 @@ This will help me create a better design for you."""
|
|
| 3655 |
preview_val = None
|
| 3656 |
if language == "html":
|
| 3657 |
_mpc = parse_multipage_html_output(clean_code)
|
|
|
|
| 3658 |
preview_val = send_to_sandbox(inline_multipage_into_single_preview(_mpc)) if _mpc.get('index.html') else send_to_sandbox(clean_code)
|
| 3659 |
elif language == "python" and is_streamlit_code(clean_code):
|
| 3660 |
preview_val = send_streamlit_to_stlite(clean_code)
|
|
@@ -3675,6 +3784,7 @@ This will help me create a better design for you."""
|
|
| 3675 |
preview_val = None
|
| 3676 |
if language == "html":
|
| 3677 |
_mpc2 = parse_multipage_html_output(clean_code)
|
|
|
|
| 3678 |
preview_val = send_to_sandbox(inline_multipage_into_single_preview(_mpc2)) if _mpc2.get('index.html') else send_to_sandbox(clean_code)
|
| 3679 |
elif language == "python" and is_streamlit_code(clean_code):
|
| 3680 |
preview_val = send_streamlit_to_stlite(clean_code)
|
|
@@ -3852,6 +3962,7 @@ This will help me create a better design for you."""
|
|
| 3852 |
preview_val = None
|
| 3853 |
if language == "html":
|
| 3854 |
_mpc3 = parse_multipage_html_output(clean_code)
|
|
|
|
| 3855 |
preview_val = send_to_sandbox(inline_multipage_into_single_preview(_mpc3)) if _mpc3.get('index.html') else send_to_sandbox(clean_code)
|
| 3856 |
elif language == "python" and is_streamlit_code(clean_code):
|
| 3857 |
preview_val = send_streamlit_to_stlite(clean_code)
|
|
@@ -3870,6 +3981,7 @@ This will help me create a better design for you."""
|
|
| 3870 |
preview_val = None
|
| 3871 |
if language == "html":
|
| 3872 |
_mpc4 = parse_multipage_html_output(clean_content)
|
|
|
|
| 3873 |
preview_val = send_to_sandbox(inline_multipage_into_single_preview(_mpc4)) if _mpc4.get('index.html') else send_to_sandbox(clean_content)
|
| 3874 |
elif language == "python" and is_streamlit_code(clean_content):
|
| 3875 |
preview_val = send_streamlit_to_stlite(clean_content)
|
|
@@ -3884,6 +3996,7 @@ This will help me create a better design for you."""
|
|
| 3884 |
preview_val = None
|
| 3885 |
if language == "html":
|
| 3886 |
_mpc5 = parse_multipage_html_output(clean_code)
|
|
|
|
| 3887 |
preview_val = send_to_sandbox(inline_multipage_into_single_preview(_mpc5)) if _mpc5.get('index.html') else send_to_sandbox(clean_code)
|
| 3888 |
elif language == "python" and is_streamlit_code(clean_code):
|
| 3889 |
preview_val = send_streamlit_to_stlite(clean_code)
|
|
@@ -4030,6 +4143,7 @@ This will help me create a better design for you."""
|
|
| 4030 |
preview_val = None
|
| 4031 |
if language == "html":
|
| 4032 |
_mpf = parse_multipage_html_output(final_content)
|
|
|
|
| 4033 |
preview_val = send_to_sandbox(inline_multipage_into_single_preview(_mpf)) if _mpf.get('index.html') else send_to_sandbox(final_content)
|
| 4034 |
elif language == "python" and is_streamlit_code(final_content):
|
| 4035 |
preview_val = send_streamlit_to_stlite(final_content)
|
|
@@ -5173,6 +5287,7 @@ with gr.Blocks(
|
|
| 5173 |
value=False,
|
| 5174 |
visible=True
|
| 5175 |
)
|
|
|
|
| 5176 |
# Image generation toggles
|
| 5177 |
image_generation_toggle = gr.Checkbox(
|
| 5178 |
label="π¨ Generate Images (text β image)",
|
|
@@ -5491,6 +5606,7 @@ with gr.Blocks(
|
|
| 5491 |
if language == "html":
|
| 5492 |
# If the content is a multi-page block, inline for preview; else render directly
|
| 5493 |
files = parse_multipage_html_output(code)
|
|
|
|
| 5494 |
if files and files.get('index.html'):
|
| 5495 |
merged = inline_multipage_into_single_preview(files)
|
| 5496 |
return send_to_sandbox(merged)
|
|
@@ -6381,6 +6497,7 @@ with gr.Blocks(
|
|
| 6381 |
files = {}
|
| 6382 |
try:
|
| 6383 |
files = parse_multipage_html_output(code)
|
|
|
|
| 6384 |
except Exception:
|
| 6385 |
files = {}
|
| 6386 |
|
|
|
|
| 428 |
Use search results to apply current best practices in accessibility, semantics, responsive meta tags, and performance (preconnect, responsive images).
|
| 429 |
"""
|
| 430 |
|
| 431 |
+
# Dynamic multi-page (model decides files) prompts
|
| 432 |
+
DYNAMIC_MULTIPAGE_HTML_SYSTEM_PROMPT = """You are an expert front-end developer.
|
| 433 |
+
|
| 434 |
+
Create a production-ready website using ONLY HTML, CSS, and vanilla JavaScript. Do NOT use SPA frameworks.
|
| 435 |
+
|
| 436 |
+
File selection policy:
|
| 437 |
+
- Generate ONLY the files actually needed for the user's request.
|
| 438 |
+
- Include at least one HTML entrypoint (default: index.html) unless the user explicitly requests a non-HTML asset only.
|
| 439 |
+
- If any local asset (CSS/JS/image) is referenced, include that file in the output.
|
| 440 |
+
- Use relative paths between files (e.g., assets/css/styles.css).
|
| 441 |
+
|
| 442 |
+
Output format (CRITICAL):
|
| 443 |
+
- Return ONLY a series of file sections, each starting with a filename line:
|
| 444 |
+
=== index.html ===
|
| 445 |
+
...file content...
|
| 446 |
+
|
| 447 |
+
=== assets/css/styles.css ===
|
| 448 |
+
...file content...
|
| 449 |
+
|
| 450 |
+
(repeat for all files)
|
| 451 |
+
- Do NOT wrap files in Markdown code fences
|
| 452 |
+
|
| 453 |
+
General requirements:
|
| 454 |
+
- Use modern, semantic HTML
|
| 455 |
+
- Mobile-first responsive design
|
| 456 |
+
- Include basic SEO meta tags in <head> for the entrypoint
|
| 457 |
+
- Include a footer on all major pages when multiple pages are present
|
| 458 |
+
- Avoid external CSS/JS frameworks (optional: CDN fonts/icons allowed)
|
| 459 |
+
"""
|
| 460 |
+
|
| 461 |
+
DYNAMIC_MULTIPAGE_HTML_SYSTEM_PROMPT_WITH_SEARCH = """You are an expert front-end developer. You have access to real-time web search.
|
| 462 |
+
|
| 463 |
+
Create a production-ready website using ONLY HTML, CSS, and vanilla JavaScript. Do NOT use SPA frameworks.
|
| 464 |
+
|
| 465 |
+
Follow the same output format and file selection policy as above (=== filename === blocks; model decides which files to create; ensure index.html unless explicitly not needed).
|
| 466 |
+
|
| 467 |
+
Use search results to apply current best practices in accessibility, semantics, responsive meta tags, and performance (preconnect, responsive images).
|
| 468 |
+
"""
|
| 469 |
+
|
| 470 |
GENERIC_SYSTEM_PROMPT_WITH_SEARCH = """You are an expert {language} developer. You have access to real-time web search. When needed, use web search to find the latest information, best practices, or specific technologies for {language}.
|
| 471 |
|
| 472 |
Write clean, idiomatic, and runnable {language} code for the user's request. If possible, include comments and best practices. Output ONLY the code inside a ``` code block, and do not include any explanations or extra text. If the user provides a file or other context, use it as a reference. If the code is for a script or app, make it as self-contained as possible. Do NOT add the language name at the top of the code output."""
|
|
|
|
| 1282 |
files[name] = content
|
| 1283 |
return files
|
| 1284 |
|
| 1285 |
+
def validate_and_autofix_files(files: Dict[str, str]) -> Dict[str, str]:
|
| 1286 |
+
"""Ensure minimal contract for multi-file sites; auto-fix missing pieces.
|
| 1287 |
+
|
| 1288 |
+
Rules:
|
| 1289 |
+
- Ensure at least one HTML entrypoint (index.html). If none, synthesize a simple index.html linking discovered pages.
|
| 1290 |
+
- For each HTML file, ensure referenced local assets exist in files; if missing, add minimal stubs.
|
| 1291 |
+
- Normalize relative paths (strip leading '/').
|
| 1292 |
+
"""
|
| 1293 |
+
if not isinstance(files, dict) or not files:
|
| 1294 |
+
return files or {}
|
| 1295 |
+
import re as _re
|
| 1296 |
+
|
| 1297 |
+
normalized: Dict[str, str] = {}
|
| 1298 |
+
for k, v in files.items():
|
| 1299 |
+
safe_key = k.strip().lstrip('/')
|
| 1300 |
+
normalized[safe_key] = v
|
| 1301 |
+
|
| 1302 |
+
html_files = [p for p in normalized.keys() if p.lower().endswith('.html')]
|
| 1303 |
+
has_index = 'index.html' in normalized
|
| 1304 |
+
|
| 1305 |
+
# If no index.html but some HTML pages exist, create a simple hub index linking to them
|
| 1306 |
+
if not has_index and html_files:
|
| 1307 |
+
links = '\n'.join([f"<li><a href=\"{p}\">{p}</a></li>" for p in html_files])
|
| 1308 |
+
normalized['index.html'] = (
|
| 1309 |
+
"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\"/>\n"
|
| 1310 |
+
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>\n"
|
| 1311 |
+
"<title>Site Index</title>\n</head>\n<body>\n<h1>Site</h1>\n<ul>\n"
|
| 1312 |
+
+ links + "\n</ul>\n</body>\n</html>"
|
| 1313 |
+
)
|
| 1314 |
+
|
| 1315 |
+
# Collect references from HTML files
|
| 1316 |
+
asset_refs: set[str] = set()
|
| 1317 |
+
link_href = _re.compile(r"<link[^>]+href=\"([^\"]+)\"")
|
| 1318 |
+
script_src = _re.compile(r"<script[^>]+src=\"([^\"]+)\"")
|
| 1319 |
+
img_src = _re.compile(r"<img[^>]+src=\"([^\"]+)\"")
|
| 1320 |
+
a_href = _re.compile(r"<a[^>]+href=\"([^\"]+)\"")
|
| 1321 |
+
|
| 1322 |
+
for path, content in list(normalized.items()):
|
| 1323 |
+
if not path.lower().endswith('.html'):
|
| 1324 |
+
continue
|
| 1325 |
+
for patt in (link_href, script_src, img_src, a_href):
|
| 1326 |
+
for m in patt.finditer(content or ""):
|
| 1327 |
+
ref = (m.group(1) or "").strip()
|
| 1328 |
+
if not ref or ref.startswith('http://') or ref.startswith('https://') or ref.startswith('data:') or '#' in ref:
|
| 1329 |
+
continue
|
| 1330 |
+
asset_refs.add(ref.lstrip('/'))
|
| 1331 |
+
|
| 1332 |
+
# Add minimal stubs for missing local references (CSS/JS/images/pages)
|
| 1333 |
+
for ref in list(asset_refs):
|
| 1334 |
+
if ref not in normalized:
|
| 1335 |
+
if ref.lower().endswith('.css'):
|
| 1336 |
+
normalized[ref] = "/* generated stub */\n"
|
| 1337 |
+
elif ref.lower().endswith('.js'):
|
| 1338 |
+
normalized[ref] = "// generated stub\n"
|
| 1339 |
+
elif any(ref.lower().endswith(ext) for ext in ['.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp']):
|
| 1340 |
+
# Use a tiny inline SVG as placeholder content
|
| 1341 |
+
normalized[ref] = (
|
| 1342 |
+
"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1\" height=\"1\"></svg>\n"
|
| 1343 |
+
)
|
| 1344 |
+
elif ref.lower().endswith('.html'):
|
| 1345 |
+
normalized[ref] = (
|
| 1346 |
+
"<!DOCTYPE html>\n<html lang=\"en\">\n<head><meta charset=\"utf-8\"/><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/><title>Page</title></head>\n"
|
| 1347 |
+
"<body><main><h1>Placeholder page</h1><p>This page was auto-created to satisfy an internal link.</p></main></body>\n</html>"
|
| 1348 |
+
)
|
| 1349 |
+
|
| 1350 |
+
return normalized
|
| 1351 |
+
|
| 1352 |
def inline_multipage_into_single_preview(files: Dict[str, str]) -> str:
|
| 1353 |
"""Inline local CSS/JS referenced by index.html for preview inside a data: iframe.
|
| 1354 |
|
|
|
|
| 3392 |
else:
|
| 3393 |
# Use language-specific prompt
|
| 3394 |
if language == "html":
|
| 3395 |
+
# Dynamic file selection always enabled
|
| 3396 |
+
system_prompt = DYNAMIC_MULTIPAGE_HTML_SYSTEM_PROMPT_WITH_SEARCH if enable_search else DYNAMIC_MULTIPAGE_HTML_SYSTEM_PROMPT
|
| 3397 |
elif language == "transformers.js":
|
| 3398 |
system_prompt = TRANSFORMERS_JS_SYSTEM_PROMPT_WITH_SEARCH if enable_search else TRANSFORMERS_JS_SYSTEM_PROMPT
|
| 3399 |
elif language == "svelte":
|
|
|
|
| 3464 |
preview_val = None
|
| 3465 |
if language == "html":
|
| 3466 |
_mp = parse_multipage_html_output(clean_code)
|
| 3467 |
+
_mp = validate_and_autofix_files(_mp)
|
| 3468 |
preview_val = send_to_sandbox(inline_multipage_into_single_preview(_mp)) if _mp.get('index.html') else send_to_sandbox(clean_code)
|
| 3469 |
elif language == "python" and is_streamlit_code(clean_code):
|
| 3470 |
preview_val = send_streamlit_to_stlite(clean_code)
|
|
|
|
| 3695 |
preview_val = None
|
| 3696 |
if language == "html":
|
| 3697 |
_mpf2 = parse_multipage_html_output(final_content)
|
| 3698 |
+
_mpf2 = validate_and_autofix_files(_mpf2)
|
| 3699 |
preview_val = send_to_sandbox(inline_multipage_into_single_preview(_mpf2)) if _mpf2.get('index.html') else send_to_sandbox(final_content)
|
| 3700 |
elif language == "python" and is_streamlit_code(final_content):
|
| 3701 |
preview_val = send_streamlit_to_stlite(final_content)
|
|
|
|
| 3763 |
preview_val = None
|
| 3764 |
if language == "html":
|
| 3765 |
_mpc = parse_multipage_html_output(clean_code)
|
| 3766 |
+
_mpc = validate_and_autofix_files(_mpc)
|
| 3767 |
preview_val = send_to_sandbox(inline_multipage_into_single_preview(_mpc)) if _mpc.get('index.html') else send_to_sandbox(clean_code)
|
| 3768 |
elif language == "python" and is_streamlit_code(clean_code):
|
| 3769 |
preview_val = send_streamlit_to_stlite(clean_code)
|
|
|
|
| 3784 |
preview_val = None
|
| 3785 |
if language == "html":
|
| 3786 |
_mpc2 = parse_multipage_html_output(clean_code)
|
| 3787 |
+
_mpc2 = validate_and_autofix_files(_mpc2)
|
| 3788 |
preview_val = send_to_sandbox(inline_multipage_into_single_preview(_mpc2)) if _mpc2.get('index.html') else send_to_sandbox(clean_code)
|
| 3789 |
elif language == "python" and is_streamlit_code(clean_code):
|
| 3790 |
preview_val = send_streamlit_to_stlite(clean_code)
|
|
|
|
| 3962 |
preview_val = None
|
| 3963 |
if language == "html":
|
| 3964 |
_mpc3 = parse_multipage_html_output(clean_code)
|
| 3965 |
+
_mpc3 = validate_and_autofix_files(_mpc3)
|
| 3966 |
preview_val = send_to_sandbox(inline_multipage_into_single_preview(_mpc3)) if _mpc3.get('index.html') else send_to_sandbox(clean_code)
|
| 3967 |
elif language == "python" and is_streamlit_code(clean_code):
|
| 3968 |
preview_val = send_streamlit_to_stlite(clean_code)
|
|
|
|
| 3981 |
preview_val = None
|
| 3982 |
if language == "html":
|
| 3983 |
_mpc4 = parse_multipage_html_output(clean_content)
|
| 3984 |
+
_mpc4 = validate_and_autofix_files(_mpc4)
|
| 3985 |
preview_val = send_to_sandbox(inline_multipage_into_single_preview(_mpc4)) if _mpc4.get('index.html') else send_to_sandbox(clean_content)
|
| 3986 |
elif language == "python" and is_streamlit_code(clean_content):
|
| 3987 |
preview_val = send_streamlit_to_stlite(clean_content)
|
|
|
|
| 3996 |
preview_val = None
|
| 3997 |
if language == "html":
|
| 3998 |
_mpc5 = parse_multipage_html_output(clean_code)
|
| 3999 |
+
_mpc5 = validate_and_autofix_files(_mpc5)
|
| 4000 |
preview_val = send_to_sandbox(inline_multipage_into_single_preview(_mpc5)) if _mpc5.get('index.html') else send_to_sandbox(clean_code)
|
| 4001 |
elif language == "python" and is_streamlit_code(clean_code):
|
| 4002 |
preview_val = send_streamlit_to_stlite(clean_code)
|
|
|
|
| 4143 |
preview_val = None
|
| 4144 |
if language == "html":
|
| 4145 |
_mpf = parse_multipage_html_output(final_content)
|
| 4146 |
+
_mpf = validate_and_autofix_files(_mpf)
|
| 4147 |
preview_val = send_to_sandbox(inline_multipage_into_single_preview(_mpf)) if _mpf.get('index.html') else send_to_sandbox(final_content)
|
| 4148 |
elif language == "python" and is_streamlit_code(final_content):
|
| 4149 |
preview_val = send_streamlit_to_stlite(final_content)
|
|
|
|
| 5287 |
value=False,
|
| 5288 |
visible=True
|
| 5289 |
)
|
| 5290 |
+
# Dynamic multipage is always enabled; no toggle in UI
|
| 5291 |
# Image generation toggles
|
| 5292 |
image_generation_toggle = gr.Checkbox(
|
| 5293 |
label="π¨ Generate Images (text β image)",
|
|
|
|
| 5606 |
if language == "html":
|
| 5607 |
# If the content is a multi-page block, inline for preview; else render directly
|
| 5608 |
files = parse_multipage_html_output(code)
|
| 5609 |
+
files = validate_and_autofix_files(files)
|
| 5610 |
if files and files.get('index.html'):
|
| 5611 |
merged = inline_multipage_into_single_preview(files)
|
| 5612 |
return send_to_sandbox(merged)
|
|
|
|
| 6497 |
files = {}
|
| 6498 |
try:
|
| 6499 |
files = parse_multipage_html_output(code)
|
| 6500 |
+
files = validate_and_autofix_files(files)
|
| 6501 |
except Exception:
|
| 6502 |
files = {}
|
| 6503 |
|