Spaces:
Running
Running
| import gradio as gr | |
| import base64 | |
| import io | |
| import json | |
| from PIL import Image | |
| import httpx | |
| import html | |
| from lzstring import LZString | |
| import os | |
| from openai import OpenAI | |
| # --- ้ป่ฎคAPI้ ็ฝฎ --- | |
| DEFAULT_NEBIUS_API_KEY = "eyJhbGciOiJIUzI1NiIsImtpZCI6IlV6SXJWd1h0dnprLVRvdzlLZWstc0M1akptWXBvX1VaVkxUZlpnMDRlOFUiLCJ0eXAiOiJKV1QifQ.eyJzdWIiOiJnb29nbGUtb2F1dGgyfDEwNTA1MTQzMDg2MDMwMzIxNDEwMiIsInNjb3BlIjoib3BlbmlkIG9mZmxpbmVfYWNjZXNzIiwiaXNzIjoiYXBpX2tleV9pc3N1ZXIiLCJhdWQiOlsiaHR0cHM6Ly9uZWJpdXMtaW5mZXJlbmNlLmV1LmF1dGgwLmNvbS9hcGkvdjIvIl0sImV4cCI6MTkwNjU5ODA0NCwidXVpZCI6ImNkOGFiMWZlLTIxN2QtNDJlMy04OWUwLWM1YTg4MjcwMGVhNyIsIm5hbWUiOiJodW5nZ2luZyIsImV4cGlyZXNfYXQiOiIyMDMwLTA2LTAyVDAyOjM0OjA0KzAwMDAifQ.MA52QuIiNruK7_lX688RXAEI2TkcCOjcf_02XrpnhI8" | |
| NEBIUS_BASE_URL = "https://api.studio.nebius.com/v1/" | |
| # --- ๆ ธๅฟๅทฅๅ ทๅฝๆฐ --- | |
| def analyze_image(image: Image.Image, nebius_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 | |
| nebius_api_key: Nebius 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ๅฏ้ฅๆ้ป่ฎคๅฏ้ฅ | |
| api_key = nebius_api_key.strip() if nebius_api_key.strip() else DEFAULT_NEBIUS_API_KEY | |
| if not api_key: | |
| return "Error: Nebius API key not provided" | |
| try: | |
| # ้ ็ฝฎNebius OpenAIๅฎขๆท็ซฏ | |
| client = OpenAI( | |
| base_url=NEBIUS_BASE_URL, | |
| api_key=api_key, | |
| ) | |
| # ่ฝฌๆขๅพ็ไธบbase64 | |
| buffered = io.BytesIO() | |
| image.save(buffered, format="PNG") | |
| img_str = base64.b64encode(buffered.getvalue()).decode("utf-8") | |
| # ๅๅปบๆ็คบ | |
| 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. | |
| """ | |
| # ไฝฟ็จQwen2.5-VL-72B-Instructๆจกๅ่ฟ่กๅพๅๅๆ | |
| response = client.chat.completions.create( | |
| model="Qwen/Qwen2.5-VL-72B-Instruct", | |
| messages=[ | |
| { | |
| "role": "user", | |
| "content": [ | |
| {"type": "text", "text": prompt}, | |
| { | |
| "type": "image_url", | |
| "image_url": { | |
| "url": f"data:image/png;base64,{img_str}" | |
| } | |
| } | |
| ] | |
| } | |
| ], | |
| max_tokens=1000, | |
| temperature=0.7 | |
| ) | |
| return response.choices[0].message.content | |
| except Exception as e: | |
| return f"Error analyzing image: {str(e)}" | |
| def generate_html_code(description: str, nebius_api_key: str = "") -> str: | |
| """ | |
| Generate HTML/CSS/JavaScript code based on a website description. | |
| Args: | |
| description: Detailed description of the website to generate | |
| nebius_api_key: Nebius 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ๅฏ้ฅๆ้ป่ฎคๅฏ้ฅ | |
| api_key = nebius_api_key.strip() if nebius_api_key.strip() else DEFAULT_NEBIUS_API_KEY | |
| if not api_key: | |
| return "Error: Nebius 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>. | |
| """ | |
| try: | |
| # ้ ็ฝฎNebius OpenAIๅฎขๆท็ซฏ | |
| client = OpenAI( | |
| base_url=NEBIUS_BASE_URL, | |
| api_key=api_key, | |
| ) | |
| # ไฝฟ็จDeepSeek-V3-0324ๆจกๅ่ฟ่กไปฃ็ ็ๆ | |
| response = client.chat.completions.create( | |
| model="deepseek-ai/DeepSeek-V3-0324", | |
| messages=[ | |
| {"role": "user", "content": prompt} | |
| ], | |
| max_tokens=8000, | |
| temperature=0.7 | |
| ) | |
| html_code = response.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 | |
| 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('=') | |
| # ็ๆURL | |
| codesandbox_url = f"https://codesandbox.io/api/v1/sandboxes/define?parameters={compressed}" | |
| # ๅฐ่ฏๅๅปบsandbox | |
| import requests | |
| # ๅฐ่ฏPOST่ฏทๆฑๅๅปบsandbox | |
| try: | |
| response = requests.post( | |
| "https://codesandbox.io/api/v1/sandboxes/define", | |
| json=parameters, | |
| timeout=10 | |
| ) | |
| except: | |
| # ๅฆๆPOSTๅคฑ่ดฅ๏ผ่ฟๅGET URL | |
| return codesandbox_url | |
| 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}" | |
| # ๅฆๆPOSTๅคฑ่ดฅ๏ผ่ฟๅGET URL | |
| return codesandbox_url | |
| except Exception as e: | |
| return f"Error creating CodeSandbox: {str(e)}" | |
| def screenshot_to_code(image: Image.Image, nebius_api_key: str = "") -> tuple: | |
| """ | |
| Complete pipeline: analyze image and generate corresponding HTML code. | |
| Args: | |
| image: Screenshot image to analyze | |
| nebius_api_key: Nebius API key for both image analysis and code generation | |
| Returns: | |
| Tuple of (description, html_code) | |
| """ | |
| # ๅๆๅพ็ | |
| description = analyze_image(image, nebius_api_key) | |
| if description.startswith("Error"): | |
| return description, "Error: Cannot generate code due to image analysis failure" | |
| # ็ๆไปฃ็ | |
| html_code = generate_html_code(description, nebius_api_key) | |
| return description, html_code | |
| # --- Gradio็้ข --- | |
| with gr.Blocks( | |
| theme=gr.themes.Soft(), | |
| title="AI Website Generator - MCP Compatible (Nebius)", | |
| 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 - Nebius) | |
| Transform website screenshots into functional HTML code using Nebius AI. | |
| **Features:** | |
| - ๐ธ Image analysis with Qwen2.5-VL-72B-Instruct | |
| - ๐ป HTML/CSS/JS code generation with DeepSeek-V3-0324 | |
| - ๐ 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"]) | |
| # API้ ็ฝฎ | |
| with gr.Group(): | |
| gr.Markdown("**Nebius API Key (Required)**") | |
| nebius_key = gr.Textbox( | |
| label="Nebius API Key", | |
| type="password", | |
| placeholder="Enter your Nebius API key", | |
| 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") | |
| nebius_key_tool = gr.Textbox(label="Nebius 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) | |
| nebius_key_tool2 = gr.Textbox(label="Nebius 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, nebius_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, nebius_key_tool], | |
| outputs=[analysis_result] | |
| ) | |
| code_btn.click( | |
| fn=generate_html_code, | |
| inputs=[desc_input, nebius_key_tool2], | |
| outputs=[code_result] | |
| ) | |
| # ็คบไพ | |
| gr.Examples( | |
| examples=[["1.jpg"]], | |
| inputs=[image_input], | |
| label="๐ท Example Screenshots" | |
| ) | |
| if __name__ == "__main__": | |
| app.launch(mcp_server=True, share=False) |