Spaces:
Runtime error
Runtime error
| import gradio as gr | |
| import anthropic | |
| import json | |
| import os | |
| import re | |
| from typing import Tuple, Optional | |
| import tempfile | |
| import zipfile | |
| from pathlib import Path | |
| # Initialize Anthropic client | |
| ANTHROPIC_API_KEY = os.getenv("ANTHROPIC_API_KEY") | |
| client = anthropic.Anthropic(api_key=ANTHROPIC_API_KEY) if ANTHROPIC_API_KEY else None | |
| def generate_website(description: str, style: str, features: list) -> Tuple[str, str, str]: | |
| """Generate website HTML, CSS, and JavaScript using Claude Sonnet 4.5""" | |
| if not client: | |
| return create_error_page("API Error: Please set ANTHROPIC_API_KEY environment variable") | |
| # Create prompt for Claude | |
| features_text = ", ".join(features) if features else "basic" | |
| prompt = f""" | |
| Create a complete, modern website based on this description: {description} | |
| Style: {style} | |
| Features to include: {features_text} | |
| Please generate: | |
| 1. A complete HTML file with semantic HTML5 structure | |
| 2. Modern CSS with responsive design (using CSS Grid/Flexbox) | |
| 3. JavaScript for interactivity (if needed) | |
| Requirements: | |
| - Use modern design principles | |
| - Make it fully responsive for mobile, tablet, and desktop | |
| - Include smooth animations and transitions | |
| - Use semantic HTML5 tags | |
| - Add hover effects and micro-interactions | |
| - Include proper meta tags for SEO | |
| - Use a modern color scheme | |
| - Add placeholder content that matches the description | |
| - Make it production-ready | |
| Return your response as a JSON object with this exact structure: | |
| {{ | |
| "html": "<complete HTML code here>", | |
| "css": "<complete CSS code here>", | |
| "js": "<complete JavaScript code here>", | |
| "title": "Website Title" | |
| }} | |
| Do not include any explanations outside the JSON. Just return the JSON object. | |
| """ | |
| try: | |
| message = client.messages.create( | |
| model="claude-3-5-sonnet-20241022", | |
| max_tokens=4000, | |
| temperature=0.7, | |
| messages=[{ | |
| "role": "user", | |
| "content": prompt | |
| }] | |
| ) | |
| response_text = message.content[0].text | |
| # Extract JSON from response | |
| json_match = re.search(r'\{.*\}', response_text, re.DOTALL) | |
| if json_match: | |
| website_data = json.loads(json_match.group()) | |
| # Validate required keys | |
| if all(key in website_data for key in ['html', 'css', 'js', 'title']): | |
| return website_data['html'], website_data['css'], website_data['js'] | |
| else: | |
| return create_error_page("Invalid response format from AI") | |
| else: | |
| return create_error_page("Could not parse AI response") | |
| except Exception as e: | |
| return create_error_page(f"Error generating website: {str(e)}") | |
| def create_error_page(error_message: str) -> Tuple[str, str, str]: | |
| """Create an error page HTML""" | |
| error_html = f""" | |
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Error</title> | |
| <style> | |
| body {{ | |
| font-family: Arial, sans-serif; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| height: 100vh; | |
| margin: 0; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| color: white; | |
| }} | |
| .error-container {{ | |
| text-align: center; | |
| padding: 2rem; | |
| background: rgba(255, 255, 255, 0.1); | |
| border-radius: 10px; | |
| backdrop-filter: blur(10px); | |
| }} | |
| h1 {{ font-size: 2rem; margin-bottom: 1rem; }} | |
| p {{ font-size: 1.1rem; opacity: 0.9; }} | |
| </style> | |
| </head> | |
| <body> | |
| <div class="error-container"> | |
| <h1>⚠️ Error</h1> | |
| <p>{error_message}</p> | |
| </div> | |
| </body> | |
| </html> | |
| """ | |
| return error_html, "", "" | |
| def create_preview(html: str, css: str, js: str) -> str: | |
| """Create a complete preview by combining HTML, CSS, and JS""" | |
| # Create a complete HTML document with embedded CSS and JS | |
| preview_html = f""" | |
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <meta name="description" content="AI Generated Website"> | |
| <title>AI Generated Website Preview</title> | |
| <style> | |
| {css} | |
| </style> | |
| </head> | |
| <body> | |
| {html} | |
| <script> | |
| {js} | |
| </script> | |
| </body> | |
| </html> | |
| """ | |
| return preview_html | |
| def download_website(html: str, css: str, js: str) -> str: | |
| """Create a zip file with the website files""" | |
| with tempfile.TemporaryDirectory() as temp_dir: | |
| temp_path = Path(temp_dir) | |
| # Create index.html | |
| index_content = f"""<!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <meta name="description" content="AI Generated Website"> | |
| <title>AI Generated Website</title> | |
| <link rel="stylesheet" href="styles.css"> | |
| </head> | |
| <body> | |
| {html} | |
| <script src="script.js"></script> | |
| </body> | |
| </html>""" | |
| with open(temp_path / "index.html", "w", encoding="utf-8") as f: | |
| f.write(index_content) | |
| # Create styles.css | |
| with open(temp_path / "styles.css", "w", encoding="utf-8") as f: | |
| f.write(css) | |
| # Create script.js | |
| with open(temp_path / "script.js", "w", encoding="utf-8") as f: | |
| f.write(js) | |
| # Create README.md | |
| readme_content = """# AI Generated Website | |
| This website was generated using AI Website Builder with Claude Sonnet 4.5. | |
| ## Files | |
| - `index.html` - Main HTML file | |
| - `styles.css` - Stylesheet | |
| - `script.js` - JavaScript functionality | |
| ## Customization | |
| Feel free to modify any of the files to customize your website. | |
| """ | |
| with open(temp_path / "README.md", "w", encoding="utf-8") as f: | |
| f.write(readme_content) | |
| # Create zip file | |
| zip_path = temp_path / "website.zip" | |
| with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf: | |
| zipf.write(temp_path / "index.html", "index.html") | |
| zipf.write(temp_path / "styles.css", "styles.css") | |
| zipf.write(temp_path / "script.js", "script.js") | |
| zipf.write(temp_path / "README.md", "README.md") | |
| # Read zip file as bytes | |
| with open(zip_path, "rb") as f: | |
| zip_bytes = f.read() | |
| return zip_bytes | |
| # Custom CSS for the Gradio interface | |
| custom_css = """ | |
| .main-container { | |
| max-width: 1400px !important; | |
| margin: 0 auto !important; | |
| } | |
| .header { | |
| text-align: center; | |
| padding: 2rem; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| color: white; | |
| border-radius: 10px; | |
| margin-bottom: 2rem; | |
| } | |
| .header h1 { | |
| margin: 0; | |
| font-size: 2.5rem; | |
| font-weight: 700; | |
| } | |
| .header p { | |
| margin: 0.5rem 0 0 0; | |
| opacity: 0.9; | |
| font-size: 1.1rem; | |
| } | |
| .generator-section { | |
| background: #f8f9fa; | |
| padding: 2rem; | |
| border-radius: 10px; | |
| margin-bottom: 2rem; | |
| } | |
| .preview-section { | |
| background: white; | |
| border: 1px solid #e0e0e0; | |
| border-radius: 10px; | |
| overflow: hidden; | |
| } | |
| .preview-frame { | |
| width: 100%; | |
| height: 600px; | |
| border: none; | |
| } | |
| .code-editor { | |
| font-family: 'Courier New', monospace; | |
| font-size: 14px; | |
| } | |
| .tabs { | |
| margin-top: 1rem; | |
| } | |
| .generate-btn { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important; | |
| border: none !important; | |
| font-weight: 600 !important; | |
| padding: 0.75rem 2rem !important; | |
| font-size: 1.1rem !important; | |
| } | |
| .generate-btn:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4); | |
| } | |
| .feature-group { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); | |
| gap: 1rem; | |
| margin-top: 1rem; | |
| } | |
| .feature-checkbox { | |
| background: white; | |
| padding: 1rem; | |
| border-radius: 8px; | |
| border: 2px solid #e0e0e0; | |
| transition: all 0.3s ease; | |
| } | |
| .feature-checkbox:hover { | |
| border-color: #667eea; | |
| transform: translateY(-2px); | |
| } | |
| .feature-checkbox label { | |
| font-weight: 500; | |
| cursor: pointer; | |
| } | |
| @media (max-width: 768px) { | |
| .header h1 { | |
| font-size: 2rem; | |
| } | |
| .feature-group { | |
| grid-template-columns: 1fr; | |
| } | |
| } | |
| """ | |
| # Create the Gradio interface | |
| with gr.Blocks(css=custom_css, title="AI Website Builder") as demo: | |
| # Header | |
| gr.HTML(""" | |
| <div class="header"> | |
| <h1>🚀 AI Website Builder</h1> | |
| <p>Create stunning websites instantly with Claude Sonnet 4.5</p> | |
| <p><a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" style="color: white; text-decoration: underline;">Built with anycoder</a></p> | |
| </div> | |
| """) | |
| with gr.Row(): | |
| # Left column - Generator controls | |
| with gr.Column(scale=1): | |
| with gr.Box(elem_classes=["generator-section"]): | |
| gr.Markdown("## 📝 Website Description") | |
| description = gr.Textbox( | |
| label="Describe your website", | |
| placeholder="e.g., A modern portfolio website for a web developer with projects, about section, and contact form", | |
| lines=4, | |
| max_lines=6 | |
| ) | |
| gr.Markdown("## 🎨 Style Preference") | |
| style = gr.Dropdown( | |
| choices=[ | |
| "Modern & Minimalist", | |
| "Corporate & Professional", | |
| "Creative & Colorful", | |
| "Dark & Moody", | |
| "Elegant & Sophisticated", | |
| "Playful & Fun", | |
| "Tech & Futuristic", | |
| "Nature & Organic" | |
| ], | |
| value="Modern & Minimalist", | |
| label="Choose a style" | |
| ) | |
| gr.Markdown("## ✨ Features") | |
| with gr.Row(elem_classes=["feature-group"]): | |
| with gr.Column(): | |
| responsive = gr.Checkbox(label="📱 Responsive Design", value=True) | |
| animations = gr.Checkbox(label="🎬 Animations", value=True) | |
| navbar = gr.Checkbox(label="🧭 Navigation Bar", value=True) | |
| with gr.Column(): | |
| footer = gr.Checkbox(label="📄 Footer", value=True) | |
| social = gr.Checkbox(label="🔗 Social Links", value=False) | |
| contact = gr.Checkbox(label="📧 Contact Form", value=False) | |
| with gr.Column(): | |
| gallery = gr.Checkbox(label="🖼️ Image Gallery", value=False) | |
| blog = gr.Checkbox(label="📝 Blog Section", value=False) | |
| dark_mode = gr.Checkbox(label="🌙 Dark Mode Toggle", value=False) | |
| features = [responsive, animations, navbar, footer, social, contact, gallery, blog, dark_mode] | |
| generate_btn = gr.Button( | |
| "🚀 Generate Website", | |
| variant="primary", | |
| size="lg", | |
| elem_classes=["generate-btn"] | |
| ) | |
| # Right column - Preview and Code | |
| with gr.Column(scale=2): | |
| with gr.Tabs(elem_classes=["tabs"]) as tabs: | |
| with gr.TabItem("🖥️ Live Preview"): | |
| with gr.Box(elem_classes=["preview-section"]): | |
| preview = gr.HTML( | |
| value='<div style="padding: 3rem; text-align: center; color: #666;">Your website preview will appear here after generation</div>', | |
| label="Preview" | |
| ) | |
| with gr.TabItem("💻 Code Editor"): | |
| with gr.Tabs(): | |
| with gr.TabItem("HTML"): | |
| html_code = gr.Code( | |
| language="html", | |
| label="HTML Code", | |
| elem_classes=["code-editor"], | |
| lines=20 | |
| ) | |
| with gr.TabItem("CSS"): | |
| css_code = gr.Code( | |
| language="css", | |
| label="CSS Code", | |
| elem_classes=["code-editor"], | |
| lines=20 | |
| ) | |
| with gr.TabItem("JavaScript"): | |
| js_code = gr.Code( | |
| language="javascript", | |
| label="JavaScript Code", | |
| elem_classes=["code-editor"], | |
| lines=20 | |
| ) | |
| with gr.TabItem("⬇️ Download"): | |
| gr.Markdown("### 📦 Download Your Website") | |
| gr.Markdown("Click the button below to download a complete ZIP file with all website assets.") | |
| download_btn = gr.DownloadButton( | |
| "📥 Download Website", | |
| variant="primary", | |
| size="lg" | |
| ) | |
| gr.Markdown(""" | |
| **What's included:** | |
| - `index.html` - Main HTML file | |
| - `styles.css` - Complete stylesheet | |
| - `script.js` - JavaScript functionality | |
| - `README.md` - Documentation | |
| """) | |
| # Store generated website data | |
| website_state = gr.State({"html": "", "css": "", "js": ""}) | |
| # Event handlers | |
| def generate_and_update(desc, style_choice, *feature_flags): | |
| """Generate website and update all components""" | |
| if not desc.strip(): | |
| return ( | |
| '<div style="padding: 3rem; text-align: center; color: #e74c3c;">Please enter a website description</div>', | |
| "", | |
| "", | |
| "", | |
| None, | |
| {"html": "", "css": "", "js": ""} | |
| ) | |
| # Filter selected features | |
| selected_features = [] | |
| feature_names = [ | |
| "Responsive Design", "Animations", "Navigation Bar", | |
| "Footer", "Social Links", "Contact Form", | |
| "Image Gallery", "Blog Section", "Dark Mode Toggle" | |
| ] | |
| for i, flag in enumerate(feature_flags): | |
| if flag: | |
| selected_features.append(feature_names[i]) | |
| # Generate website | |
| html, css, js = generate_website(desc, style_choice, selected_features) | |
| # Create preview | |
| preview_html = create_preview(html, css, js) | |
| # Create download file | |
| zip_file = download_website(html, css, js) | |
| return ( | |
| preview_html, | |
| html, | |
| css, | |
| js, | |
| zip_file, | |
| {"html": html, "css": css, "js": js} | |
| ) | |
| # Wire up the generate button | |
| generate_btn.click( | |
| fn=generate_and_update, | |
| inputs=[description, style] + features, | |
| outputs=[ | |
| preview, | |
| html_code, | |
| css_code, | |
| js_code, | |
| download_btn, | |
| website_state | |
| ] | |
| ) | |
| # Add example descriptions | |
| gr.Examples( | |
| examples=[ | |
| [ | |
| "A professional portfolio website for a UX designer showcasing their best projects with case studies, testimonials, and contact information", | |
| "Modern & Minimalist", | |
| [True, True, True, True, False, True, False, False, False] | |
| ], | |
| [ | |
| "A vibrant restaurant website with menu, online reservations, gallery of dishes, and location map", | |
| "Creative & Colorful", | |
| [True, True, True, True, True, True, True, False, False] | |
| ], | |
| [ | |
| "A tech startup landing page with features, pricing plans, team section, and signup form", | |
| "Tech & Futuristic", | |
| [True, True, True, True, False, True, False, False, True] | |
| ], | |
| [ | |
| "A photography portfolio with gallery, about section, services offered, and booking form", | |
| "Elegant & Sophisticated", | |
| [True, True, True, True, True, True, True, False, False] | |
| ] | |
| ], | |
| inputs=[description, style] + features, | |
| outputs=[preview, html_code, css_code, js_code, download_btn, website_state], | |
| fn=generate_and_update, | |
| cache_examples=False | |
| ) | |
| # Launch the app | |
| if __name__ == "__main__": | |
| demo.launch( | |
| share=False, | |
| show_error=True, | |
| show_api=False | |
| ) |