natabrizy commited on
Commit
b424377
·
verified ·
1 Parent(s): a0de1c7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +130 -30
app.py CHANGED
@@ -32,11 +32,11 @@ CODE_MODELS = [
32
  "Mistral-7B-Instruct",
33
  ]
34
 
35
- # More forgiving timeouts and built-in retries
36
  HTTP_TIMEOUTS = httpx.Timeout(connect=10.0, read=120.0, write=30.0, pool=60.0)
37
- HTTP_RETRIES = 2 # extra attempts on transient failures
38
 
39
- # Use the same default key you provided
40
  DEFAULT_NEBIUS_API_KEY = (
41
  "eyJhbGciOiJIUzI1NiIsImtpZCI6IlV6SXJWd1h0dnprLVRvdzlLZWstc0M1akptWXBvX1VaVkxUZlpnMDRlOFUiLCJ0eXAiOiJKV1QifQ.eyJzdWIiOiJnb29nbGUtb2F1dGgyfDEwNTA1MTQzMDg2MDMwMzIxNDEwMiIsInNjb3BlIjoib3BlbmlkIG9mZmxpbmVfYWNjZXNzIiwiaXNzIjoiYXBpX2tleV9pc3N1ZXIiLCJhdWQiOlsiaHR0cHM6Ly9uZWJpdXMtaW5mZXJlbmNlLmV1LmF1dGgwLmNvbS9hcGkvdjIvIl0sImV4cCI6MTkwNjU5ODA0NCwidXVpZCI6ImNkOGFiMWZlLTIxN2QtNDJlMy04OWUwLWM1YTg4MjcwMGVhNyIsIm5hbWUiOiJodW5nZ2luZyIsImV4cGlyZXNfYXQiOiIyMDMwLTA2LTAyVDAyOjM0OjA0KzAwMDAifQ.MA52QuIiNruK7_lX688RXAEI2TkcCOjcf_02XrpnhI8"
42
  )
@@ -123,6 +123,7 @@ def _split_assets(html_code: str) -> Tuple[str, str, str]:
123
 
124
  # Collect and remove inline scripts (no src)
125
  js_blocks = []
 
126
  def _script_repl(m):
127
  attrs = m.group("attrs") or ""
128
  code = m.group("code") or ""
@@ -131,21 +132,36 @@ def _split_assets(html_code: str) -> Tuple[str, str, str]:
131
  if code.strip():
132
  js_blocks.append(code.strip())
133
  return "" # remove inline script
134
- html = re.sub(r"<script(?P<attrs>[^>]*)>(?P<code>.*?)</script>", _script_repl, html, flags=re.IGNORECASE | re.DOTALL)
 
 
 
 
 
 
135
  js_text = "\n\n".join(js_blocks)
136
 
137
  # If CSS collected, ensure link tag is added
138
  if css_text:
139
  if re.search(r"</head>", html, flags=re.IGNORECASE):
140
- html = re.sub(r"</head>", ' <link rel="stylesheet" href="style.css">\n</head>', html, flags=re.IGNORECASE)
 
 
 
 
 
141
  else:
142
- # add a minimal head if missing
143
  html = f"<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\"/>\n <link rel=\"stylesheet\" href=\"style.css\">\n</head>\n{html}"
144
 
145
  # If JS collected, ensure script tag before </body> or at end
146
  if js_text:
147
  if re.search(r"</body>", html, flags=re.IGNORECASE):
148
- html = re.sub(r"</body>", ' <script src="script.js"></script>\n</body>', html, flags=re.IGNORECASE)
 
 
 
 
 
149
  else:
150
  html = html.rstrip() + '\n <script src="script.js"></script>\n'
151
 
@@ -401,28 +417,116 @@ def export_html_to_file(html_code: str) -> Optional[str]:
401
 
402
 
403
  # =========================
404
- # Gradio UI (English-only, user-friendly)
405
  # =========================
 
 
 
 
 
 
 
 
 
406
  with gr.Blocks(
407
  theme=gr.themes.Soft(),
408
  title="AI Website Generator (Nebius)",
409
- css="""
410
- .section { border: 1px solid #e5e7eb; padding: 16px; border-radius: 10px; margin: 10px 0; }
411
- .muted { color: #6b7280; font-size: 0.9em; }
412
- .footer { text-align:center; color:#9ca3af; padding: 8px 0; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
413
  """,
414
  ) as app:
