CoolFace
Apppublic

Agents-MCP-Hackathon/Website_Generator

sourceHugging Facemitupdated 1y agoView on Hugging Face
19likes
app.py386 linesDownload Raw Back to root
1import gradio as gr2import base643import io4import json5from PIL import Image6import httpx7import html8from lzstring import LZString9import os10from openai import OpenAI11 12# --- 默认API配置 ---13DEFAULT_NEBIUS_API_KEY = "eyJhbGciOiJIUzI1NiIsImtpZCI6IlV6SXJWd1h0dnprLVRvdzlLZWstc0M1akptWXBvX1VaVkxUZlpnMDRlOFUiLCJ0eXAiOiJKV1QifQ.eyJzdWIiOiJnb29nbGUtb2F1dGgyfDEwNTA1MTQzMDg2MDMwMzIxNDEwMiIsInNjb3BlIjoib3BlbmlkIG9mZmxpbmVfYWNjZXNzIiwiaXNzIjoiYXBpX2tleV9pc3N1ZXIiLCJhdWQiOlsiaHR0cHM6Ly9uZWJpdXMtaW5mZXJlbmNlLmV1LmF1dGgwLmNvbS9hcGkvdjIvIl0sImV4cCI6MTkwNjU5ODA0NCwidXVpZCI6ImNkOGFiMWZlLTIxN2QtNDJlMy04OWUwLWM1YTg4MjcwMGVhNyIsIm5hbWUiOiJodW5nZ2luZyIsImV4cGlyZXNfYXQiOiIyMDMwLTA2LTAyVDAyOjM0OjA0KzAwMDAifQ.MA52QuIiNruK7_lX688RXAEI2TkcCOjcf_02XrpnhI8"14NEBIUS_BASE_URL = "https://api.studio.nebius.com/v1/"15 16# --- 核心工具函数 ---17def analyze_image(image: Image.Image, nebius_api_key: str = "") -> str:18    """19    Analyze an uploaded image and provide a detailed description of its content and layout.20    21    Args:22        image: The PIL Image object to analyze23        nebius_api_key: Nebius API key for image analysis24        25    Returns:26        A detailed description of the image content, layout, and website type27    """28    if image is None:29        return "Error: No image provided"30    31    # 使用提供的API密钥或默认密钥32    api_key = nebius_api_key.strip() if nebius_api_key.strip() else DEFAULT_NEBIUS_API_KEY33    34    if not api_key:35        return "Error: Nebius API key not provided"36    37    try:38        # 配置Nebius OpenAI客户端39        client = OpenAI(40            base_url=NEBIUS_BASE_URL,41            api_key=api_key,42        )43        44        # 转换图片为base6445        buffered = io.BytesIO()46        image.save(buffered, format="PNG")47        img_str = base64.b64encode(buffered.getvalue()).decode("utf-8")48        49        # 创建提示50        prompt = """51        Analyze this image and provide a concise description.52        Describe the main elements, colors, layout, and UI components.53        Identify what type of website or application this resembles.54        Focus on structural and visual elements that would be important for recreating the design.55        """56        57        # 使用Qwen2.5-VL-72B-Instruct模型进行图像分析58        response = client.chat.completions.create(59            model="Qwen/Qwen2.5-VL-72B-Instruct",60            messages=[61                {62                    "role": "user",63                    "content": [64                        {"type": "text", "text": prompt},65                        {66                            "type": "image_url",67                            "image_url": {68                                "url": f"data:image/png;base64,{img_str}"69                            }70                        }71                    ]72                }73            ],74            max_tokens=1000,75            temperature=0.776        )77        78        return response.choices[0].message.content79        80    except Exception as e:81        return f"Error analyzing image: {str(e)}"82 83def generate_html_code(description: str, nebius_api_key: str = "") -> str:84    """85    Generate HTML/CSS/JavaScript code based on a website description.86    87    Args:88        description: Detailed description of the website to generate89        nebius_api_key: Nebius API key for code generation90        91    Returns:92        Complete HTML code with embedded CSS and JavaScript93    """94    if not description or description.startswith("Error"):95        return "Error: Invalid or missing description"96    97    # 使用提供的API密钥或默认密钥98    api_key = nebius_api_key.strip() if nebius_api_key.strip() else DEFAULT_NEBIUS_API_KEY99    100    if not api_key:101        return "Error: Nebius API key not provided"102    103    prompt = f"""104    Generate a complete, responsive webpage based on this description:105    106    {description}107    108    Requirements:109    - Use modern HTML5, CSS3, and vanilla JavaScript only110    - Include TailwindCSS via CDN for styling111    - Make it responsive and visually appealing112    - Use placeholder images from https://unsplash.com/ if needed113    - Include proper semantic HTML structure114    - Add interactive elements where appropriate115    - Ensure the design matches the described layout and style116    117    Return only the complete HTML code starting with <!DOCTYPE html> and ending with </html>.118    """119    120    try:121        # 配置Nebius OpenAI客户端122        client = OpenAI(123            base_url=NEBIUS_BASE_URL,124            api_key=api_key,125        )126        127        # 使用DeepSeek-V3-0324模型进行代码生成128        response = client.chat.completions.create(129            model="deepseek-ai/DeepSeek-V3-0324",130            messages=[131                {"role": "user", "content": prompt}132            ],133            max_tokens=8000,134            temperature=0.7135        )136        137        html_code = response.choices[0].message.content138        139        # 清理代码格式140        if html_code.strip().startswith("```html"):141            html_code = html_code.split("```html", 1)[1].strip()142        if html_code.strip().endswith("```"):143            html_code = html_code.rsplit("```", 1)[0].strip()144        145        # 确保代码完整性146        if "<!DOCTYPE html>" in html_code and "</html>" in html_code:147            start = html_code.find("<!DOCTYPE html>")148            end = html_code.rfind("</html>") + 7149            return html_code[start:end]150        else:151            return html_code152            153    except Exception as e:154        return f"Error generating HTML code: {str(e)}"155 156def create_codesandbox(html_code: str) -> str:157    """158    Create a CodeSandbox project from HTML code.159    160    Args:161        html_code: Complete HTML code to upload to CodeSandbox162        163    Returns:164        CodeSandbox URL or error message165    """166    if not html_code or html_code.startswith("Error"):167        return "Error: No valid HTML code provided"168    169    try:170        # 准备文件结构171        files = {172            "index.html": {173                "content": html_code,174                "isBinary": False175            },176            "package.json": {177                "content": json.dumps({178                    "name": "ai-generated-website",179                    "version": "1.0.0",180                    "description": "Website generated from image analysis",181                    "main": "index.html",182                    "scripts": {183                        "start": "serve .",184                        "build": "echo 'No build required'"185                    },186                    "devDependencies": {187                        "serve": "^14.0.0"188                    }189                }, indent=2),190                "isBinary": False191            }192        }193        194        # 准备参数195        parameters = {196            "files": files,197            "template": "static"198        }199        200        # 压缩数据201        json_str = json.dumps(parameters, separators=(',', ':'))202        lz = LZString()203        compressed = lz.compressToBase64(json_str)204        compressed = compressed.replace('+', '-').replace('/', '_').rstrip('=')205        206        # 生成URL207        codesandbox_url = f"https://codesandbox.io/api/v1/sandboxes/define?parameters={compressed}"208        209        # 尝试创建sandbox210        import requests211        212        # 尝试POST请求创建sandbox213        try:214            response = requests.post(215                "https://codesandbox.io/api/v1/sandboxes/define",216                json=parameters,217                timeout=10218            )219        except:220            # 如果POST失败,返回GET URL221            return codesandbox_url222        223        if response.status_code == 200:224            result = response.json()225            sandbox_id = result.get("sandbox_id")226            if sandbox_id:227                return f"https://codesandbox.io/s/{sandbox_id}"228        229        # 如果POST失败,返回GET URL230        return codesandbox_url231        232    except Exception as e:233        return f"Error creating CodeSandbox: {str(e)}"234 235def screenshot_to_code(image: Image.Image, nebius_api_key: str = "") -> tuple:236    """237    Complete pipeline: analyze image and generate corresponding HTML code.238    239    Args:240        image: Screenshot image to analyze241        nebius_api_key: Nebius API key for both image analysis and code generation242        243    Returns:244        Tuple of (description, html_code)245    """246    # 分析图片247    description = analyze_image(image, nebius_api_key)248    249    if description.startswith("Error"):250        return description, "Error: Cannot generate code due to image analysis failure"251    252    # 生成代码253    html_code = generate_html_code(description, nebius_api_key)254    255    return description, html_code256 257# --- Gradio界面 ---258with gr.Blocks(259    theme=gr.themes.Soft(),260    title="AI Website Generator - MCP Compatible (Nebius)",261    css="""262    .api-section { background: #f8f9fa; padding: 15px; border-radius: 8px; margin: 10px 0; }263    .tool-section { border: 1px solid #e0e0e0; padding: 15px; border-radius: 8px; margin: 10px 0; }264    """265) as app:266    267    gr.Markdown("""268    # 🚀 AI Website Generator (MCP Compatible - Nebius)269    270    Transform website screenshots into functional HTML code using Nebius AI.271    272    **Features:**273    - 📸 Image analysis with Qwen2.5-VL-72B-Instruct274    - 💻 HTML/CSS/JS code generation with DeepSeek-V3-0324275    - 🌐 Direct CodeSandbox deployment276    - 🔧 MCP (Model Context Protocol) compatible277    278    **Tools Available:**279    - `analyze_image`: Analyze website screenshots280    - `generate_html_code`: Generate HTML from descriptions281    - `create_codesandbox`: Deploy to CodeSandbox282    - `screenshot_to_code`: Complete pipeline283    """)284    285    with gr.Tab("🎯 Quick Generate"):286        with gr.Row():287            with gr.Column(scale=1):288                gr.Markdown("### 📤 Input", elem_classes=["tool-section"])289                290                # API配置291                with gr.Group():292                    gr.Markdown("**Nebius API Key (Required)**")293                    nebius_key = gr.Textbox(294                        label="Nebius API Key",295                        type="password",296                        placeholder="Enter your Nebius API key",297                        value=DEFAULT_NEBIUS_API_KEY298                    )299                300                # 图片上传301                image_input = gr.Image(302                    type="pil",303                    label="Upload Website Screenshot",304                    sources=["upload", "clipboard"]305                )306                307                generate_btn = gr.Button(308                    "🎨 Generate Website",309                    variant="primary",310                    size="lg"311                )312            313            with gr.Column(scale=2):314                gr.Markdown("### 📋 Results", elem_classes=["tool-section"])315                316                description_output = gr.Textbox(317                    label="📝 Image Analysis",318                    lines=6,319                    interactive=False320                )321                322                html_output = gr.Code(323                    label="💻 Generated HTML Code",324                    language="html",325                    lines=15326                )327                328                with gr.Row():329                    codesandbox_btn = gr.Button("🚀 Deploy to CodeSandbox")330                    codesandbox_output = gr.Textbox(331                        label="CodeSandbox URL",332                        interactive=False333                    )334    335    with gr.Tab("🔧 Individual Tools"):336        gr.Markdown("### Use individual MCP tools")337        338        with gr.Row():339            with gr.Column():340                gr.Markdown("#### 📸 Image Analysis Tool")341                img_tool = gr.Image(type="pil", label="Image")342                nebius_key_tool = gr.Textbox(label="Nebius API Key", type="password", value=DEFAULT_NEBIUS_API_KEY)343                analyze_btn = gr.Button("Analyze Image")344                analysis_result = gr.Textbox(label="Analysis Result", lines=5)345            346            with gr.Column():347                gr.Markdown("#### 💻 Code Generation Tool")348                desc_input = gr.Textbox(label="Description", lines=3)349                nebius_key_tool2 = gr.Textbox(label="Nebius API Key", type="password", value=DEFAULT_NEBIUS_API_KEY)350                code_btn = gr.Button("Generate Code")351                code_result = gr.Code(label="Generated Code", language="html")352    353    # 事件绑定354    generate_btn.click(355        fn=screenshot_to_code,356        inputs=[image_input, nebius_key],357        outputs=[description_output, html_output]358    )359    360    codesandbox_btn.click(361        fn=create_codesandbox,362        inputs=[html_output],363        outputs=[codesandbox_output]364    )365    366    analyze_btn.click(367        fn=analyze_image,368        inputs=[img_tool, nebius_key_tool],369        outputs=[analysis_result]370    )371    372    code_btn.click(373        fn=generate_html_code,374        inputs=[desc_input, nebius_key_tool2],375        outputs=[code_result]376    )377    378    # 示例379    gr.Examples(380        examples=[["1.jpg"]],381        inputs=[image_input],382        label="📷 Example Screenshots"383    )384 385if __name__ == "__main__":386    app.launch(mcp_server=True, share=False)