MINEOGO commited on
Commit
c06d1c2
·
verified ·
1 Parent(s): 4e60047

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +72 -68
app.py CHANGED
@@ -1,7 +1,7 @@
1
  import gradio as gr
2
  from huggingface_hub import InferenceClient
3
  import os
4
- import re # Import regex for potential cleaning, although prompt is the primary fix
5
 
6
  # --- Configuration ---
7
  API_TOKEN = os.getenv("HF_TOKEN", None)
@@ -32,58 +32,53 @@ def generate_code(
32
  ):
33
  """
34
  Generates website code based on user prompt and choices.
 
35
  Yields the code token by token for live updates.
36
- Strives to output ONLY raw code.
37
  """
38
  print(f"--- Generating Code ---")
39
  print(f"Prompt: {prompt[:100]}...")
40
  print(f"Backend Context: {backend_choice}")
41
- print(f"File Structure: {file_structure}") # Crucial input
42
  print(f"Settings: Max Tokens={max_tokens}, Temp={temperature}, Top-P={top_p}")
43
 
44
- # --- Dynamically Build System Message Based on File Structure ---
45
 
46
- # Define specific instructions based on the user's choice
47
  if file_structure == "Single File":
48
  file_structure_instruction = (
49
  "- **File Structure is 'Single File':** Generate ONLY a single, complete `index.html` file. "
50
  "Embed ALL CSS directly within `<style>` tags inside the `<head>`. "
51
  "Embed ALL necessary JavaScript directly within `<script>` tags just before the closing `</body>` tag. "
52
- "Do NOT use markers like `<!-- index.html -->` or `/* style.css */`."
53
  )
54
  else: # Multiple Files
55
  file_structure_instruction = (
56
  "- **File Structure is 'Multiple Files':** Generate code for `index.html`, `style.css`, and `script.js` (if JS is needed). "
57
- "Use these EXACT markers to separate the files:\n"
58
- " `<!-- index.html -->`\n"
59
- " `/* style.css */`\n"
60
- " `// script.js` (ONLY include this marker and the JS code if JavaScript is necessary for the requested functionality).\n"
61
  "- Place the corresponding code directly after each marker.\n"
62
- "- Inside the `index.html` code block, ensure you correctly link the CSS (`<link rel='stylesheet' href='style.css'>`) in the `<head>`.\n"
63
- "- Inside the `index.html` code block, ensure you correctly include the JS (`<script src='script.js'></script>`) just before the closing `</body>` tag *if* the `// script.js` marker and code are present."
64
  )
65
 
66
- # Assemble the full system message with the dynamic instruction
67
- # Emphasize constraints VERY strongly
68
  system_message = (
69
- "You are an expert frontend web developer AI. Your SOLE task is to generate RAW SOURCE CODE (HTML, CSS, JavaScript) based on the user's request and selected options. "
70
- "You MUST follow ALL these rules ABSOLUTELY:\n"
71
- "1. **RAW CODE ONLY:** Your *entire* response MUST consist *only* of the requested code. NO extra text, NO explanations, NO apologies, NO introductions (like 'Here is the code...', 'Okay, here is the code...'), NO summaries, NO comments about the code (unless it's a standard code comment like `<!-- comment -->`), and ABSOLUTELY NO MARKDOWN FORMATTING like ```html, ```css, ```javascript, or ```.\n"
72
- "2. **IMMEDIATE CODE START:** The response MUST begin *directly* with the first character of the code (e.g., `<!DOCTYPE html>` or `<!-- index.html -->`). NO leading spaces or lines.\n"
73
- "3. **MANDATORY `index.html`:** Always generate the content for `index.html`.\n"
74
- f"4. **FILE STRUCTURE ({file_structure}):** Strictly follow ONLY the instructions for the *selected* file structure below:\n"
 
 
75
  f" {file_structure_instruction}\n" # Insert the specific instruction here
76
- "5. **BACKEND CONTEXT ({backend_choice}):** Use this as a hint for frontend structure (e.g., placeholders like `{{ variable }}` if 'Flask' is chosen), but ONLY generate the static frontend code (HTML, CSS, client-side JS).\n"
77
- "6. **FRONTEND ONLY:** Do NOT generate server-side code (Python, Node.js, etc.).\n"
78
- "7. **ACCURACY:** Generate functional code that directly addresses the user's prompt.\n\n"
79
- "REMEMBER: ONLY CODE. NO OTHER TEXT. START IMMEDIATELY WITH CODE." # Final reinforcement
80
  )
