MINEOGO commited on
Commit
9376840
·
verified ·
1 Parent(s): 58a5e73

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +111 -52
app.py CHANGED
@@ -5,7 +5,7 @@ import time # For potential brief pauses if needed
5
 
6
  # --- Hugging Face Token (Optional but Recommended) ---
7
  # from huggingface_hub import login
8
- # login("YOUR_HUGGINGFACE_TOKEN")
9
 
10
  # --- Inference Client ---
11
  try:
@@ -15,9 +15,9 @@ try:
15
  client.timeout = 120 # Increase timeout for potentially long generations
16
  except Exception as e:
17
  print(f"Error initializing InferenceClient: {e}")
18
- client = None
19
 
20
- # --- Parsing Function (from previous good version) ---
21
  def parse_files(raw_response):
22
  """
23
  Parses filenames and code blocks from the raw AI output.
@@ -60,16 +60,20 @@ def stream_and_parse_code(prompt, backend, system_message, max_tokens, temperatu
60
  """
61
  Streams raw output to one component and generates final tabs for another.
62
  This function acts as the main callback for the button click.
 
63
  """
 
64
  if not client:
65
- error_msg = "Error: Inference Client not available."
 
66
  yield {
67
- live_output: error_msg,
68
  final_tabs: gr.Tabs(tabs=[gr.TabItem(label="Error", children=[gr.Textbox(value=error_msg)])])
69
  }
70
  return # Stop execution
71
 
72
  # --- Prepare for Streaming ---
 
73
  full_sys_msg = f"""
74
  You are a code generation AI. Given a prompt, generate the necessary files for a website using the {backend} backend.
75
  Always include an index.html file.
@@ -83,9 +87,14 @@ index.html
83
  style.css
84
  body {{}}
