mgbam commited on
Commit
0131ae7
Β·
verified Β·
1 Parent(s): 2f2aa44

Create main.py

Browse files
Files changed (1) hide show
  1. main.py +848 -0
main.py ADDED
@@ -0,0 +1,848 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Main AnyCoder application with advanced professional UI.
3
+ """
4
+
5
+ import os
6
+ import uuid
7
+ import time
8
+ from typing import Dict, List, Optional, Tuple, Any
9
+ import gradio as gr
10
+
11
+ # Import all modules
12
+ from config import (
13
+ AVAILABLE_MODELS, DEFAULT_MODEL, THEME_CONFIGS, DEMO_LIST,
14
+ get_gradio_language, get_saved_theme, save_theme_preference
15
+ )
16
+ from utils import (
17
+ get_inference_client, remove_code_block, extract_text_from_file,
18
+ create_multimodal_message, apply_search_replace_changes,
19
+ cleanup_all_temp_media, cleanup_session_media, reap_old_media
20
+ )
21
+ from media_generation import (
22
+ generate_image_with_qwen, generate_image_to_image, generate_video_from_image,
23
+ generate_video_from_text, generate_music_from_text
24
+ )
25
+ from web_utils import extract_website_content, enhance_query_with_search, tavily_client
26
+ from code_processing import (
27
+ is_streamlit_code, is_gradio_code, parse_transformers_js_output,
28
+ format_transformers_js_output, parse_svelte_output, format_svelte_output,
29
+ parse_multipage_html_output, format_multipage_output, validate_and_autofix_files,
30
+ inline_multipage_into_single_preview, apply_generated_media_to_html,
31
+ extract_html_document, apply_search_replace_changes as apply_transformers_js_search_replace_changes
32
+ )
33
+ from sandbox import (
34
+ send_to_sandbox, send_to_sandbox_with_refresh, send_streamlit_to_stlite,
35
+ send_gradio_to_lite, send_transformers_to_sandbox, generate_preview
36
+ )
37
+ from deployment import (
38
+ deploy_to_user_space, deploy_to_spaces, deploy_to_spaces_static,
39
+ load_project_from_url, extract_import_statements
40
+ )
41
+
42
+ # Global state
43
+ History = List[Tuple[str, str]]
44
+ Messages = List[Dict[str, str]]
45
+
46
+ def history_to_messages(history: History, system: str) -> Messages:
47
+ """Convert history to messages format"""
48
+ messages = [{'role': 'system', 'content': system}]
49
+ for h in history:
50
+ user_content = h[0]
51
+ if isinstance(user_content, list):
52
+ text_content = ""
53
+ for item in user_content:
54
+ if isinstance(item, dict) and item.get("type") == "text":
55
+ text_content += item.get("text", "")
56
+ user_content = text_content if text_content else str(user_content)
57
+
58
+ messages.append({'role': 'user', 'content': user_content})
59
+ messages.append({'role': 'assistant', 'content': h[1]})
60
+ return messages
61
+
62
+ def history_to_chatbot_messages(history: History) -> List[Dict[str, str]]:
63
+ """Convert history tuples to chatbot message format"""
64
+ messages = []
65
+ for user_msg, assistant_msg in history:
66
+ if isinstance(user_msg, list):
67
+ text_content = ""
68
+ for item in user_msg:
69
+ if isinstance(item, dict) and item.get("type") == "text":
70
+ text_content += item.get("text", "")
71
+ user_msg = text_content if text_content else str(user_msg)
72
+
73
+ messages.append({"role": "user", "content": user_msg})
74
+ messages.append({"role": "assistant", "content": assistant_msg})
75
+ return messages
76
+
77
+ def clear_history():
78
+ """Clear all history and reset UI"""
79
+ return [], [], None, ""
80
+
81
+ def update_image_input_visibility(model):
82
+ """Update image input visibility based on selected model"""
83
+ is_vision_model = model.get("supports_vision", False)
84
+ return gr.update(visible=is_vision_model)
85
+
86
+ def generation_code(query: Optional[str], vlm_image: Optional[gr.Image], gen_image: Optional[gr.Image],
87
+ file: Optional[str], website_url: Optional[str], _setting: Dict[str, str],
88
+ _history: Optional[History], _current_model: Dict, enable_search: bool = False,
89
+ language: str = "html", provider: str = "auto", enable_image_generation: bool = False,
90
+ enable_image_to_image: bool = False, image_to_image_prompt: Optional[str] = None,
91
+ text_to_image_prompt: Optional[str] = None, enable_image_to_video: bool = False,
92
+ image_to_video_prompt: Optional[str] = None, enable_text_to_video: bool = False,
93
+ text_to_video_prompt: Optional[str] = None, enable_text_to_music: bool = False,
94
+ text_to_music_prompt: Optional[str] = None):
95
+ """Main code generation function"""
96
+
97
+ if query is None:
98
+ query = ''
99
+ if _history is None:
100
+ _history = []
101
+
102
+ # Ensure proper history format
103
+ if not isinstance(_history, list):
104
+ _history = []
105
+ _history = [h for h in _history if isinstance(h, list) and len(h) == 2]
106
+
107
+ # Create/lookup session ID for temp file tracking
108
+ if _setting is not None and isinstance(_setting, dict):
109
+ session_id = _setting.get("__session_id__")
110
+ if not session_id:
111
+ session_id = str(uuid.uuid4())
112
+ _setting["__session_id__"] = session_id
113
+ else:
114
+ session_id = str(uuid.uuid4())
115
+
116
+ # Cleanup old files
117
+ try:
118
+ cleanup_session_media(session_id)
119
+ reap_old_media()
120
+ except Exception:
121
+ pass
122
+
123
+ # Check for existing content (modification request)
124
+ has_existing_content = False
125
+ last_assistant_msg = ""
126
+ if _history and len(_history[-1]) > 1:
127
+ last_assistant_msg = _history[-1][1]
128
+ if any(indicator in last_assistant_msg for indicator in [
129
+ '<!DOCTYPE html>', '<html', 'import gradio', 'import streamlit',
130
+ 'def ', '=== index.html ===', '=== index.js ===', '=== style.css ==='
131
+ ]):
132
+ has_existing_content = True
133
+
134
+ # Handle modification requests with search/replace
135
+ if has_existing_content and query.strip():
136
+ try:
137
+ client = get_inference_client(_current_model['id'], provider)
138
+
139
+ system_prompt = f"""You are a code editor assistant. Generate EXACT search/replace blocks using these markers:
140
+ {from config import SEARCH_START, DIVIDER, REPLACE_END}
141
+
142
+ CRITICAL REQUIREMENTS:
143
+ 1. Use EXACTLY these markers: {SEARCH_START}, {DIVIDER}, {REPLACE_END}
144
+ 2. The SEARCH block must match existing code EXACTLY (whitespace, indentation, line breaks)
145
+ 3. Generate multiple blocks if needed for different changes
146
+ 4. Include enough context to make search blocks unique
147
+ 5. Do NOT include explanations outside the blocks"""
148
+
149
+ user_prompt = f"""Existing code:
150
+ {last_assistant_msg}
151
+
152
+ Modification instructions:
153
+ {query}
154
+
155
+ Generate the exact search/replace blocks needed."""
156
+
157
+ messages = [
158
+ {"role": "system", "content": system_prompt},
159
+ {"role": "user", "content": user_prompt}
160
+ ]
161
+
162
+ # Generate search/replace instructions
163
+ if hasattr(client, 'chat'):
164
+ if hasattr(client.chat, 'completions'):
165
+ response = client.chat.completions.create(
166
+ model=_current_model['id'],
167
+ messages=messages,
168
+ max_tokens=4000,
169
+ temperature=0.1
170
+ )
171
+ changes_text = response.choices[0].message.content
172
+ else:
173
+ response = client.chat.complete(
174
+ model=_current_model['id'],
175
+ messages=messages,
176
+ max_tokens=4000,
177
+ temperature=0.1
178
+ )
179
+ changes_text = response.choices[0].message.content
180
+ else:
181
+ completion = client.chat.completions.create(
182
+ model=_current_model['id'],
183
+ messages=messages,
184
+ max_tokens=4000,
185
+ temperature=0.1
186
+ )
187
+ changes_text = completion.choices[0].message.content
188
+
189
+ # Apply changes
190
+ if language == "transformers.js" and ('=== index.html ===' in last_assistant_msg):
191
+ modified_content = apply_transformers_js_search_replace_changes(last_assistant_msg, changes_text)
192
+ else:
193
+ modified_content = apply_search_replace_changes(last_assistant_msg, changes_text)
194
+
195
+ # If changes were applied, return modified content
196
+ if modified_content != last_assistant_msg:
197
+ _history.append([query, modified_content])
198
+
199
+ # Generate preview
200
+ preview_val = generate_preview(modified_content, language)
201
+
202
+ yield {
203
+ code_output: modified_content,
204
+ history: _history,
205
+ sandbox: preview_val,
206
+ history_output: history_to_chatbot_messages(_history),
207
+ }
208
+ return
209
+
210
+ except Exception as e:
211
+ print(f"Search/replace failed, falling back to normal generation: {e}")
212
+
213
+ # Choose appropriate system prompt
214
+ from config import HTML_SYSTEM_PROMPT, TRANSFORMERS_JS_SYSTEM_PROMPT, SVELTE_SYSTEM_PROMPT, GENERIC_SYSTEM_PROMPT
215
+
216
+ if language == "html":
217
+ system_prompt = HTML_SYSTEM_PROMPT
218
+ elif language == "transformers.js":
219
+ system_prompt = TRANSFORMERS_JS_SYSTEM_PROMPT
220
+ elif language == "svelte":
221
+ system_prompt = SVELTE_SYSTEM_PROMPT
222
+ else:
223
+ system_prompt = GENERIC_SYSTEM_PROMPT.format(language=language)
224
+
225
+ messages = history_to_messages(_history, system_prompt)
226
+
227
+ # Process file input
228
+ file_text = ""
229
+ if file:
230
+ file_text = extract_text_from_file(file)
231
+ if file_text:
232
+ file_text = file_text[:5000]
233
+ query = f"{query}\n\n[Reference file content]\n{file_text}"
234
+
235
+ # Process website URL
236
+ if website_url and website_url.strip():
237
+ website_text = extract_website_content(website_url.strip())
238
+ if website_text and not website_text.startswith("Error"):
239
+ website_text = website_text[:8000]
240
+ query = f"{query}\n\n[Website content to redesign]\n{website_text}"
241
+
242
+ # Enhance with web search if enabled
243
+ enhanced_query = enhance_query_with_search(query, enable_search)
244
+
245
+ # Add message
246
+ if vlm_image is not None:
247
+ messages.append(create_multimodal_message(enhanced_query, vlm_image))
248
+ else:
249
+ messages.append({'role': 'user', 'content': enhanced_query})
250
+
251
+ # Generate code using the appropriate client
252
+ try:
253
+ client = get_inference_client(_current_model["id"], provider)
254
+
255
+ # Stream generation
256
+ if hasattr(client, 'chat') and hasattr(client.chat, 'completions'):
257
+ completion = client.chat.completions.create(
258
+ model=_current_model["id"],
259
+ messages=messages,
260
+ stream=True,
261
+ max_tokens=16384
262
+ )
263
+ else:
264
+ # Handle other client types
265
+ completion = client.chat.completions.create(
266
+ model=_current_model["id"],
267
+ messages=messages,
268
+ stream=True,
269
+ max_tokens=16384
270
+ )
271
+
272
+ content = ""
273
+ for chunk in completion:
274
+ chunk_content = None
275
+ if hasattr(chunk, "choices") and chunk.choices:
276
+ if hasattr(chunk.choices[0], "delta") and hasattr(chunk.choices[0].delta, "content"):
277
+ chunk_content = chunk.choices[0].delta.content
278
+
279
+ if chunk_content:
280
+ content += chunk_content
281
+
282
+ # Generate live preview
283
+ clean_code = remove_code_block(content)
284
+ preview_val = generate_preview(clean_code, language)
285
+
286
+ yield {
287
+ code_output: gr.update(value=clean_code, language=get_gradio_language(language)),
288
+ history_output: history_to_chatbot_messages(_history),
289
+ sandbox: preview_val,
290
+ }
291
+
292
+ # Final processing
293
+ final_content = remove_code_block(content)
294
+
295
+ # Apply media generation
296
+ final_content = apply_generated_media_to_html(
297
+ final_content,
298
+ query,
299
+ enable_text_to_image=enable_image_generation,
300
+ enable_image_to_image=enable_image_to_image,
301
+ input_image_data=gen_image,
302
+ image_to_image_prompt=image_to_image_prompt,
303
+ text_to_image_prompt=text_to_image_prompt,
304
+ enable_image_to_video=enable_image_to_video,
305
+ image_to_video_prompt=image_to_video_prompt,
306
+ session_id=session_id,
307
+ enable_text_to_video=enable_text_to_video,
308
+ text_to_video_prompt=text_to_video_prompt,
309
+ enable_text_to_music=enable_text_to_music,
310
+ text_to_music_prompt=text_to_music_prompt,
311
+ )
312
+
313
+ _history.append([query, final_content])
314
+
315
+ # Generate final preview
316
+ preview_val = generate_preview(final_content, language)
317
+
318
+ yield {
319
+ code_output: final_content,
320
+ history: _history,
321
+ sandbox: preview_val,
322
+ history_output: history_to_chatbot_messages(_history),
323
+ }
324
+
325
+ except Exception as e:
326
+ error_message = f"Error: {str(e)}"
327
+ yield {
328
+ code_output: error_message,
329
+ history_output: history_to_chatbot_messages(_history),
330
+ }
331
+
332
+ def create_advanced_ui():
333
+ """Create the advanced professional UI"""
334
+
335
+ # Load saved theme
336
+ current_theme_name = get_saved_theme()
337
+ current_theme = THEME_CONFIGS[current_theme_name]["theme"]
338
+
339
+ # Custom CSS for professional styling
340
+ custom_css = """
341
+ /* Professional styling */
342
+ .gradio-container {
343
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif !important;
344
+ }
345
+
346
+ /* Advanced sidebar styling */
347
+ .advanced-sidebar {
348
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
349
+ border-radius: 16px;
350
+ padding: 24px;
351
+ margin-bottom: 16px;
352
+ }
353
+
354
+ .advanced-sidebar h3 {
355
+ color: white;
356
+ font-weight: 600;
357
+ margin-bottom: 16px;
358
+ font-size: 18px;
359
+ }
360
+
361
+ /* Model cards */
362
+ .model-card {
363
+ background: rgba(255, 255, 255, 0.1);
364
+ backdrop-filter: blur(10px);
365
+ border-radius: 12px;
366
+ padding: 16px;
367
+ margin-bottom: 12px;
368
+ border: 1px solid rgba(255, 255, 255, 0.2);
369
+ }
370
+
371
+ .model-card.selected {
372
+ background: rgba(255, 255, 255, 0.2);
373
+ border-color: rgba(255, 255, 255, 0.4);
374
+ }
375
+
376
+ /* Demo cards */
377
+ .demo-grid {
378
+ display: grid;
379
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
380
+ gap: 16px;
381
+ margin: 20px 0;
382
+ }
383
+
384
+ .demo-card {
385
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
386
+ border-radius: 12px;
387
+ padding: 20px;
388
+ cursor: pointer;
389
+ transition: all 0.3s ease;
390
+ border: 2px solid transparent;
391
+ }
392
+
393
+ .demo-card:hover {
394
+ transform: translateY(-2px);
395
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
396
+ border-color: #667eea;
397
+ }
398
+
399
+ .demo-card h4 {
400
+ color: #2d3748;
401
+ font-weight: 600;
402
+ margin-bottom: 8px;
403
+ }
404
+
405
+ .demo-card p {
406
+ color: #4a5568;
407
+ font-size: 14px;
408
+ line-height: 1.5;
409
+ }
410
+
411
+ .demo-category {
412
+ display: inline-block;
413
+ background: #667eea;
414
+ color: white;
415
+ padding: 4px 8px;
416
+ border-radius: 12px;
417
+ font-size: 12px;
418
+ font-weight: 500;
419
+ margin-bottom: 8px;
420
+ }
421
+
422
+ /* Feature toggles */
423
+ .feature-toggle {
424
+ background: rgba(103, 126, 234, 0.1);
425
+ border: 1px solid rgba(103, 126, 234, 0.3);
426
+ border-radius: 8px;
427
+ padding: 12px;
428
+ margin-bottom: 8px;
429
+ }
430
+
431
+ /* Status indicators */
432
+ .status-indicator {
433
+ display: inline-flex;
434
+ align-items: center;
435
+ gap: 8px;
436
+ font-size: 14px;
437
+ color: #4a5568;
438
+ }
439
+
440
+ .status-dot {
441
+ width: 8px;
442
+ height: 8px;
443
+ border-radius: 50%;
444
+ background: #48bb78;
445
+ }
446
+
447
+ .status-dot.warning {
448
+ background: #ed8936;
449
+ }
450
+
451
+ .status-dot.error {
452
+ background: #f56565;
453
+ }
454
+
455
+ /* Code editor enhancements */
456
+ .code-editor-wrapper {
457
+ border-radius: 8px;
458
+ overflow: hidden;
459
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
460
+ }
461
+
462
+ /* Preview enhancements */
463
+ .preview-container {
464
+ border-radius: 8px;
465
+ overflow: hidden;
466
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
467
+ background: white;
468
+ }
469
+
470
+ /* Deployment section */
471
+ .deployment-section {
472
+ background: linear-gradient(135deg, #84fab0 0%, #8fd3f4 100%);
473
+ border-radius: 12px;
474
+ padding: 20px;
475
+ margin-top: 16px;
476
+ }
477
+
478
+ .deployment-section h4 {
479
+ color: #2d3748;
480
+ font-weight: 600;
481
+ margin-bottom: 12px;
482
+ }
483
+ """
484
+
485
+ # Create the main interface
486
+ with gr.Blocks(
487
+ title="AnyCoder - Advanced AI Code Generator",
488
+ theme=current_theme,
489
+ css=custom_css
490
+ ) as demo:
491
+
492
+ # State management
493
+ history = gr.State([])
494
+ setting = gr.State({"system": from config import HTML_SYSTEM_PROMPT})
495
+ current_model = gr.State(DEFAULT_MODEL)
496
+
497
+ # Header
498
+ with gr.Row():
499
+ with gr.Column(scale=1):
500
+ gr.HTML("""
501
+ <div style='text-align: center; padding: 20px 0;'>
502
+ <h1 style='font-size: 2.5em; font-weight: 700; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 8px;'>
503
+ AnyCoder Pro
504
+ </h1>
505
+ <p style='font-size: 1.1em; color: #4a5568; margin: 0;'>
506
+ Professional AI-Powered Code Generation Platform
507
+ </p>
508
+ </div>
509
+ """)
510
+
511
+ # Main layout
512
+ with gr.Row():
513
+ # Advanced Sidebar
514
+ with gr.Column(scale=1, elem_classes=["advanced-sidebar"]) as sidebar:
515
+ # Login section
516
+ login_button = gr.LoginButton()
517
+
518
+ # Model selection with categories
519
+ with gr.Accordion("πŸ€– Model Selection", open=True):
520
+ # Group models by category
521
+ model_categories = {}
522
+ for model in AVAILABLE_MODELS:
523
+ category = model.get("category", "General")
524
+ if category not in model_categories:
525
+ model_categories[category] = []
526
+ model_categories[category].append(model)
527
+
528
+ model_dropdown = gr.Dropdown(
529
+ choices=[model['name'] for model in AVAILABLE_MODELS],
530
+ value=DEFAULT_MODEL['name'],
531
+ label="Select Model",
532
+ info="Choose the AI model for code generation"
533
+ )
534
+
535
+ # Model info display
536
+ model_info = gr.Markdown(DEFAULT_MODEL['description'])
537
+
538
+ # Project management
539
+ with gr.Accordion("πŸ“ Project Management", open=False):
540
+ gr.Markdown("**Import Existing Project**")
541
+ load_project_url = gr.Textbox(
542
+ label="Project URL",
543
+ placeholder="https://huggingface.co/spaces/user/space",
544
+ info="Import from HF Spaces, GitHub, or HF Models"
545
+ )
546
+ load_project_btn = gr.Button("Import Project", variant="secondary")
547
+ load_project_status = gr.Markdown(visible=False)
548
+
549
+ # Code generation settings
550
+ with gr.Accordion("βš™οΈ Generation Settings", open=True):
551
+ language_dropdown = gr.Dropdown(
552
+ choices=["html", "streamlit", "gradio", "python", "transformers.js", "svelte"],
553
+ value="html",
554
+ label="Framework/Language",
555
+ info="Select the target framework"
556
+ )
557
+
558
+ enable_search = gr.Checkbox(
559
+ label="πŸ” Web Search Enhancement",
560
+ value=False,
561
+ info="Use real-time web search for up-to-date information"
562
+ )
563
+
564
+ if tavily_client:
565
+ search_status = gr.HTML("""
566
+ <div class="status-indicator">
567
+ <div class="status-dot"></div>
568
+ <span>Web search available</span>
569
+ </div>
570
+ """)
571
+ else:
572
+ search_status = gr.HTML("""
573
+ <div class="status-indicator">
574
+ <div class="status-dot error"></div>
575
+ <span>Web search unavailable</span>
576
+ </div>
577
+ """)
578
+
579
+ # Media generation features
580
+ with gr.Accordion("🎨 AI Media Generation", open=False):
581
+ enable_image_generation = gr.Checkbox(
582
+ label="Generate Images (Text β†’ Image)",
583
+ value=False,
584
+ info="Auto-generate images using Qwen-Image"
585
+ )
586
+
587
+ text_to_image_prompt = gr.Textbox(
588
+ label="Image Generation Prompt",
589
+ placeholder="Describe the image to generate...",
590
+ lines=2,
591
+ visible=False
592
+ )
593
+
594
+ enable_image_to_image = gr.Checkbox(
595
+ label="Transform Images (Image β†’ Image)",
596
+ value=False,
597
+ info="Transform uploaded images using AI"
598
+ )
599
+
600
+ image_to_image_prompt = gr.Textbox(
601
+ label="Image Transformation Prompt",
602
+ placeholder="Describe how to transform the image...",
603
+ lines=2,
604
+ visible=False
605
+ )
606
+
607
+ enable_image_to_video = gr.Checkbox(
608
+ label="Generate Videos (Image β†’ Video)",
609
+ value=False,
610
+ info="Create videos from uploaded images"
611
+ )
612
+
613
+ enable_text_to_video = gr.Checkbox(
614
+ label="Generate Videos (Text β†’ Video)",
615
+ value=False,
616
+ info="Create videos from text descriptions"
617
+ )
618
+
619
+ enable_text_to_music = gr.Checkbox(
620
+ label="Generate Music (Text β†’ Music)",
621
+ value=False,
622
+ info="Compose music from text descriptions"
623
+ )
624
+
625
+ # Input section
626
+ with gr.Accordion("πŸ“ Input & Files", open=True):
627
+ user_input = gr.Textbox(
628
+ label="What would you like to build?",
629
+ placeholder="Describe your application in detail...",
630
+ lines=4,
631
+ info="Be specific about features, design, and functionality"
632
+ )
633
+
634
+ website_url_input = gr.Textbox(
635
+ label="Website URL (for redesign)",
636
+ placeholder="https://example.com",
637
+ info="URL of website to redesign"
638
+ )
639
+
640
+ file_input = gr.File(
641
+ label="Reference Files",
642
+ file_types=[".pdf", ".txt", ".md", ".csv", ".docx", ".jpg", ".png"],
643
+ info="Upload reference documents or images"
644
+ )
645
+
646
+ vlm_image = gr.Image(
647
+ label="Design Reference Image",
648
+ visible=False,
649
+ info="Upload UI mockup or design reference"
650
+ )
651
+
652
+ generation_image = gr.Image(
653
+ label="Image for Generation",
654
+ visible=False,
655
+ info="Upload image for AI processing"
656
+ )
657
+
658
+ # Action buttons
659
+ with gr.Row():
660
+ generate_btn = gr.Button("πŸš€ Generate", variant="primary", scale=2)
661
+ clear_btn = gr.Button("πŸ—‘οΈ Clear", variant="secondary", scale=1)
662
+
663
+ # Main content area
664
+ with gr.Column(scale=3):
665
+ # Quick start section
666
+ with gr.Row():
667
+ gr.HTML("""
668
+ <div style='background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); border-radius: 12px; padding: 20px; margin-bottom: 20px;'>
669
+ <h3 style='color: white; margin: 0 0 16px 0; font-weight: 600;'>Quick Start Examples</h3>
670
+ <div class='demo-grid'>
671
+ """)
672
+
673
+ # Demo cards
674
+ demo_cards = []
675
+ for i, demo in enumerate(DEMO_LIST[:6]): # Show first 6 demos
676
+ demo_card = gr.Button(
677
+ f"""
678
+ <div class='demo-card'>
679
+ <div class='demo-category'>{demo.get('category', 'General')}</div>
680
+ <h4>{demo['title']}</h4>
681
+ <p>{demo['description']}</p>
682
+ </div>
683
+ """,
684
+ variant="secondary",
685
+ elem_classes=["demo-card-btn"]
686
+ )
687
+ demo_cards.append(demo_card)
688
+
689
+ gr.HTML("</div></div>")
690
+
691
+ # Main tabs
692
+ with gr.Tabs() as main_tabs:
693
+ # Preview tab
694
+ with gr.Tab("πŸ–₯️ Live Preview"):
695
+ sandbox = gr.HTML(
696
+ label="Live Preview",
697
+ elem_classes=["preview-container"]
698
+ )
699
+
700
+ # Code editor tab
701
+ with gr.Tab("πŸ“ Code Editor"):
702
+ with gr.Row():
703
+ with gr.Column():
704
+ code_output = gr.Code(
705
+ language="html",
706
+ lines=30,
707
+ interactive=True,
708
+ label="Generated Code",
709
+ elem_classes=["code-editor-wrapper"]
710
+ )
711
+
712
+ # Multi-file editors (hidden by default)
713
+ with gr.Group(visible=False) as transformers_group:
714
+ with gr.Tabs():
715
+ with gr.Tab("index.html"):
716
+ tjs_html_code = gr.Code(language="html", lines=25, interactive=True)
717
+ with gr.Tab("index.js"):
718
+ tjs_js_code = gr.Code(language="javascript", lines=25, interactive=True)
719
+ with gr.Tab("style.css"):
720
+ tjs_css_code = gr.Code(language="css", lines=25, interactive=True)
721
+
722
+ # Deployment section
723
+ with gr.Group(elem_classes=["deployment-section"], visible=False) as deployment_section:
724
+ gr.Markdown("### πŸš€ Deploy Your Application")
725
+
726
+ with gr.Row():
727
+ space_name_input = gr.Textbox(
728
+ label="App Name",
729
+ placeholder="my-awesome-app",
730
+ scale=2
731
+ )
732
+
733
+ sdk_dropdown = gr.Dropdown(
734
+ choices=["Static (HTML)", "Gradio (Python)", "Streamlit (Python)", "Transformers.js", "Svelte"],
735
+ value="Static (HTML)",
736
+ label="App Type",
737
+ scale=1
738
+ )
739
+
740
+ with gr.Row():
741
+ deploy_btn = gr.Button("πŸš€ Deploy to Spaces", variant="primary", scale=2)
742
+ deploy_status = gr.Markdown("", scale=3)
743
+
744
+ # Hidden components for state management
745
+ history_output = gr.Chatbot(visible=False, type="messages")
746
+
747
+ # Event handlers
748
+ def on_model_change(model_name):
749
+ for m in AVAILABLE_MODELS:
750
+ if m['name'] == model_name:
751
+ return m, gr.update(value=m['description']), update_image_input_visibility(m)
752
+ return AVAILABLE_MODELS[0], gr.update(value=AVAILABLE_MODELS[0]['description']), gr.update(visible=False)
753
+
754
+ def on_demo_click(demo_index):
755
+ if 0 <= demo_index < len(DEMO_LIST):
756
+ return DEMO_LIST[demo_index]['description']
757
+ return ""
758
+
759
+ def toggle_media_prompts(image_gen, img2img, img2vid, txt2vid, txt2music):
760
+ return [
761
+ gr.update(visible=image_gen), # text_to_image_prompt
762
+ gr.update(visible=img2img), # image_to_image_prompt
763
+ gr.update(visible=img2img or img2vid), # generation_image
764
+ ]
765
+
766
+ def show_deployment_section():
767
+ return gr.update(visible=True)
768
+
769
+ def handle_import_project(url):
770
+ if not url.strip():
771
+ return gr.update(value="Please enter a URL.", visible=True), "", ""
772
+
773
+ status, code = load_project_from_url(url)
774
+ return gr.update(value=status, visible=True), code, gr.update(value="", visible=False)
775
+
776
+ # Wire up events
777
+ model_dropdown.change(
778
+ on_model_change,
779
+ inputs=[model_dropdown],
780
+ outputs=[current_model, model_info, vlm_image]
781
+ )
782
+
783
+ # Demo card clicks
784
+ for i, card in enumerate(demo_cards):
785
+ card.click(
786
+ lambda idx=i: on_demo_click(idx),
787
+ outputs=[user_input]
788
+ )
789
+
790
+ # Media generation toggles
791
+ for toggle in [enable_image_generation, enable_image_to_image, enable_image_to_video]:
792
+ toggle.change(
793
+ toggle_media_prompts,
794
+ inputs=[enable_image_generation, enable_image_to_image, enable_image_to_video, enable_text_to_video, enable_text_to_music],
795
+ outputs=[text_to_image_prompt, image_to_image_prompt, generation_image]
796
+ )
797
+
798
+ # Main generation
799
+ generate_btn.click(
800
+ generation_code,
801
+ inputs=[
802
+ user_input, vlm_image, generation_image, file_input, website_url_input,
803
+ setting, history, current_model, enable_search, language_dropdown,
804
+ gr.State("auto"), enable_image_generation, enable_image_to_image,
805
+ image_to_image_prompt, text_to_image_prompt, enable_image_to_video,
806
+ gr.State(None), enable_text_to_video, gr.State(None), enable_text_to_music, gr.State(None)
807
+ ],
808
+ outputs=[code_output, history, sandbox, history_output]
809
+ ).then(
810
+ show_deployment_section,
811
+ outputs=[deployment_section]
812
+ )
813
+
814
+ # Project import
815
+ load_project_btn.click(
816
+ handle_import_project,
817
+ inputs=[load_project_url],
818
+ outputs=[load_project_status, code_output, load_project_url]
819
+ )
820
+
821
+ # Clear functionality
822
+ clear_btn.click(
823
+ clear_history,
824
+ outputs=[history, history_output, file_input, website_url_input]
825
+ )
826
+
827
+ # Deployment
828
+ deploy_btn.click(
829
+ deploy_to_user_space,
830
+ inputs=[code_output, space_name_input, sdk_dropdown],
831
+ outputs=[deploy_status]
832
+ )
833
+
834
+ return demo
835
+
836
+ # Main application entry point
837
+ if __name__ == "__main__":
838
+ # Clean up any orphaned temporary files
839
+ cleanup_all_temp_media()
840
+
841
+ # Create and launch the application
842
+ demo = create_advanced_ui()
843
+ demo.queue(api_open=False, default_concurrency_limit=20).launch(
844
+ show_api=False,
845
+ server_name="0.0.0.0",
846
+ server_port=7860,
847
+ ssr_mode=True
848
+ )