File size: 3,579 Bytes
547c16c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import time
import base64
import io
from PIL import Image
from bs4 import BeautifulSoup
from langchain_google_genai import ChatGoogleGenerativeAI
from langchain_core.messages import HumanMessage

def resize_and_encode_image(image_file, max_size=(400, 400)):
    img = Image.open(image_file)
    img.thumbnail(max_size)
    buffered = io.BytesIO()
    img.save(buffered, format="JPEG")
    image_bytes = buffered.getvalue()
    base64_str = base64.b64encode(image_bytes).decode("utf-8")
    return f"data:image/jpeg;base64,{base64_str}"

def beautify_html(html_code):
    soup = BeautifulSoup(html_code, "html.parser")
    return soup.prettify()

def generate_html_css_from_image(image_file):
    image_data_url = resize_and_encode_image(image_file)

    prompt_text = """
You are an expert front-end developer.

The input is a screenshot of a website UI. Carefully analyze its layout and generate accurate, semantic, and maintainable HTML and CSS.

Follow these professional guidelines:

1) Structure & Semantics:
- Use HTML5 semantic tags that match the visual hierarchy (e.g., <header>, <nav>, <main>, <section>, <article>, <aside>, <footer>)
- Reflect layout grouping using appropriate containers and divs where needed

2) Layout & Responsiveness:
- Use Flexbox or CSS Grid for layout
- Include responsive breakpoints (mobile-first) with at least one media query
- Ensure layout adapts well to mobile screen sizes

3) CSS Practices:
- Keep CSS in a <style> block or separate file (no inline styles)
- Use class names that follow a clean naming convention (e.g., BEM or descriptive naming)
- Group CSS rules logically (layout, typography, components)

4) Accessibility & UX:
- Add accessible markup: alt text, ARIA roles, labels
- Ensure good contrast and keyboard navigability

5) Content & Comments:
- Use meaningful placeholder text (not lorem ipsum)
- Add short code comments to explain each major section

6) Output:
- The output should be a complete single HTML file with embedded CSS
- Preserve the visual structure and content flow of the original screenshot as closely as possible
- Do not skip or summarize any sections

Assume this is for real production-ready front-end code generation from a web UI screenshot.
"""

    prompt = [
        HumanMessage(
            content=[
                {"type": "text", "text": prompt_text},
                {"type": "image_url", "image_url": {"url": image_data_url, "mime_type": "image/jpeg"}}
            ]
        )
    ]

    llm = ChatGoogleGenerativeAI(model="gemini-2.5-flash", temperature=0)
    max_retries = 3
    generated_code = None

    for attempt in range(max_retries):
        try:
            response = llm.invoke(prompt)
            generated_code = response.content
            break
        except Exception as e:
            if "ResourceExhausted" in str(e) or "429" in str(e):
                time.sleep(30 * (attempt + 1))
            else:
                raise e

    if generated_code:
        soup = BeautifulSoup(generated_code, "html.parser")
        style_tag = soup.find("style")
        css_code = style_tag.string if style_tag else ""
        html_without_style = str(soup).replace(str(style_tag), "") if style_tag else str(soup)

        cleaned_html = beautify_html(html_without_style)

        final_output = f"""<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
{css_code}
</style>
</head>
{cleaned_html.split("</head>")[1]}
</html>"""

        return final_output
    else:
        return None