85
 
 
 
 
86
  Ensure the code is complete. NO commentary, NO explanations, NO markdown formatting like backticks (```).
87
  Start generating the files now.
88
- """.strip() + ("\n" + system_message if system_message else "")
 
 
89
 
90
  messages = [
91
  {"role": "system", "content": full_sys_msg},
@@ -96,53 +105,55 @@ Start generating the files now.
96
  error_occurred = False
97
  error_message = ""
98
 
99
- # Initial state update
100
  yield {
101
- live_output: "Generating stream...",
102
- # Set initial tabs state to indicate loading
103
- final_tabs: gr.Tabs(tabs=[gr.TabItem(label="Generating...")])
104
  }
105
 
106
  # --- Streaming Loop ---
107
  try:
 
108
  stream = client.chat_completion(
109
  messages,
110
- max_tokens=int(max_tokens),
111
  stream=True,
112
  temperature=temperature,
113
  top_p=top_p
114
  )
 
115
  for chunk in stream:
116
  token = chunk.choices[0].delta.content
117
  if token:
118
  full_raw_response += token
119
- # Yield updates for the live raw output component
120
- # Keep tabs in a 'generating' state during the stream
121
  yield {
122
- live_output: full_raw_response,
123
- final_tabs: gr.Tabs(tabs=[gr.TabItem(label="Streaming...")]) # Keep showing streaming
 
124
  }
125
- # time.sleep(0.01) # Optional small delay if updates are too fast
126
 
127
  except Exception as e:
 
128
  print(f"Error during AI streaming: {e}")
129
- error_message = f"Error during AI generation: {e}\n\nPartial Response:\n{full_raw_response}"
130
  error_occurred = True
131
- # Update live output with error, keep tabs showing error state
132
  yield {
133
- live_output: error_message,
134
- final_tabs: gr.Tabs(tabs=[gr.TabItem(label="Error")])
135
  }
136
 
137
-
138
  # --- Post-Streaming: Parsing and Final Tab Generation ---
139
  if error_occurred:
140
- # If an error happened during stream, create an error tab
141
  final_tabs_update = gr.Tabs(tabs=[
142
- gr.TabItem(label="Error", children=[gr.Textbox(value=error_message, label="Generation Error")])
143
  ])
144
  else:
145
- # Parse the complete raw response
146
  print("\n--- Final Raw AI Response ---")
147
  print(full_raw_response)
148
  print("--------------------------\n")
@@ -150,12 +161,12 @@ Start generating the files now.
150
 
151
  if not files:
152
  # Handle case where parsing failed or AI gave empty/invalid response
153
- no_files_msg = "AI finished, but did not return recognizable file content. See raw output above."
154
  final_tabs_update = gr.Tabs(tabs=[
155
  gr.TabItem(label="Output", children=[gr.Textbox(value=no_files_msg, label="Result")])
156
  ])
157
- # Update live output as well if needed
158
- yield { live_output: full_raw_response + "\n\n" + no_files_msg, final_tabs: final_tabs_update }
159
  return # Exit if no files
160
 
161
  # --- Create Tabs (if files were parsed successfully) ---
@@ -163,11 +174,13 @@ Start generating the files now.
163
  for name, content in files:
164
  name = name.strip()
165
  content = content.strip()
 
166
  if not name or not content:
167
  print(f"Skipping file with empty name or content: Name='{name}'")
168
  continue
169
 
170
- lang = "text" # Default
 
171
  if name.endswith((".html", ".htm")): lang = "html"
172
  elif name.endswith(".css"): lang = "css"
173
  elif name.endswith(".js"): lang = "javascript"
@@ -175,50 +188,95 @@ Start generating the files now.
175
  elif name.endswith(".json"): lang = "json"
176
  elif name.endswith(".md"): lang = "markdown"
177
  elif name.endswith((".sh", ".bash")): lang = "bash"
 
 
 
 
 
178
 
179
- tab_item = gr.TabItem(label=name, elem_id=f"tab_{name.replace('.', '_').replace('/', '_')}", children=[
180
- gr.Code(value=content, language=lang, label=name)
181
  ])
182
  tabs_content.append(tab_item)
183
 
184
- if not tabs_content: # Handle case where parsing found files, but they were filtered out
185
- final_tabs_update = gr.Tabs(tabs=[gr.TabItem(label="Output", children=[gr.Textbox(value="No valid files generated.", label="Result")])])
 
186
  else:
187
- final_tabs_update = gr.Tabs(tabs=tabs_content) # Create the final Tabs component
188
-
189
 
190
  # --- Final Update ---
191
  # Yield the final state for both components
 
 
192
  yield {
193
- live_output: full_raw_response if not error_occurred else error_message, # Show final raw response or error
194
- final_tabs: final_tabs_update # Show the generated tabs or error tab
195
  }
196
 
197
 
198
  # --- Gradio UI Definition ---
199
- with gr.Blocks(css=".gradio-container { max-width: 95% !important; }") as demo: # Wider interface
200
  gr.Markdown("## WebGen AI — One Prompt → Full Website Generator")
201
  gr.Markdown("Generates website code based on your description. Raw output streams live, final files appear in tabs below.")
202
 
203
  with gr.Row():
 
204
  with gr.Column(scale=2):
205
- prompt = gr.Textbox(label="Describe your website", placeholder="E.g., a simple portfolio site with a dark mode toggle", lines=3)
206
- backend = gr.Dropdown(["Static", "Flask", "Node.js"], value="Static", label="Backend Technology")
 
 
 
 
 
 
 
 
207
  with gr.Accordion("Advanced Options", open=False):
208
- system_message = gr.Textbox(label="Extra instructions for the AI (System Message)", placeholder="Optional: e.g., 'Use Bootstrap 5', 'Prefer functional components in React'", value="")
209
- max_tokens = gr.Slider(minimum=256, maximum=4096, value=1536, step=64, label="Max Tokens (Length)")
210
- temperature = gr.Slider(minimum=0.1, maximum=1.5, value=0.7, step=0.1, label="Temperature (Creativity)")
211
- top_p = gr.Slider(minimum=0.1, maximum=1.0, value=0.95, step=0.05, label="Top-p (Sampling)")
212
- generate_button = gr.Button("✨ Generate Code ✨", variant="primary")
213
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  with gr.Column(scale=3):
215
  gr.Markdown("#### Live Raw Output Stream")
216
- # Component to show the live, unparsed stream
217
- live_output = gr.Code(label="Raw AI Stream", language="text", lines=15, interactive=False)
218
-
219
- gr.Markdown("---")
 
 
 
 
 
220
  gr.Markdown("#### Final Generated Files (Tabs)")
221
- # Placeholder for the final structured tabs
222
  final_tabs = gr.Tabs(elem_id="output_tabs")
223
 
224
 
@@ -226,10 +284,11 @@ with gr.Blocks(css=".gradio-container { max-width: 95% !important; }") as demo:
226
  generate_button.click(
227
  stream_and_parse_code, # Call the main function that handles streaming and parsing
228
  inputs=[prompt, backend, system_message, max_tokens, temperature, top_p],
229
- # Outputs dictionary maps function yields to components
230
  outputs=[live_output, final_tabs],
231
- show_progress="hidden" # Hide default progress bar as we show live stream
232
  )
233
 
234
  if __name__ == "__main__":
 
235
  demo.launch(debug=True)
 
5
 
6
  # --- Hugging Face Token (Optional but Recommended) ---
7
  # from huggingface_hub import login
8
+ # login("YOUR_HUGGINGFACE_TOKEN") # Replace with your token if needed
9
 
10
  # --- Inference Client ---
11
  try:
 
15
  client.timeout = 120 # Increase timeout for potentially long generations
16
  except Exception as e:
17
  print(f"Error initializing InferenceClient: {e}")
18
+ client = None # Set client to None if initialization fails
19
 
20
+ # --- Parsing Function ---
21
  def parse_files(raw_response):
22
  """
23
  Parses filenames and code blocks from the raw AI output.
 
60
  """
61
  Streams raw output to one component and generates final tabs for another.
62
  This function acts as the main callback for the button click.
63
+ Yields dictionary updates for Gradio components.
64
  """
65
+ # Check if client initialized correctly
66
  if not client:
67
+ error_msg = "Error: Inference Client not available. Check API token or model name."
68
+ # Yield updates to both components indicating the error
69
  yield {
70
+ live_output: gr.update(value=error_msg),
71
  final_tabs: gr.Tabs(tabs=[gr.TabItem(label="Error", children=[gr.Textbox(value=error_msg)])])
72
  }
73
  return # Stop execution
74
 
75
  # --- Prepare for Streaming ---
76
+ # Construct the system prompt dynamically
77
  full_sys_msg = f"""
78
  You are a code generation AI. Given a prompt, generate the necessary files for a website using the {backend} backend.
79
  Always include an index.html file.
 
87
  style.css
88
  body {{}}
89
 
90
+ script.js
91
+ console.log("Hello");
92
+
93
  Ensure the code is complete. NO commentary, NO explanations, NO markdown formatting like backticks (```).