81
 
82
  # --- Construct the messages for the API ---
83
  messages = [
84
  {"role": "system", "content": system_message},
85
- # Make user prompt clearer
86
- {"role": "user", "content": f"Generate the website frontend code based on this description: {prompt}"}
87
  ]
88
 
89
  # --- Stream the response from the API ---
@@ -95,39 +90,43 @@ def generate_code(
95
  messages=messages,
96
  max_tokens=max_tokens,
97
  stream=True,
98
- temperature=temperature,
99
  top_p=top_p,
100
  ):
101
  token = message.choices[0].delta.content
102
  if isinstance(token, str):
103
  response_stream += token
104
- full_response_for_cleaning += token # Keep a separate copy for potential final cleaning
105
- yield response_stream # Yield the cumulative response for live update
106
 
107
  print(f"API stream finished. Raw length: {len(full_response_for_cleaning)}")
108
 
109
- # --- Basic Post-Processing (Attempt to remove backticks if prompt fails) ---
110
- # While the prompt *should* handle this, add a safety net.
111
  cleaned_response = full_response_for_cleaning.strip()
112
 
113
- # Remove potential leading/trailing markdown code fences more robustly
114
- # Matches ``` followed by optional language identifier and newline, or just ```
115
  cleaned_response = re.sub(r"^\s*```[a-z]*\s*\n?", "", cleaned_response)
116
  cleaned_response = re.sub(r"\n?\s*```\s*$", "", cleaned_response)
117
 
118
- # Also remove common introductory phrases if they slip through (less likely with strong prompt)
119
- common_intros = [
 
 
 
120
  "Here is the code:", "Okay, here is the code:", "Here's the code:",
121
- "```html", "```css", "```javascript" # Also catch these if regex missed them
 
122
  ]
123
- for intro in common_intros:
124
- if cleaned_response.lower().startswith(intro.lower()):
125
- cleaned_response = cleaned_response[len(intro):].lstrip()
126
-
127
- # Yield the final potentially cleaned response *once* after streaming is done
128
- # This replaces the last yielded value from the loop if cleaning occurred
129
- yield cleaned_response.strip() # Ensure no trailing whitespace after cleaning
130
 
 
 
131
 
132
  except Exception as e:
133
  error_message = f"An error occurred during the API call: {e}"