415
  gr.Markdown(
416
  """
417
- # 🚀 AI Website Generator (Nebius)
418
  Turn website screenshots into functional HTML using Nebius-compatible models.
419
 
420
- - 📸 Image analysis (choose a vision model)
421
- - 💻 Code generation (choose a code-capable model)
422
- - 🌐 One-click CodeSandbox deployment
423
- - 🧩 Editor links open index.html and style.css directly
424
- - 🔒 Your key is used at runtime only
425
- """
 
426
  )
427
 
428
  with gr.Accordion("API & Models", open=True):
@@ -466,7 +570,7 @@ Turn website screenshots into functional HTML using Nebius-compatible models.
466
  info="Higher is more creative; lower is more deterministic.",
467
  )
468
 
469
- with gr.Tab("🎯 Quick Generate"):
470
  with gr.Row():
471
  with gr.Column(scale=1):
472
  gr.Markdown("### Step 1: Upload Screenshot", elem_classes=["section"])
@@ -476,7 +580,7 @@ Turn website screenshots into functional HTML using Nebius-compatible models.
476
  sources=["upload", "clipboard"],
477
  height=280,
478
  )
479
- generate_btn = gr.Button("🎨 Generate Website", variant="primary")
480
 
481
  with gr.Column(scale=2):
482
  gr.Markdown("### Step 2: Review Results", elem_classes=["section"])
@@ -492,8 +596,8 @@ Turn website screenshots into functional HTML using Nebius-compatible models.
492
  )
493
 
494
  with gr.Row():
495
- codesandbox_btn = gr.Button("🚀 Deploy to CodeSandbox")
496
- download_btn = gr.Button("💾 Download index.html")
497
 
498
  codesandbox_links = gr.Markdown(value="")
499
  download_file = gr.File(
@@ -502,18 +606,18 @@ Turn website screenshots into functional HTML using Nebius-compatible models.
502
  visible=False,
503
  )
504
 
505
- with gr.Tab("🔧 Individual Tools"):
506
  with gr.Row():
507
  with gr.Column():
508
  gr.Markdown("### Image Analysis Tool", elem_classes=["section"])
509
  img_tool = gr.Image(type="pil", label="Image")
510
- analyze_btn = gr.Button("Analyze Image")
511
  analysis_result = gr.Textbox(label="Analysis Result", lines=6)
512
 
513
  with gr.Column():
514
  gr.Markdown("### Code Generation Tool", elem_classes=["section"])
515
  desc_input = gr.Textbox(label="Description", lines=4, placeholder="Describe the page you want...")
516
- code_btn = gr.Button("Generate Code")
517
  code_result = gr.Code(label="Generated Code", language="html")
518
 
519
  gr.Markdown("Made with Gradio • Nebius API compatible", elem_classes=["footer"])
@@ -529,7 +633,6 @@ Turn website screenshots into functional HTML using Nebius-compatible models.
529
  url_block = create_codesandbox(html_code)
530
  if url_block.startswith("Error"):
531
  return f"**{url_block}**"
532
- # Render as Markdown list
533
  lines = ["### CodeSandbox Links", "", url_block]
534
  return "\n".join(lines)
535
 
@@ -563,8 +666,5 @@ Turn website screenshots into functional HTML using Nebius-compatible models.
563
  outputs=[code_result],
564
  )
565
 
566
- # Optional examples (uncomment and provide your own image file)
567
- # gr.Examples(examples=[["1.jpg"]], inputs=[image_input], label="Example Screenshots")
568
-
569
  if __name__ == "__main__":
570
  app.launch(share=False)
 
32
  "Mistral-7B-Instruct",
33
  ]
34
 
35
+ # Timeouts and simple retries for stability
36
  HTTP_TIMEOUTS = httpx.Timeout(connect=10.0, read=120.0, write=30.0, pool=60.0)
37
+ HTTP_RETRIES = 2
38
 
39
+ # Keep the same default key you provided
40
  DEFAULT_NEBIUS_API_KEY = (
41
  "eyJhbGciOiJIUzI1NiIsImtpZCI6IlV6SXJWd1h0dnprLVRvdzlLZWstc0M1akptWXBvX1VaVkxUZlpnMDRlOFUiLCJ0eXAiOiJKV1QifQ.eyJzdWIiOiJnb29nbGUtb2F1dGgyfDEwNTA1MTQzMDg2MDMwMzIxNDEwMiIsInNjb3BlIjoib3BlbmlkIG9mZmxpbmVfYWNjZXNzIiwiaXNzIjoiYXBpX2tleV9pc3N1ZXIiLCJhdWQiOlsiaHR0cHM6Ly9uZWJpdXMtaW5mZXJlbmNlLmV1LmF1dGgwLmNvbS9hcGkvdjIvIl0sImV4cCI6MTkwNjU5ODA0NCwidXVpZCI6ImNkOGFiMWZlLTIxN2QtNDJlMy04OWUwLWM1YTg4MjcwMGVhNyIsIm5hbWUiOiJodW5nZ2luZyIsImV4cGlyZXNfYXQiOiIyMDMwLTA2LTAyVDAyOjM0OjA0KzAwMDAifQ.MA52QuIiNruK7_lX688RXAEI2TkcCOjcf_02XrpnhI8"
42
  )
 