94
  Start generating the files now.
95
+ """.strip()
96
+ if system_message: # Append user's system message if provided
97
+ full_sys_msg += "\n\n" + system_message
98
 
99
  messages = [
100
  {"role": "system", "content": full_sys_msg},
 
105
  error_occurred = False
106
  error_message = ""
107
 
108
+ # Initial state update: Clear previous output and show generating status
109
  yield {
110
+ live_output: gr.update(value="Generating stream..."),
111
+ final_tabs: gr.Tabs(tabs=[gr.TabItem(label="Generating...")]) # Indicate loading in tabs
 
112
  }
113
 
114
  # --- Streaming Loop ---
115
  try:
116
+ # Start the streaming call
117
  stream = client.chat_completion(
118
  messages,
119
+ max_tokens=int(max_tokens), # Ensure max_tokens is an integer
120
  stream=True,
121
  temperature=temperature,
122
  top_p=top_p
123
  )
124
+ # Process each chunk received from the stream
125
  for chunk in stream:
126
  token = chunk.choices[0].delta.content
127
  if token:
128
  full_raw_response += token
129
+ # Yield updates for the live raw output component only
130
+ # Keep tabs in a 'streaming' state during the stream
131
  yield {
132
+ live_output: gr.update(value=full_raw_response),
133
+ # No update needed for final_tabs here, or keep showing streaming state
134
+ # final_tabs: gr.Tabs(tabs=[gr.TabItem(label="Streaming...")]) # Optional: update tabs state
135
  }
136
+ # time.sleep(0.01) # Optional: small delay if updates are too fast and causing UI lag
137
 
138
  except Exception as e:
139
+ # Handle errors during the API call or streaming process
140
  print(f"Error during AI streaming: {e}")
141
+ error_message = f"Error during AI generation: {e}\n\nPartial Response (if any):\n{full_raw_response}"
142
  error_occurred = True
143
+ # Update live output with error, prepare error tab
144
  yield {
145
+ live_output: gr.update(value=error_message),
146
+ final_tabs: gr.Tabs(tabs=[gr.TabItem(label="Error")]) # Indicate error state in tabs
147
  }
148
 
 
149
  # --- Post-Streaming: Parsing and Final Tab Generation ---
150
  if error_occurred:
151
+ # If an error happened during stream, create a final error tab
152
  final_tabs_update = gr.Tabs(tabs=[
153
+ gr.TabItem(label="Error", children=[gr.Textbox(value=error_message, label="Generation Error", lines=10)])
154
  ])
155
  else:
156
+ # If streaming succeeded, parse the complete raw response
157
  print("\n--- Final Raw AI Response ---")
158
  print(full_raw_response)
159
  print("--------------------------\n")
 
161
 
162
  if not files:
163
  # Handle case where parsing failed or AI gave empty/invalid response
164
+ no_files_msg = "AI finished, but did not return recognizable file content or the response was empty. See raw output above."
165
  final_tabs_update = gr.Tabs(tabs=[
166
  gr.TabItem(label="Output", children=[gr.Textbox(value=no_files_msg, label="Result")])
167
  ])
168
+ # Update live output as well to make the message clear
169
+ yield { live_output: gr.update(value=full_raw_response + "\n\n" + no_files_msg), final_tabs: final_tabs_update }
170
  return # Exit if no files
171
 
172
  # --- Create Tabs (if files were parsed successfully) ---
 
174
  for name, content in files:
175
  name = name.strip()
176
  content = content.strip()
177
+ # Skip if filename or content is empty after stripping
178
  if not name or not content:
179
  print(f"Skipping file with empty name or content: Name='{name}'")
180
  continue
181
 
182
+ # Determine language for syntax highlighting
183
+ lang = "plaintext" # Default
184
  if name.endswith((".html", ".htm")): lang = "html"
185
  elif name.endswith(".css"): lang = "css"
186
  elif name.endswith(".js"): lang = "javascript"
 
188
  elif name.endswith(".json"): lang = "json"
189
  elif name.endswith(".md"): lang = "markdown"
190
  elif name.endswith((".sh", ".bash")): lang = "bash"
191
+ elif name.endswith((".xml", ".xaml", ".svg")): lang = "xml"
192
+ elif name.endswith(".yaml") or name.endswith(".yml"): lang = "yaml"
193
+
194
+ # Ensure elem_id is unique and valid (replace problematic characters)
195
+ elem_id = f"tab_{re.sub(r'[^a-zA-Z0-9_-]', '_', name)}"
196
 
197
+ tab_item = gr.TabItem(label=name, elem_id=elem_id, children=[
198
+ gr.Code(value=content, language=lang, label=name, interactive=False) # Show code in Code block
199
  ])
200
  tabs_content.append(tab_item)
201
 
202
+ # Handle case where parsing found files, but they were all filtered out (empty name/content)
203
+ if not tabs_content:
204
+ final_tabs_update = gr.Tabs(tabs=[gr.TabItem(label="Output", children=[gr.Textbox(value="No valid files generated after filtering.", label="Result")])])
205
  else:
206
+ final_tabs_update = gr.Tabs(tabs=tabs_content) # Create the final Tabs component with content
 
207
 
208
  # --- Final Update ---
209
  # Yield the final state for both components
210
+ # Use gr.update for live_output if you only want to set its value without recreating it
211
+ # Directly return the new final_tabs component
212
  yield {
213
+ live_output: gr.update(value=full_raw_response if not error_occurred else error_message), # Show final raw response or error
214
+ final_tabs: final_tabs_update # Update the final_tabs component completely
215
  }
216
 
217
 
218
  # --- Gradio UI Definition ---
219
+ with gr.Blocks(css=".gradio-container { max-width: 95% !important; }") as demo: # Use more screen width
220
  gr.Markdown("## WebGen AI — One Prompt → Full Website Generator")
221
  gr.Markdown("Generates website code based on your description. Raw output streams live, final files appear in tabs below.")
222
 
223
  with gr.Row():
224
+ # Column for inputs and controls
225
  with gr.Column(scale=2):
226
+ prompt = gr.Textbox(
227
+ label="Describe your website",
228
+ placeholder="E.g., a simple landing page for a coffee shop with sections for menu, about, and contact.",
229
+ lines=3 # Allow more lines for the prompt
230
+ )
231
+ backend = gr.Dropdown(
232
+ ["Static", "Flask", "Node.js"],
233
+ value="Static",
234
+ label="Backend Technology"
235
+ )
236
  with gr.Accordion("Advanced Options", open=False):
237
+ system_message = gr.Textbox(
238
+ label="Extra instructions for the AI (System Message)",
239
+ placeholder="Optional: e.g., 'Use Tailwind CSS for styling', 'Make it responsive'",
240
+ value="",
241
+ lines=2
242
+ )
243
+ max_tokens = gr.Slider(
244
+ minimum=256,
245
+ maximum=4096, # Increased max tokens for complex sites
246
+ value=2048, # Increased default
247
+ step=64,
248
+ label="Max Tokens (Output Length)"
249
+ )
250
+ temperature = gr.Slider(
251
+ minimum=0.1,
252
+ maximum=1.5, # Allow slightly higher temperature
253
+ value=0.7,
254
+ step=0.1,
255
+ label="Temperature (Creativity)"
256
+ )
257
+ top_p = gr.Slider(
258
+ minimum=0.1,
259
+ maximum=1.0,
260
+ value=0.95,
261
+ step=0.05,
262
+ label="Top-p (Sampling Focus)"
263
+ )
264
+ generate_button = gr.Button("✨ Generate Code ✨", variant="primary") # Make button primary
265
+
266
+ # Column for live output
267
  with gr.Column(scale=3):
268
  gr.Markdown("#### Live Raw Output Stream")
269
+ # Component to show the live, unparsed stream - CORRECTED LANGUAGE
270
+ live_output = gr.Code(
271
+ label="Raw AI Stream",
272
+ language="plaintext", # Use "plaintext" for generic text
273
+ lines=20, # Increased lines for visibility
274
+ interactive=False # Output only
275
+ )
276
+
277
+ gr.Markdown("---") # Separator
278
  gr.Markdown("#### Final Generated Files (Tabs)")
279
+ # Placeholder for the final structured tabs - will be replaced by the output yield
280
  final_tabs = gr.Tabs(elem_id="output_tabs")
281
 
282
 
 
284
  generate_button.click(
285
  stream_and_parse_code, # Call the main function that handles streaming and parsing
286
  inputs=[prompt, backend, system_message, max_tokens, temperature, top_p],
287
+ # Outputs dictionary maps function yields to components by variable name
288
  outputs=[live_output, final_tabs],
289
+ show_progress="hidden" # Hide default Gradio progress bar as we show live stream
290
  )
291
 
292
  if __name__ == "__main__":
293
+ # Launch the Gradio app with debug=True for development
294
  demo.launch(debug=True)