@@ -137,45 +136,51 @@ def generate_code(
137
 
138
  # --- Build Gradio Interface using Blocks ---
139
  with gr.Blocks(css=".gradio-container { max-width: 90% !important; }") as demo:
140
- gr.Markdown("# Website Code Generator 🚀")
141
  gr.Markdown(
142
- "Describe the website, choose options, and get ONLY the raw frontend code. "
143
- "Code appears live below. **Select 'Single File' or 'Multiple Files' carefully.**"
 
144
  )
145
 
146
  with gr.Row():
147
  with gr.Column(scale=2):
148
  prompt_input = gr.Textbox(
149
  label="Website Description",
150
- placeholder="e.g., A simple landing page with a navbar, hero section, and footer.",
151
- lines=5,
152
  )
153
  backend_radio = gr.Radio(
154
- ["Static", "Flask", "Node.js"],
155
- label="Backend Context Hint",
156
- value="Static",
157
- info="Hint for AI (e.g., template placeholders) - generates ONLY frontend code.",
158
  )
159
  file_structure_radio = gr.Radio(
160
- ["Multiple Files", "Single File"], # Default: Multiple
161
- label="Output File Structure",
162
- value="Multiple Files",
163
- info="Choose 'Single File' for everything in index.html OR 'Multiple Files' for separate css/js.", # Clarified info
164
  )
165
- generate_button = gr.Button("Generate Website Code", variant="primary")
166
 
167
  with gr.Column(scale=3):
168
  code_output = gr.Code(
169
- label="Generated Code (Raw Output)", # Updated label
170
  language="html",
171
- lines=28,
172
  interactive=False,
173
  )
174
 
175
  with gr.Accordion("Advanced Generation Settings", open=False):
176
- max_tokens_slider = gr.Slider(minimum=512, maximum=4096, value=2048, step=128, label="Max New Tokens")
177
- temperature_slider = gr.Slider(minimum=0.1, maximum=1.2, value=0.6, step=0.1, label="Temperature")
178
- top_p_slider = gr.Slider(minimum=0.1, maximum=1.0, value=0.9, step=0.05, label="Top-P")
 
 
 
 
 
 
 
 
 
179
 
180
  # --- Connect Inputs/Outputs ---
181
  generate_button.click(
@@ -194,14 +199,13 @@ with gr.Blocks(css=".gradio-container { max-width: 90% !important; }") as demo:
194
  # --- Examples ---
195
  gr.Examples(
196
  examples=[
197
- ["A simple counter page with a number display, an increment button, and a decrement button. Use Javascript for the logic.", "Static", "Single File"],
198
- ["A login form with fields for username and password, and a submit button. Basic styling.", "Static", "Multiple Files"],
199
- ["Product cards display grid. Each card shows an image, product name, price, and an 'Add to Cart' button. Make it responsive.", "Static", "Multiple Files"],
200
- ["A personal blog homepage with a header, a list of recent posts (just placeholders), and a sidebar with categories.", "Flask", "Multiple Files"],
201
- ["A very basic HTML page with just a title 'My App' and a heading 'Welcome'. No CSS or JS.", "Static", "Single File"]
202
  ],
203
  inputs=[prompt_input, backend_radio, file_structure_radio],
204
- label="Example Prompts"
205
  )
206
 
207
  # --- Launch ---
 
1
  import gradio as gr
2
  from huggingface_hub import InferenceClient
3
  import os
4
+ import re # For post-processing fallback
5
 
6
  # --- Configuration ---
7
  API_TOKEN = os.getenv("HF_TOKEN", None)
 
32
  ):
33
  """
34
  Generates website code based on user prompt and choices.
35
+ Aims for richer CSS and strictly outputs ONLY raw code.
36
  Yields the code token by token for live updates.
 
37
  """
38
  print(f"--- Generating Code ---")
39
  print(f"Prompt: {prompt[:100]}...")
40
  print(f"Backend Context: {backend_choice}")
41
+ print(f"File Structure: {file_structure}")
42
  print(f"Settings: Max Tokens={max_tokens}, Temp={temperature}, Top-P={top_p}")
43
 
44
+ # --- Dynamically Build System Message Based on File Structure & Style Request ---
45
 
 
46
  if file_structure == "Single File":
47
  file_structure_instruction = (
48
  "- **File Structure is 'Single File':** Generate ONLY a single, complete `index.html` file. "
49
  "Embed ALL CSS directly within `<style>` tags inside the `<head>`. "
50
  "Embed ALL necessary JavaScript directly within `<script>` tags just before the closing `</body>` tag. "
51
+ "Do NOT use file separation markers."
52
  )
53
  else: # Multiple Files
54
  file_structure_instruction = (
55
  "- **File Structure is 'Multiple Files':** Generate code for `index.html`, `style.css`, and `script.js` (if JS is needed). "
56
+ "Use these EXACT markers: `<!-- index.html -->`, `/* style.css */`, `// script.js` (only if JS is needed).\n"
 
 
 
57
  "- Place the corresponding code directly after each marker.\n"
58
+ "- Inside `index.html`, link `style.css` in the `<head>` and include `script.js` before `</body>` if generated."
 
59
  )
60
 
61
+ # Assemble the full system message with enhanced style guidance and stricter output rules
 
62
  system_message = (
63
+ "You are an expert frontend web developer AI. Your primary goal is to generate **visually appealing, modern, and well-styled** frontend code (HTML, CSS, client-side JS) based *only* on the user's description and selected options. "
64
+ "Follow ALL these rules with EXTREME STRICTNESS:\n"
65
+ "1. **STYLE & DETAIL:** Generate rich, detailed code. Don't just make minimal examples. Use **plenty of CSS** for layout (Flexbox/Grid), spacing (padding/margin), typography (fonts), colors, and consider adding subtle transitions or effects for a polished look. Aim for a high-quality visual result.\n"
66
+ "2. **RAW CODE ONLY:** Your *entire* response MUST consist *only* of the requested source code. NO extra text, NO explanations, NO apologies, NO introductions ('Here is the code...'), NO summaries, NO comments about the code (except standard code comments), NO MARKDOWN formatting (like ```html), and ***ABSOLUTELY NO CONVERSATIONAL TEXT OR TAGS*** like `<|user|>` or `<|assistant|>` before, during, or after the code.\n"
67
+ "3. **IMMEDIATE CODE START:** The response MUST begin *directly* with the first character of the code (e.g., `<!DOCTYPE html>` or `<!-- index.html -->`). NO leading spaces, newlines, or any other characters.\n"
68
+ "4. **IMMEDIATE CODE END:** The response MUST end *immediately* after the very last character of the generated code (e.g., the final `</html>`, `}`, or `;`). DO NOT add *any* text, spaces, or newlines after the code concludes.\n"
69
+ "5. **MANDATORY `index.html`:** Always generate the content for `index.html`.\n"
70
+ f"6. **FILE STRUCTURE ({file_structure}):** Strictly follow ONLY the instructions for the *selected* file structure below:\n"
71
  f" {file_structure_instruction}\n" # Insert the specific instruction here
72
+ "7. **BACKEND CONTEXT ({backend_choice}):** Use this as a hint for frontend structure (e.g., placeholders like `{{ variable }}` if 'Flask' is chosen), but ONLY generate the static frontend code (HTML, CSS, client-side JS).\n"
73
+ "8. **FRONTEND ONLY:** Do NOT generate server-side code (Python, Node.js, etc.).\n"
74
+ "9. **ACCURACY:** Generate functional code that directly addresses the user's prompt.\n\n"
75
+ "REMEMBER: Create visually appealing code. Output ONLY the raw code. START immediately with code. END immediately with code. NO extra text or tags EVER." # Final reinforcement
76
  )
77
 
78
  # --- Construct the messages for the API ---
79
  messages = [
80
  {"role": "system", "content": system_message},
81
+ {"role": "user", "content": f"Generate the website frontend code for: {prompt}"} # Slightly rephrased user message
 
82
  ]
83
 
84
  # --- Stream the response from the API ---
 
90
  messages=messages,
91
  max_tokens=max_tokens,
92
  stream=True,
93
+ temperature=temperature, # User controlled - 0.7 is a reasonable default balance
94
  top_p=top_p,
95
  ):