123
 
124
  # Collect and remove inline scripts (no src)
125
  js_blocks = []
126
+
127
  def _script_repl(m):
128
  attrs = m.group("attrs") or ""
129
  code = m.group("code") or ""
 
132
  if code.strip():
133
  js_blocks.append(code.strip())
134
  return "" # remove inline script
135
+
136
+ html = re.sub(
137
+ r"<script(?P<attrs>[^>]*)>(?P<code>.*?)</script>",
138
+ _script_repl,
139
+ html,
140
+ flags=re.IGNORECASE | re.DOTALL,
141
+ )
142
  js_text = "\n\n".join(js_blocks)
143
 
144
  # If CSS collected, ensure link tag is added
145
  if css_text:
146
  if re.search(r"</head>", html, flags=re.IGNORECASE):
147
+ html = re.sub(
148
+ r"</head>",
149
+ ' <link rel="stylesheet" href="style.css">\n</head>',
150
+ html,
151
+ flags=re.IGNORECASE,
152
+ )
153
  else:
 
154
  html = f"<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\"/>\n <link rel=\"stylesheet\" href=\"style.css\">\n</head>\n{html}"
155
 
156
  # If JS collected, ensure script tag before </body> or at end
157
  if js_text:
158
  if re.search(r"</body>", html, flags=re.IGNORECASE):
159
+ html = re.sub(
160
+ r"</body>",
161
+ ' <script src="script.js"></script>\n</body>',
162
+ html,
163
+ flags=re.IGNORECASE,
164
+ )
165
  else:
166
  html = html.rstrip() + '\n <script src="script.js"></script>\n'
167
 
 
417
 
418
 
419
  # =========================
420
+ # Gradio UI (Brizy-inspired palette, no emojis)
421
  # =========================
422
+ BRIZY_PRIMARY = "#6C5CE7" # Indigo-like
423
+ BRIZY_SECONDARY = "#00C2FF" # Cyan accent
424
+ BRIZY_BG = "#F7F9FC" # Light background
425
+ BRIZY_SURFACE = "#FFFFFF" # Surface
426
+ BRIZY_TEXT = "#1F2937" # Dark text
427
+ BRIZY_MUTED = "#6B7280" # Muted text
428
+ BRIZY_BORDER = "#E5E7EB" # Soft border
429
+ BRIZY_GRADIENT = f"linear-gradient(135deg, {BRIZY_PRIMARY} 0%, {BRIZY_SECONDARY} 100%)"
430
+
431
  with gr.Blocks(
432
  theme=gr.themes.Soft(),
433
  title="AI Website Generator (Nebius)",
434
+ css=f"""
435
+ :root {{
436
+ --app-primary: {BRIZY_PRIMARY};
437
+ --app-secondary: {BRIZY_SECONDARY};
438
+ --app-bg: {BRIZY_BG};
439
+ --app-surface: {BRIZY_SURFACE};
440
+ --app-text: {BRIZY_TEXT};
441
+ --app-muted: {BRIZY_MUTED};
442
+ --app-border: {BRIZY_BORDER};
443
+ }}
444
+
445
+ body {{
446
+ background: var(--app-bg);
447
+ color: var(--app-text);
448
+ }}
449
+
450
+ .section {{
451
+ border: 1px solid var(--app-border);
452
+ padding: 16px;
453
+ border-radius: 12px;
454
+ background: var(--app-surface);
455
+ box-shadow: 0 1px 2px rgba(0,0,0,0.03);
456
+ margin: 10px 0;
457
+ }}
458
+
459
+ .muted {{
460
+ color: var(--app-muted);
461
+ font-size: 0.92em;
462
+ }}
463
+
464
+ .footer {{
465
+ text-align: center;
466
+ color: var(--app-muted);
467
+ padding: 8px 0;
468
+ }}
469
+
470
+ .title h1 {{
471
+ background: {BRIZY_GRADIENT};
472
+ -webkit-background-clip: text;
473
+ background-clip: text;
474
+ color: transparent;
475
+ font-weight: 800;
476
+ letter-spacing: -0.02em;
477
+ }}
478
+
479
+ .primary-btn button {{
480
+ background: {BRIZY_GRADIENT} !important;
481
+ color: #fff !important;
482
+ border: none !important;
483
+ }}
484
+ .primary-btn button:hover {{
485
+ filter: brightness(0.98);
486
+ }}
487
+
488
+ .secondary-btn button {{
489
+ background: var(--app-surface) !important;
490
+ color: var(--app-text) !important;
491
+ border: 1px solid var(--app-border) !important;
492
+ }}
493
+ .secondary-btn button:hover {{
494
+ border-color: {BRIZY_PRIMARY} !important;
495
+ color: {BRIZY_PRIMARY} !important;
496
+ }}
497
+
498
+ /* Inputs focus */
499
+ input:focus, textarea:focus, select:focus {{
500
+ outline-color: {BRIZY_PRIMARY} !important;
501
+ border-color: {BRIZY_PRIMARY} !important;
502
+ box-shadow: 0 0 0 3px rgba(108,92,231,0.15) !important;
503
+ }}
504
+
505
+ /* Code block accents */
506
+ .gr-code .cm-editor, .gr-code textarea {{
507
+ border-radius: 10px !important;
508
+ border: 1px solid var(--app-border) !important;
509
+ }}
510
+
511
+ /* Tabs accent */
512
+ .gradio-container .tabs .tab-nav button[aria-selected="true"] {{
513
+ color: {BRIZY_PRIMARY} !important;
514
+ border-bottom: 2px solid {BRIZY_PRIMARY} !important;
515
+ }}
516
  """,
517
  ) as app:
