File size: 9,123 Bytes
0dbe55a
 
 
 
a51a732
 
 
 
 
 
 
 
 
0dbe55a
 
 
a51a732
 
0dbe55a
 
 
 
 
 
 
a51a732
 
0dbe55a
 
 
 
 
 
a51a732
0dbe55a
 
a51a732
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0dbe55a
 
a51a732
0dbe55a
a51a732
 
 
 
 
 
 
 
 
0dbe55a
a51a732
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0dbe55a
a51a732
 
 
 
0dbe55a
 
 
 
 
a51a732
0dbe55a
 
 
 
 
 
 
 
a51a732
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0dbe55a
 
a51a732
 
 
 
 
 
 
 
0dbe55a
a51a732
 
 
 
 
 
 
 
 
 
0dbe55a
 
 
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
import streamlit as st
import pathlib
from PIL import Image
import google.generativeai as genai
import os # Import os for environment variables

# --- Configuration ---
try:
    # Ensure GOOGLE_API_KEY is set in Streamlit secrets or as an environment variable
    API_KEY = st.secrets["GOOGLE_API_KEY"]
except KeyError:
    st.error("Google API Key not found. Please set it in Streamlit secrets or as an environment variable (`GOOGLE_API_KEY`).")
    st.stop() # Stop the app if API key is missing

genai.configure(api_key=API_KEY)

# Generation configuration for the Gemini model
GENERATION_CONFIG = {
    "temperature": 1,
    "top_p": 0.95,
    "top_k": 64,
    "max_output_tokens": 8192,
    "response_mime_type": "text/plain",
}