96
  token = message.choices[0].delta.content
97
  if isinstance(token, str):
98
  response_stream += token
99
+ full_response_for_cleaning += token
100
+ yield response_stream # Yield cumulative response for live update
101
 
102
  print(f"API stream finished. Raw length: {len(full_response_for_cleaning)}")
103
 
104
+ # --- Post-Processing (Fallback Safety Net) ---
105
+ # Primarily rely on the prompt, but clean common issues just in case.
106
  cleaned_response = full_response_for_cleaning.strip()
107
 
108
+ # Remove potential leading/trailing markdown code fences
 
109
  cleaned_response = re.sub(r"^\s*```[a-z]*\s*\n?", "", cleaned_response)
110
  cleaned_response = re.sub(r"\n?\s*```\s*$", "", cleaned_response)
111
 
112
+ # Remove potential conversational tags if they slip through (less likely now)
113
+ cleaned_response = re.sub(r"<\s*\|?\s*(user|assistant)\s*\|?\s*>", "", cleaned_response, flags=re.IGNORECASE)
114
+
115
+ # Remove common introductory/closing phrases if they slip through
116
+ common_phrases = [
117
  "Here is the code:", "Okay, here is the code:", "Here's the code:",
118
+ "Sure, here is the code you requested:", "Let me know if you need anything else."
119
+ # Add more if needed
120
  ]