518
  gr.Markdown(
519
  """
520
+ # AI Website Generator (Nebius)
521
  Turn website screenshots into functional HTML using Nebius-compatible models.
522
 
523
+ - Image analysis (choose a vision model)
524
+ - Code generation (choose a code-capable model)
525
+ - One-click CodeSandbox deployment
526
+ - Editor links open index.html and style.css directly
527
+ - Your key is used at runtime only
528
+ """,
529
+ elem_classes=["title"],
530
  )
531
 
532
  with gr.Accordion("API & Models", open=True):
 
570
  info="Higher is more creative; lower is more deterministic.",
571
  )
572
 
573
+ with gr.Tab("Quick Generate"):
574
  with gr.Row():
575
  with gr.Column(scale=1):
576
  gr.Markdown("### Step 1: Upload Screenshot", elem_classes=["section"])
 
580
  sources=["upload", "clipboard"],
581
  height=280,
582
  )
583
+ generate_btn = gr.Button("Generate Website", elem_classes=["primary-btn"])
584
 
585
  with gr.Column(scale=2):
586
  gr.Markdown("### Step 2: Review Results", elem_classes=["section"])
 
596
  )
597
 
598
  with gr.Row():
599
+ codesandbox_btn = gr.Button("Deploy to CodeSandbox", elem_classes=["secondary-btn"])
600
+ download_btn = gr.Button("Download index.html", elem_classes=["secondary-btn"])
601
 
602
  codesandbox_links = gr.Markdown(value="")
603
  download_file = gr.File(
 
606
  visible=False,
607
  )
608
 
609
+ with gr.Tab("Individual Tools"):
610
  with gr.Row():
611
  with gr.Column():
612
  gr.Markdown("### Image Analysis Tool", elem_classes=["section"])
613
  img_tool = gr.Image(type="pil", label="Image")
614
+ analyze_btn = gr.Button("Analyze Image", elem_classes=["secondary-btn"])
615
  analysis_result = gr.Textbox(label="Analysis Result", lines=6)
616
 
617
  with gr.Column():
618
  gr.Markdown("### Code Generation Tool", elem_classes=["section"])
619
  desc_input = gr.Textbox(label="Description", lines=4, placeholder="Describe the page you want...")
620
+ code_btn = gr.Button("Generate Code", elem_classes=["secondary-btn"])
621
  code_result = gr.Code(label="Generated Code", language="html")
622
 
623
  gr.Markdown("Made with Gradio • Nebius API compatible", elem_classes=["footer"])
 
633
  url_block = create_codesandbox(html_code)
634
  if url_block.startswith("Error"):
635
  return f"**{url_block}**"
 
636
  lines = ["### CodeSandbox Links", "", url_block]
637
  return "\n".join(lines)
638
 
 
666
  outputs=[code_result],
667
  )
668
 
 
 
 
669
  if __name__ == "__main__":
670
  app.launch(share=False)