# Safety settings for the Gemini model
SAFETY_SETTINGS = [
    {"category": "HARM_CATEGORY_HARASSMENT", "threshold": "BLOCK_NONE"},
    {"category": "HARM_CATEGORY_HATE_SPEECH", "threshold": "BLOCK_NONE"},
    {"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "threshold": "BLOCK_NONE"},
    {"category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_NONE"},
]

# Model name constant
MODEL_NAME = "gemini-1.5-pro-latest"

# --- Model Initialization ---
@st.cache_resource # Cache the model to avoid re-initializing on every rerun
def load_gemini_model():
    """Loads and caches the Google GenerativeModel."""
    return genai.GenerativeModel(
        model_name=MODEL_NAME,
        safety_settings=SAFETY_SETTINGS,
        generation_config=GENERATION_CONFIG,
    )

model = load_gemini_model()

# Initialize chat session in Streamlit's session state
# This ensures the chat history persists across reruns for a single user
if "chat_session" not in st.session_state:
    st.session_state.chat_session = model.start_chat(history=[])

# --- Helper Function for Model Communication ---
def send_message_to_model(message: str, image_path: pathlib.Path) -> str:
    """Sends a message and an image to the Gemini model and returns the response."""
    image_input = {
        'mime_type': 'image/jpeg',
        'data': image_path.read_bytes()
    }
    try:
        response = st.session_state.chat_session.send_message([message, image_input])
        return response.text
    except Exception as e:
        st.error(f"Error communicating with the Gemini model: {e}")
        st.exception(e) # Display full traceback for debugging
        return "An error occurred during AI model communication. Please try again or check your API key."

# --- Streamlit App ---
def main():
    """Main function to run the Streamlit application."""
    st.set_page_config(page_title="Gemini 1.5 Pro: Images to Code", layout="wide") # Set a wider layout
    st.title("Gemini 1.5 Pro: Images to Code 👨‍💻")
    st.markdown('Made with ❤️ by [KhulnaSoft](https://x.com/khulnasoft)')

    st.info("Upload an image of a UI design, and I'll generate the corresponding HTML and CSS code for you!")

    # Framework selection using a selectbox
    framework_options = {
        "Regular CSS (Flexbox/Grid)": "Regular CSS use flex grid etc",
        "Bootstrap": "Bootstrap",
        "Tailwind CSS": "Tailwind CSS",
        "Materialize CSS": "Materialize CSS"
    }
    selected_framework_name = st.selectbox(
        "Choose your preferred CSS framework:",
        options=list(framework_options.keys()),
        help="This will influence the CSS generated within your HTML file."
    )
    framework = framework_options[selected_framework_name]

    uploaded_file = st.file_uploader("Upload a UI image (JPG, JPEG, PNG):", type=["jpg", "jpeg", "png"])

    # temp_image_path is declared outside the try block to ensure it's accessible for cleanup
    temp_image_path = pathlib.Path("temp_image.jpg")

    if uploaded_file is not None:
        try:
            # Load and display the image
            image = Image.open(uploaded_file)
            st.image(image, caption='Uploaded UI Image', use_column_width=True)

            # Convert image to RGB mode if it has an alpha channel
            if image.mode == 'RGBA':
                image = image.convert('RGB')

            # Save the uploaded image temporarily
            image.save(temp_image_path, format="JPEG")

            st.markdown("---") # Visual separator

            # Button to trigger the generation process
            if st.button("Generate UI Code", help="Click to initiate the multi-step code generation."):
                st.subheader("Code Generation Process:")

                # Step 1: Generate initial UI description
                with st.spinner("Step 1/4: Describing your UI elements and colors..."):
                    prompt = "Describe this UI in accurate details. When you reference a UI element put its name and bounding box in the format: [object name (y_min, x_min, y_max, x_max)]. Also Describe the color of the elements."
                    description = send_message_to_model(prompt, temp_image_path)
                    st.success("UI Description Generated!")
                    with st.expander("See Initial UI Description"):
                        st.text(description)

                # Step 2: Refine the description
                with st.spinner("Step 2/4: Refining description with visual comparison..."):
                    refine_prompt = f"Compare the described UI elements with the provided image and identify any missing elements or inaccuracies. Also Describe the color of the elements. Provide a refined and accurate description of the UI elements based on this comparison. Here is the initial description: {description}"
                    refined_description = send_message_to_model(refine_prompt, temp_image_path)
                    st.success("UI Description Refined!")
                    with st.expander("See Refined UI Description"):
                        st.text(refined_description)

                # Step 3: Generate initial HTML
                with st.spinner("Step 3/4: Generating initial HTML with CSS..."):
                    html_prompt = (
                        f"Create an HTML file based on the following UI description, using the UI elements described in the previous response. "
                        f"Include {framework} CSS within the HTML file to style the elements. "
                        f"Make sure the colors used are the same as the original UI. "
                        f"The UI needs to be responsive and mobile-first, matching the original UI as closely as possible. "
                        f"Do not include any explanations or comments. Avoid using ```html and ``` at the end. "
                        f"ONLY return the HTML code with inline CSS. Here is the refined description: {refined_description}"
                    )
                    initial_html = send_message_to_model(html_prompt, temp_image_path)
                    st.success("Initial HTML Generated!")
                    st.subheader("Initial Generated HTML:")
                    st.code(initial_html, language='html')

                # Step 4: Refine HTML
                with st.spinner("Step 4/4: Refining the generated HTML code..."):
                    refine_html_prompt = (
                        f"Validate the following HTML code based on the UI description and image and provide a refined version of the HTML code with {framework} CSS that improves accuracy, responsiveness, and adherence to the original design. "
                        f"ONLY return the refined HTML code with inline CSS. Avoid using ```html and ``` at the end. "
                        f"Here is the initial HTML: {initial_html}"
                    )
                    refined_html = send_message_to_model(refine_html_prompt, temp_image_path)
                    st.success("HTML Refined Successfully!")
                    st.subheader("Refined Generated HTML:")
                    st.code(refined_html, language='html')

                st.markdown("---") # Final separator
                st.success("All steps completed! Your `index.html` file is ready for download.")

                # Save the refined HTML to a file and provide download link
                with open("index.html", "w", encoding="utf-8") as file: # Specify encoding
                    file.write(refined_html)

                st.download_button(
                    label="Download index.html",
                    data=refined_html,
                    file_name="index.html",
                    mime="text/html"
                )
                st.info("You can open the downloaded `index.html` file in your web browser to view the generated UI.")

        except Exception as e:
            st.error(f"An unexpected error occurred: {e}")
            st.exception(e) # Displays the full traceback

        finally:
            # Clean up the temporary image file whether an error occurred or not
            if temp_image_path.exists():
                os.remove(temp_image_path)
                # st.success("Temporary image file removed.") # Can uncomment for debugging
    else:
        st.write("Please upload an image to start generating UI code.")

if __name__ == "__main__":
    main()