121
+ temp_response = cleaned_response.lower()
122
+ for phrase in common_phrases:
123
+ if temp_response.startswith(phrase.lower()):
124
+ cleaned_response = cleaned_response[len(phrase):].lstrip()
125
+ if temp_response.endswith(phrase.lower()):
126
+ cleaned_response = cleaned_response[:-len(phrase)].rstrip()
 
127
 
128
+ # Yield the final cleaned response *once* after streaming.
129
+ yield cleaned_response.strip()
130
 
131
  except Exception as e:
132
  error_message = f"An error occurred during the API call: {e}"
 
136
 
137
  # --- Build Gradio Interface using Blocks ---
138
  with gr.Blocks(css=".gradio-container { max-width: 90% !important; }") as demo:
139
+ gr.Markdown("# Website Code Generator ") # Added some flair
140
  gr.Markdown(
141
+ "Describe the website you want. The AI will generate **visually styled** frontend code (HTML, CSS, JS) using **plenty of CSS**. "
142
+ "The code appears live below. \n"
143
+ "**Important:** This generator creates code based *only* on your initial description. To refine the output, modify your description and generate again." # Added clarification
144
  )
145
 
146
  with gr.Row():
147
  with gr.Column(scale=2):
148
  prompt_input = gr.Textbox(
149
  label="Website Description",
150
+ placeholder="e.g., A modern portfolio landing page with a smooth scroll navigation, a stylish hero section, project cards with hover effects, and a contact form.", # More ambitious placeholder
151
+ lines=6, # Slightly more lines
152
  )
153
  backend_radio = gr.Radio(
154
+ ["Static", "Flask", "Node.js"], label="Backend Context Hint", value="Static",
155
+ info="Hint for AI (e.g., template placeholders) - generates ONLY frontend code."
 
 
156
  )
157
  file_structure_radio = gr.Radio(
158
+ ["Multiple Files", "Single File"], label="Output File Structure", value="Multiple Files",
159
+ info="Choose 'Single File' (all in index.html) or 'Multiple Files' (separate css/js)."
 
 
160
  )
161
+ generate_button = gr.Button("🎨 Generate Stylish Website Code", variant="primary") # Updated button text
162
 
163
  with gr.Column(scale=3):
164
  code_output = gr.Code(
165
+ label="Generated Code (Raw Output - Aiming for Style!)", # Updated label
166
  language="html",
167
+ lines=30, # More lines for potentially longer code
168
  interactive=False,
169
  )
170
 
171
  with gr.Accordion("Advanced Generation Settings", open=False):
172
+ max_tokens_slider = gr.Slider(
173
+ minimum=512, maximum=4096, value=2560, step=128, label="Max New Tokens", # Increased default
174
+ info="Max length of generated code. Increase for complex pages."
175
+ )
176
+ temperature_slider = gr.Slider(
177
+ minimum=0.1, maximum=1.2, value=0.7, step=0.1, label="Temperature", # Default 0.7 is often good
178
+ info="Controls randomness. Lower=more predictable, Higher=more creative."
179
+ )
180
+ top_p_slider = gr.Slider(
181
+ minimum=0.1, maximum=1.0, value=0.9, step=0.05, label="Top-P",
182
+ info="Alternative randomness control."
183
+ )
184
 
185
  # --- Connect Inputs/Outputs ---
186
  generate_button.click(
 
199
  # --- Examples ---
200
  gr.Examples(
201
  examples=[
202
+ ["A simple counter page with a number display, an increment button, and a decrement button. Style the buttons nicely and center everything.", "Static", "Single File"],
203
+ ["A responsive product grid for an e-commerce site. Each card needs an image, title, price, and 'Add to Cart' button with a hover effect. Use modern CSS.", "Static", "Multiple Files"],
204
+ ["A personal blog homepage featuring a clean header with navigation, a main content area for post summaries (placeholders ok), and a simple footer. Use a nice font.", "Flask", "Multiple Files"],
205
+ ["A 'Coming Soon' page with a large countdown timer (use JS), a background image, and an email signup form. Make it look sleek.", "Static", "Multiple Files"]
 
206
  ],
207
  inputs=[prompt_input, backend_radio, file_structure_radio],
208
+ label="Example Prompts (Aiming for Style)" # Updated label
209
  )
210
 
211
  # --- Launch ---