| import gradio as gr |
| import base64 |
| import io |
| import json |
| from PIL import Image |
| import httpx |
| import html |
| from lzstring import LZString |
| import google.generativeai as genai |
|
|
| |
| DEFAULT_GEMINI_API_KEY = "" |
| DEFAULT_DEEPSEEK_API_KEY = "" |
| DEEPSEEK_BASE_URL = "https://api.deepseek.com" |
|
|
| |
| def analyze_image(image: Image.Image, gemini_api_key: str = "") -> str: |
| """ |
| Analyze an uploaded image and provide a detailed description of its content and layout. |
| |
| Args: |
| image: The PIL Image object to analyze |
| gemini_api_key: Gemini API key for image analysis |
| |
| Returns: |
| A detailed description of the image content, layout, and website type |
| """ |
| if image is None: |
| return "Error: No image provided" |
| |
| |
| api_key = gemini_api_key.strip() if gemini_api_key.strip() else DEFAULT_GEMINI_API_KEY |
| |
| if not api_key: |
| return "Error: Gemini API key not provided" |
| |
| try: |
| |
| genai.configure(api_key=api_key) |
| |
| |
| buffered = io.BytesIO() |
| image.save(buffered, format="PNG") |
| img_str = base64.b64encode(buffered.getvalue()).decode("utf-8") |
| |
| |
| model = genai.GenerativeModel(model_name="gemini-2.5-flash-preview-05-20") |
| prompt = """ |
| Analyze this image and provide a concise description. |
| Describe the main elements, colors, layout, and UI components. |
| Identify what type of website or application this resembles. |
| Focus on structural and visual elements that would be important for recreating the design. |
| """ |
| |
| image_part = {"mime_type": "image/png", "data": img_str} |
| contents = [prompt, image_part] |
| |
| |
| response = model.generate_content(contents) |
| return response.text |
| |
| except Exception as e: |
| return f"Error analyzing image: {str(e)}" |
|
|
| def generate_html_code(description: str, deepseek_api_key: str = "") -> str: |
| """ |
| Generate HTML/CSS/JavaScript code based on a website description. |
| |
| Args: |
| description: Detailed description of the website to generate |
| deepseek_api_key: DeepSeek API key for code generation |
| |
| Returns: |
| Complete HTML code with embedded CSS and JavaScript |
| """ |
| if not description or description.startswith("Error"): |
| return "Error: Invalid or missing description" |
| |
| |
| api_key = deepseek_api_key.strip() if deepseek_api_key.strip() else DEFAULT_DEEPSEEK_API_KEY |
| |
| if not api_key: |
| return "Error: DeepSeek API key not provided" |
| |
| prompt = f""" |
| Generate a complete, responsive webpage based on this description: |
| |
| {description} |
| |
| Requirements: |
| - Use modern HTML5, CSS3, and vanilla JavaScript only |
| - Include TailwindCSS via CDN for styling |
| - Make it responsive and visually appealing |
| - Use placeholder images from https://unsplash.com/ if needed |
| - Include proper semantic HTML structure |
| - Add interactive elements where appropriate |
| - Ensure the design matches the described layout and style |
| |
| Return only the complete HTML code starting with <!DOCTYPE html> and ending with </html>. |
| """ |
| |
| headers = { |
| "Authorization": f"Bearer {api_key}", |
| "Content-Type": "application/json" |
| } |
| |
| data = { |
| "model": "deepseek-chat", |
| "messages": [{"role": "user", "content": prompt}], |
| "temperature": 0.7, |
| "max_tokens": 8000 |
| } |
| |
| try: |
| import requests |
| response = requests.post( |
| f"{DEEPSEEK_BASE_URL}/chat/completions", |
| headers=headers, |
| json=data, |
| timeout=60 |
| ) |
| |
| if response.status_code == 200: |
| result = response.json() |
| html_code = result['choices'][0]['message']['content'] |
| |
| |
| if html_code.strip().startswith("```html"): |
| html_code = html_code.split("```html", 1)[1].strip() |
| if html_code.strip().endswith("```"): |
| html_code = html_code.rsplit("```", 1)[0].strip() |
| |
| |
| if "<!DOCTYPE html>" in html_code and "</html>" in html_code: |
| start = html_code.find("<!DOCTYPE html>") |
| end = html_code.rfind("</html>") + 7 |
| return html_code[start:end] |
| else: |
| return html_code |
| else: |
| return f"Error: API request failed with status {response.status_code}" |
| |
| except Exception as e: |
| return f"Error generating HTML code: {str(e)}" |
|
|
| def create_codesandbox(html_code: str) -> str: |
| """ |
| Create a CodeSandbox project from HTML code. |
| |
| Args: |
| html_code: Complete HTML code to upload to CodeSandbox |
| |
| Returns: |
| CodeSandbox URL or error message |
| """ |
| if not html_code or html_code.startswith("Error"): |
| return "Error: No valid HTML code provided" |
| |
| try: |
| |
| files = { |
| "index.html": { |
| "content": html_code, |
| "isBinary": False |
| }, |
| "package.json": { |
| "content": json.dumps({ |
| "name": "ai-generated-website", |
| "version": "1.0.0", |
| "description": "Website generated from image analysis", |
| "main": "index.html", |
| "scripts": { |
| "start": "serve .", |
| "build": "echo 'No build required'" |
| }, |
| "devDependencies": { |
| "serve": "^14.0.0" |
| } |
| }, indent=2), |
| "isBinary": False |
| } |
| } |
| |
| |
| parameters = { |
| "files": files, |
| "template": "static" |
| } |
| |
| |
| json_str = json.dumps(parameters, separators=(',', ':')) |
| lz = LZString() |
| compressed = lz.compressToBase64(json_str) |
| compressed = compressed.replace('+', '-').replace('/', '_').rstrip('=') |
| |
| |
| codesandbox_url = f"https://codesandbox.io/api/v1/sandboxes/define?parameters={compressed}" |
| |
| |
| import requests |
| response = requests.post(codesandbox_url, timeout=30) |
| |
| if response.status_code == 200: |
| result = response.json() |
| sandbox_id = result.get("sandbox_id") |
| if sandbox_id: |
| return f"https://codesandbox.io/s/{sandbox_id}" |
| |
| |
| return codesandbox_url |
| |
| except Exception as e: |
| return f"Error creating CodeSandbox: {str(e)}" |
|
|
| def screenshot_to_code(image: Image.Image, gemini_api_key: str = "", deepseek_api_key: str = "") -> tuple: |
| """ |
| Complete pipeline: analyze image and generate corresponding HTML code. |
| |
| Args: |
| image: Screenshot image to analyze |
| gemini_api_key: Gemini API key for image analysis |
| deepseek_api_key: DeepSeek API key for code generation |
| |
| Returns: |
| Tuple of (description, html_code) |
| """ |
| |
| description = analyze_image(image, gemini_api_key) |
| |
| if description.startswith("Error"): |
| return description, "Error: Cannot generate code due to image analysis failure" |
| |
| |
| html_code = generate_html_code(description, deepseek_api_key) |
| |
| return description, html_code |
|
|
| |
| with gr.Blocks( |
| theme=gr.themes.Soft(), |
| title="AI Website Generator - MCP Compatible", |
| css=""" |
| .api-section { background: #f8f9fa; padding: 15px; border-radius: 8px; margin: 10px 0; } |
| .tool-section { border: 1px solid #e0e0e0; padding: 15px; border-radius: 8px; margin: 10px 0; } |
| """ |
| ) as app: |
| |
| gr.Markdown(""" |
| # 🚀 AI Website Generator (MCP Compatible) |
| |
| Transform website screenshots into functional HTML code using AI. |
| |
| **Features:** |
| - 📸 Image analysis with Gemini AI |
| - 💻 HTML/CSS/JS code generation with DeepSeek |
| - 🌐 Direct CodeSandbox deployment |
| - 🔧 MCP (Model Context Protocol) compatible |
| |
| **Tools Available:** |
| - `analyze_image`: Analyze website screenshots |
| - `generate_html_code`: Generate HTML from descriptions |
| - `create_codesandbox`: Deploy to CodeSandbox |
| - `screenshot_to_code`: Complete pipeline |
| """) |
| |
| with gr.Tab("🎯 Quick Generate"): |
| with gr.Row(): |
| with gr.Column(scale=1): |
| gr.Markdown("### 📤 Input", elem_classes=["tool-section"]) |
| |
| |
| with gr.Group(): |
| gr.Markdown("**API Keys (Optional)**") |
| gemini_key = gr.Textbox( |
| label="Gemini API Key", |
| type="password", |
| placeholder="Leave empty to use default", |
| value="" |
| ) |
| deepseek_key = gr.Textbox( |
| label="DeepSeek API Key", |
| type="password", |
| placeholder="Leave empty to use default", |
| value="" |
| ) |
| |
| |
| image_input = gr.Image( |
| type="pil", |
| label="Upload Website Screenshot", |
| sources=["upload", "clipboard"] |
| ) |
| |
| generate_btn = gr.Button( |
| "🎨 Generate Website", |
| variant="primary", |
| size="lg" |
| ) |
| |
| with gr.Column(scale=2): |
| gr.Markdown("### 📋 Results", elem_classes=["tool-section"]) |
| |
| description_output = gr.Textbox( |
| label="📝 Image Analysis", |
| lines=6, |
| interactive=False |
| ) |
| |
| html_output = gr.Code( |
| label="💻 Generated HTML Code", |
| language="html", |
| lines=15 |
| ) |
| |
| with gr.Row(): |
| codesandbox_btn = gr.Button("🚀 Deploy to CodeSandbox") |
| codesandbox_output = gr.Textbox( |
| label="CodeSandbox URL", |
| interactive=False |
| ) |
| |
| with gr.Tab("🔧 Individual Tools"): |
| gr.Markdown("### Use individual MCP tools") |
| |
| with gr.Row(): |
| with gr.Column(): |
| gr.Markdown("#### 📸 Image Analysis Tool") |
| img_tool = gr.Image(type="pil", label="Image") |
| gemini_key_tool = gr.Textbox(label="Gemini API Key", type="password") |
| analyze_btn = gr.Button("Analyze Image") |
| analysis_result = gr.Textbox(label="Analysis Result", lines=5) |
| |
| with gr.Column(): |
| gr.Markdown("#### 💻 Code Generation Tool") |
| desc_input = gr.Textbox(label="Description", lines=3) |
| deepseek_key_tool = gr.Textbox(label="DeepSeek API Key", type="password") |
| code_btn = gr.Button("Generate Code") |
| code_result = gr.Code(label="Generated Code", language="html") |
| |
| |
| generate_btn.click( |
| fn=screenshot_to_code, |
| inputs=[image_input, gemini_key, deepseek_key], |
| outputs=[description_output, html_output] |
| ) |
| |
| codesandbox_btn.click( |
| fn=create_codesandbox, |
| inputs=[html_output], |
| outputs=[codesandbox_output] |
| ) |
| |
| analyze_btn.click( |
| fn=analyze_image, |
| inputs=[img_tool, gemini_key_tool], |
| outputs=[analysis_result] |
| ) |
| |
| code_btn.click( |
| fn=generate_html_code, |
| inputs=[desc_input, deepseek_key_tool], |
| outputs=[code_result] |
| ) |
| |
| |
| gr.Examples( |
| examples=[["1.jpg"]], |
| inputs=[image_input], |
| label="📷 Example Screenshots" |
| ) |
|
|
| if __name__ == "__main__": |
| app.launch(mcp_server=True, share=False) |