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 |
|