acecalisto3 commited on
Commit
ada947c
1 Parent(s): f72d856

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +987 -418
app.py CHANGED
@@ -1,136 +1,42 @@
1
  import gradio as gr
2
- import subprocess
3
- import random
4
  import json
5
- import os
 
6
  import tempfile
 
7
  from pathlib import Path
8
- from datetime import datetime
9
- import logging
10
- from typing import Dict, List, Any, Optional
11
- import yaml
12
 
13
  # Configure logging
14
- logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
 
 
 
 
 
 
 
15
  logger = logging.getLogger(__name__)
16
 
17
- # Template Categories and Configurations
18
- TEMPLATE_CATEGORIES = {
19
- "Chat Applications": {
20
- "Basic Chat": {
21
- "components": [
22
- {"type": "Chatbot", "label": "Chat History"},
23
- {"type": "Textbox", "label": "User Input", "placeholder": "Type your message..."},
24
- {"type": "Button", "label": "Send", "variant": "primary"},
25
- {"type": "Radio", "label": "Model", "choices": ["GPT-3.5", "GPT-4", "Claude", "Custom"]},
26
- {"type": "Slider", "label": "Temperature", "minimum": 0, "maximum": 1, "step": 0.1},
27
- {"type": "Checkbox", "label": "Stream Output"},
28
- ],
29
- "layout": "vertical",
30
- "css": """
31
- .chat-container { max-width: 800px; margin: auto; }
32
- .message { padding: 10px; margin: 5px; border-radius: 5px; }
33
- .user { background: #e3f2fd; }
34
- .bot { background: #f5f5f5; }
35
- """
36
- },
37
- "Advanced Chat": {
38
- "components": [
39
- {"type": "Chatbot", "label": "Chat History"},
40
- {"type": "Textbox", "label": "User Input", "placeholder": "Type your message..."},
41
- {"type": "Button", "label": "Send", "variant": "primary"},
42
- {"type": "Dropdown", "label": "Model", "choices": ["GPT-3.5", "GPT-4", "Claude", "Custom"]},
43
- {"type": "Slider", "label": "Temperature", "minimum": 0, "maximum": 1, "step": 0.1},
44
- {"type": "Slider", "label": "Max Length", "minimum": 100, "maximum": 2000, "step": 100},
45
- {"type": "Checkbox", "label": "Stream Output"},
46
- {"type": "File", "label": "Upload Context", "file_types": [".txt", ".pdf"]},
47
- {"type": "Dropdown", "label": "Language", "choices": ["English", "Spanish", "French", "German"]},
48
- {"type": "Radio", "label": "Mode", "choices": ["Chat", "Completion", "QA"]},
49
- ],
50
- "layout": "vertical",
51
- "dependencies": ["openai", "transformers", "langchain"]
52
- }
53
- },
54
- "Audio Generation": {
55
- "Music Generator": {
56
- "components": [
57
- {"type": "Audio", "label": "Generated Audio", "source": "microphone"},
58
- {"type": "Textbox", "label": "Prompt", "placeholder": "Describe the music..."},
59
- {"type": "Dropdown", "label": "Style", "choices": ["Classical", "Jazz", "Rock", "Electronic"]},
60
- {"type": "Slider", "label": "Duration (seconds)", "minimum": 5, "maximum": 60},
61
- {"type": "Button", "label": "Generate", "variant": "primary"},
62
- {"type": "File", "label": "Download", "file_types": [".mp3", ".wav"]},
63
- ],
64
- "layout": "vertical",
65
- "dependencies": ["audiocraft", "torchaudio"]
66
- }
67
- },
68
- "Image Processing": {
69
- "Image Generator": {
70
- "components": [
71
- {"type": "Image", "label": "Generated Image"},
72
- {"type": "Textbox", "label": "Prompt", "placeholder": "Describe the image..."},
73
- {"type": "Dropdown", "label": "Model", "choices": ["Stable Diffusion", "DALL-E", "Midjourney"]},
74
- {"type": "Slider", "label": "Steps", "minimum": 20, "maximum": 100},
75
- {"type": "Button", "label": "Generate", "variant": "primary"},
76
- ],
77
- "layout": "vertical",
78
- "dependencies": ["diffusers", "torch"]
79
- },
80
- "Image Editor": {
81
- "components": [
82
- {"type": "Image", "label": "Input Image", "source": "upload"},
83
- {"type": "Image", "label": "Output Image"},
84
- {"type": "Dropdown", "label": "Effect", "choices": ["Blur", "Sharpen", "Style Transfer"]},
85
- {"type": "Slider", "label": "Intensity", "minimum": 0, "maximum": 1, "step": 0.1},
86
- {"type": "Button", "label": "Apply", "variant": "primary"},
87
- ],
88
- "layout": "horizontal",
89
- "dependencies": ["pillow", "opencv-python"]
90
- }
91
- },
92
- "3D Processing": {
93
- "3D Model Viewer": {
94
- "components": [
95
- {"type": "Model3D", "label": "3D Model"},
96
- {"type": "File", "label": "Upload Model", "file_types": [".obj", ".glb", ".gltf"]},
97
- {"type": "Checkbox", "label": "Show Wireframe"},
98
- {"type": "ColorPicker", "label": "Background Color"},
99
- {"type": "Slider", "label": "Camera Distance", "minimum": 1, "maximum": 10},
100
- ],
101
- "layout": "vertical",
102
- "dependencies": ["pygltflib", "trimesh"]
103
- }
104
- },
105
- "Data Analysis": {
106
- "Data Explorer": {
107
- "components": [
108
- {"type": "File", "label": "Upload Dataset", "file_types": [".csv", ".xlsx"]},
109
- {"type": "Dataframe", "label": "Data Preview"},
110
- {"type": "Dropdown", "label": "Chart Type", "choices": ["Line", "Bar", "Scatter", "Histogram"]},
111
- {"type": "Dropdown", "label": "X Axis"},
112
- {"type": "Dropdown", "label": "Y Axis"},
113
- {"type": "Plot", "label": "Visualization"},
114
- ],
115
- "layout": "vertical",
116
- "dependencies": ["pandas", "plotly"]
117
- }
118
- }
119
- }
120
-
121
- # Enhanced Component Registry with Categories
122
  COMPONENT_CATEGORIES = {
123
- "Basic Input": {
124
  "Textbox": {
 
125
  "properties": {
126
  "label": "Text Input",
127
- "placeholder": "Enter text...",
128
  "lines": 1,
129
  "type": "text"
130
  },
131
- "code_snippet": 'gr.Textbox(label="{label}", placeholder="{placeholder}", lines={lines})'
132
  },
133
  "Number": {
 
134
  "properties": {
135
  "label": "Number Input",
136
  "value": 0,
@@ -139,390 +45,1053 @@ COMPONENT_CATEGORIES = {
139
  },
140
  "code_snippet": 'gr.Number(label="{label}", value={value}, minimum={minimum}, maximum={maximum})'
141
  },
142
- "Slider": {
 
143
  "properties": {
144
- "label": "Slider",
145
- "minimum": 0,
146
- "maximum": 100,
147
- "step": 1,
148
- "value": 50
149
  },
150
- "code_snippet": 'gr.Slider(label="{label}", minimum={minimum}, maximum={maximum}, step={step}, value={value})'
151
  }
152
  },
153
- "Media Input": {
154
  "Image": {
 
155
  "properties": {
156
- "label": "Image Input",
 
 
157
  "source": "upload",
158
- "tool": "select",
159
- "type": "filepath"
160
  },
161
- "code_snippet": 'gr.Image(label="{label}", source="{source}", tool="{tool}", type="{type}")'
162
  },
163
  "Audio": {
 
164
  "properties": {
165
- "label": "Audio Input",
166
  "source": "upload",
167
- "type": "filepath"
168
  },
169
  "code_snippet": 'gr.Audio(label="{label}", source="{source}", type="{type}")'
170
  },
171
  "Video": {
 
172
  "properties": {
173
- "label": "Video Input",
174
- "source": "upload",
175
- "format": "mp4"
176
  },
177
- "code_snippet": 'gr.Video(label="{label}", source="{source}", format="{format}")'
178
  }
179
  },
180
- "Control Elements": {
181
- "Button": {
182
- "properties": {
183
- "label": "Click Me",
184
- "variant": "primary",
185
- "size": "sm"
186
- },
187
- "code_snippet": 'gr.Button(value="{label}", variant="{variant}", size="{size}")'
188
- },
189
- "Checkbox": {
190
  "properties": {
191
- "label": "Check this",
192
- "value": False
 
193
  },
194
- "code_snippet": 'gr.Checkbox(label="{label}", value={value})'
195
  },
196
  "Radio": {
 
197
  "properties": {
198
- "label": "Select One",
199
- "choices": ["Option 1", "Option 2", "Option 3"],
200
- "value": "Option 1"
201
  },
202
- "code_snippet": 'gr.Radio(label="{label}", choices={choices}, value="{value}")'
203
- }
204
- },
205
- "Advanced Input": {
206
- "JSON": {
207
- "properties": {
208
- "label": "JSON Input",
209
- "value": "{}"
210
- },
211
- "code_snippet": 'gr.JSON(label="{label}", value={value})'
212
  },
213
- "File": {
 
214
  "properties": {
215
- "label": "File Upload",
216
- "file_types": [".txt", ".pdf", ".csv"],
217
- "multiple": False
218
  },
219
- "code_snippet": 'gr.File(label="{label}", file_types={file_types}, multiple={multiple})'
 
 
 
 
 
 
 
 
 
 
 
 
220
  },
221
- "Dataframe": {
222
- "properties": {
223
- "label": "Data Table",
224
- "headers": ["Column 1", "Column 2"],
225
- "interactive": True
226
- },
227
- "code_snippet": 'gr.Dataframe(label="{label}", headers={headers}, interactive={interactive})'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
228
  }
229
  },
230
- "Output Display": {
231
- "Label": {
232
- "properties": {
233
- "label": "Output Label",
234
- "value": "Result will appear here..."
235
- },
236
- "code_snippet": 'gr.Label(label="{label}", value="{value}")'
237
- },
238
- "Plot": {
239
- "properties": {
240
- "label": "Plot Output",
241
- "type": "line"
242
- },
243
- "code_snippet": 'gr.Plot(label="{label}")'
244
- },
245
- "HTML": {
246
- "properties": {
247
- "label": "HTML Output",
248
- "value": "<div>HTML content here</div>"
249
- },
250
- "code_snippet": 'gr.HTML(label="{label}", value="""{value}""")'
 
 
 
 
 
 
 
 
251
  }
252
  }
253
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
  class ComponentManager:
255
  def __init__(self):
256
- self.categories = COMPONENT_CATEGORIES
257
- self.templates = TEMPLATE_CATEGORIES
258
- self.active_components = []
259
- self.dependencies = set()
260
 
261
- def get_component_info(self, category: str, component_type: str) -> Dict:
262
- """Get component information from registry"""
263
- return self.categories[category][component_type]
 
 
264
 
265
- def add_component(self, category: str, component_type: str, properties: Dict = None) -> Dict:
266
- """Add a component with specified properties"""
267
- component_info = self.get_component_info(category, component_type)
268
- component_id = f"{component_type}_{len(self.active_components)}"
269
-
270
- new_component = {
271
- "id": component_id,
272
- "type": component_type,
273
- "category": category,
274
- "properties": properties or component_info["properties"].copy(),
275
- "code_snippet": component_info["code_snippet"]
276
- }
277
-
278
- self.active_components.append(new_component)
279
- return new_component
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
280
 
281
- def remove_component(self, component_id: str):
282
  """Remove a component by ID"""
283
- self.active_components = [c for c in self.active_components if c["id"] != component_id]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
284
 
285
- def update_component(self, component_id: str, properties: Dict):
286
- """Update component properties"""
287
- for component in self.active_components:
288
- if component["id"] == component_id:
289
- component["properties"].update(properties)
290
- break
 
 
 
 
 
 
 
 
 
 
291
 
292
  class TemplateManager:
293
  def __init__(self):
294
  self.templates = TEMPLATE_CATEGORIES
295
- self.component_manager = ComponentManager()
296
 
297
- def load_template(self, category: str, template_name: str) -> Dict:
298
- """Load a template configuration"""
299
- template = self.templates[category][template_name]
300
- self.component_manager.active_components = []
301
- self.component_manager.dependencies = set(template.get("dependencies", []))
302
-
303
- # Add components from template
304
- for component_config in template["components"]:
305
- component_type = component_config.pop("type")
306
- # Find category for component type
307
- for cat, components in COMPONENT_CATEGORIES.items():
308
- if component_type in components:
309
- self.component_manager.add_component(cat, component_type, component_config)
310
- break
311
-
312
- return {
313
- "layout": template.get("layout", "vertical"),
314
- "css": template.get("css", ""),
315
- "dependencies": list(self.component_manager.dependencies)
316
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
317
 
318
  class CodeGenerator:
319
  def __init__(self, template_manager: TemplateManager):
320
  self.template_manager = template_manager
 
321
 
322
- def generate_imports(self) -> str:
323
- """Generate import statements"""
324
- imports = [
325
- "import gradio as gr",
326
- "import os",
327
- "import logging",
328
- "from pathlib import Path",
329
- ]
330
-
331
- # Add template-specific imports
332
- if self.template_manager.component_manager.dependencies:
333
- imports.extend([f"import {dep}" for dep in self.template_manager.component_manager.dependencies])
334
 
335
- return "\n".join(imports) + "\n\n"
 
 
 
 
 
 
 
 
336
 
337
- def generate_component_code(self, component: Dict) -> str:
338
- """Generate code for a single component"""
339
- try:
340
- return component["code_snippet"].format(**component["properties"])
341
- except KeyError as e:
342
- logger.error(f"Missing property {e} for component {component['id']}")
343
- return f"# Error generating code for {component['id']}"
344
-
345
- def generate_layout_code(self, layout: str, components: List[Dict]) -> str:
346
- """Generate layout code"""
347
- indent = " "
348
- code = []
349
 
350
- if layout == "horizontal":
351
- code.append("with gr.Row():")
352
- indent = " "
353
- elif layout == "vertical":
354
- code.append("with gr.Column():")
355
- indent = " "
 
356
 
 
 
 
 
 
 
 
 
357
  for component in components:
358
- code.append(f"{indent}{self.generate_component_code(component)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
359
 
360
- return "\n".join(code)
361
 
362
- def generate_full_code(self, app_name: str, template_config: Dict) -> str:
363
- """Generate complete application code"""
364
- code_parts = [
365
- self.generate_imports(),
366
- "# Configure logging",
367
- 'logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")',
368
- 'logger = logging.getLogger(__name__)\n',
369
  ]
370
 
371
- # Add CSS if present
372
- if template_config.get("css"):
373
- code_parts.extend([
374
- "# Custom CSS",
375
- f'custom_css = """{template_config["css"]}"""',
376
- ""
377
- ])
378
-
379
- # Start app definition
380
- code_parts.extend([
381
- f"def create_{app_name}():",
382
- " with gr.Blocks(css=custom_css) as app:",
383
- f' gr.Markdown("# {app_name}")\n'
384
- ])
 
 
 
 
 
 
385
 
386
- # Add layout code
387
- code_parts.append(self.generate_layout_code(
388
- template_config["layout"],
389
- self.template_manager.component_manager.active_components
390
- ))
391
 
392
  # Add launch code
393
- code_parts.extend([
394
- "\n return app",
395
- "\nif __name__ == '__main__':",
396
- f" app = create_{app_name}()",
397
- " app.launch(debug=True)"
398
  ])
399
 
400
- return "\n".join(code_parts)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
401
 
402
  class AppBuilder:
403
  def __init__(self):
 
 
404
  self.template_manager = TemplateManager()
405
  self.code_generator = CodeGenerator(self.template_manager)
406
- self.current_app_name = ""
407
- self.current_template = None
408
-
409
- def create_interface(self):
410
- with gr.Blocks(theme=gr.themes.Default()) as interface:
411
- gr.Markdown("# 🚀 Advanced Gradio App Builder")
412
-
413
- with gr.Tabs():
414
- # Template Selection Tab
415
- with gr.TabItem("📋 Templates"):
416
- with gr.Row():
417
- template_category = gr.Dropdown(
418
- choices=list(TEMPLATE_CATEGORIES.keys()),
419
- label="Category"
420
- )
421
- template_name = gr.Dropdown(
422
- label="Template"
423
- )
424
-
425
- app_name = gr.Textbox(label="Application Name")
426
- load_template_btn = gr.Button("Load Template", variant="primary")
427
- template_info = gr.JSON(label="Template Information")
428
-
429
- # Component Editor Tab
430
- with gr.TabItem("🔧 Components"):
431
- with gr.Row():
432
- with gr.Column(scale=1):
433
- component_category = gr.Dropdown(
434
- choices=list(COMPONENT_CATEGORIES.keys()),
435
- label="Component Category"
436
- )
437
- component_type = gr.Dropdown(
438
- label="Component Type"
439
- )
440
- add_component_btn = gr.Button("Add Component")
441
-
442
- with gr.Column(scale=2):
443
- component_list = gr.JSON(label="Active Components")
444
- component_properties = gr.JSON(label="Component Properties")
445
-
446
- # Code Preview Tab
447
- with gr.TabItem("💻 Code"):
448
- generate_code_btn = gr.Button("Generate Code")
449
- code_output = gr.Code(language="python")
450
-
451
- # Preview Tab
452
- with gr.TabItem("👁️ Preview"):
453
- preview_btn = gr.Button("Update Preview")
454
- preview_area = gr.HTML()
455
-
456
- # Event handlers
457
- def update_template_choices(category):
458
- return gr.Dropdown(choices=list(TEMPLATE_CATEGORIES[category].keys()))
459
-
460
- def update_component_choices(category):
461
- return gr.Dropdown(choices=list(COMPONENT_CATEGORIES[category].keys()))
462
-
463
- def load_template(category, template_name, app_name):
464
- if not app_name:
465
- return "Please enter an application name", None
466
-
467
- self.current_app_name = app_name
468
- template_config = self.template_manager.load_template(category, template_name)
469
- self.current_template = template_config
470
- return "Template loaded successfully", template_config
471
-
472
- def add_component(category, component_type):
473
- if not self.current_template:
474
- return "Please load a template first", None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
475
 
476
- new_component = self.template_manager.component_manager.add_component(
477
- category, component_type
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
478
  )
479
- return (
480
- "Component added successfully",
481
- self.template_manager.component_manager.active_components
482
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
483
 
484
- def generate_code():
485
- if not self.current_template or not self.current_app_name:
486
- return "Please load a template first"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
487
 
488
- return self.code_generator.generate_full_code(
489
- self.current_app_name,
490
- self.current_template
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
491
  )
 
 
 
 
 
 
 
 
492
 
493
- # Connect events
494
- template_category.change(
495
- update_template_choices,
496
- inputs=[template_category],
497
- outputs=[template_name]
498
- )
499
 
500
- component_category.change(
501
- update_component_choices,
502
- inputs=[component_category],
503
- outputs=[component_type]
504
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
505
 
506
- load_template_btn.click(
507
- load_template,
508
- inputs=[template_category, template_name, app_name],
509
- outputs=[template_info, component_list]
510
- )
511
 
512
- add_component_btn.click(
513
- add_component,
514
- inputs=[component_category, component_type],
515
- outputs=[component_list, component_properties]
516
- )
 
 
 
 
 
517
 
518
- generate_code_btn.click(
519
- generate_code,
520
- outputs=[code_output]
521
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
522
 
523
- return interface
 
 
 
 
 
 
 
 
 
 
 
 
 
524
 
525
  if __name__ == "__main__":
526
- builder = AppBuilder()
527
- interface = builder.create_interface()
528
- interface.launch(server_port=7860, share=True, debug=True)
 
1
  import gradio as gr
2
+ import logging
 
3
  import json
4
+ import re
5
+ import torch
6
  import tempfile
7
+ import subprocess
8
  from pathlib import Path
9
+ from typing import Dict, List, Tuple, Optional, Any
10
+ from dataclasses import dataclass
11
+ from enum import Enum
12
+ from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
13
 
14
  # Configure logging
15
+ logging.basicConfig(
16
+ level=logging.INFO,
17
+ format='%(asctime)s - %(levelname)s - %(message)s',
18
+ handlers=[
19
+ logging.StreamHandler(),
20
+ logging.FileHandler('gradio_builder.log')
21
+ ]
22
+ )
23
  logger = logging.getLogger(__name__)
24
 
25
+ # Constants and Default Configurations
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  COMPONENT_CATEGORIES = {
27
+ "Basic": {
28
  "Textbox": {
29
+ "description": "Text input component",
30
  "properties": {
31
  "label": "Text Input",
32
+ "placeholder": "",
33
  "lines": 1,
34
  "type": "text"
35
  },
36
+ "code_snippet": 'gr.Textbox(label="{label}", placeholder="{placeholder}", lines={lines}, type="{type}")'
37
  },
38
  "Number": {
39
+ "description": "Numeric input component",
40
  "properties": {
41
  "label": "Number Input",
42
  "value": 0,
 
45
  },
46
  "code_snippet": 'gr.Number(label="{label}", value={value}, minimum={minimum}, maximum={maximum})'
47
  },
48
+ "Button": {
49
+ "description": "Clickable button component",
50
  "properties": {
51
+ "text": "Button",
52
+ "variant": "primary"
 
 
 
53
  },
54
+ "code_snippet": 'gr.Button(value="{text}", variant="{variant}")'
55
  }
56
  },
57
+ "Media": {
58
  "Image": {
59
+ "description": "Image display/upload component",
60
  "properties": {
61
+ "label": "Image",
62
+ "shape": None,
63
+ "image_mode": "RGB",
64
  "source": "upload",
65
+ "type": "numpy"
 
66
  },
67
+ "code_snippet": 'gr.Image(label="{label}", shape={shape}, image_mode="{image_mode}", source="{source}", type="{type}")'
68
  },
69
  "Audio": {
70
+ "description": "Audio player/recorder component",
71
  "properties": {
72
+ "label": "Audio",
73
  "source": "upload",
74
+ "type": "numpy"
75
  },
76
  "code_snippet": 'gr.Audio(label="{label}", source="{source}", type="{type}")'
77
  },
78
  "Video": {
79
+ "description": "Video player component",
80
  "properties": {
81
+ "label": "Video",
82
+ "source": "upload"
 
83
  },
84
+ "code_snippet": 'gr.Video(label="{label}", source="{source}")'
85
  }
86
  },
87
+ "Selection": {
88
+ "Dropdown": {
89
+ "description": "Dropdown selection component",
 
 
 
 
 
 
 
90
  "properties": {
91
+ "label": "Dropdown",
92
+ "choices": [],
93
+ "multiselect": False
94
  },
95
+ "code_snippet": 'gr.Dropdown(label="{label}", choices={choices}, multiselect={multiselect})'
96
  },
97
  "Radio": {
98
+ "description": "Radio button group component",
99
  "properties": {
100
+ "label": "Radio Group",
101
+ "choices": [],
102
+ "type": "value"
103
  },
104
+ "code_snippet": 'gr.Radio(label="{label}", choices={choices}, type="{type}")'
 
 
 
 
 
 
 
 
 
105
  },
106
+ "Checkbox": {
107
+ "description": "Checkbox component",
108
  "properties": {
109
+ "label": "Checkbox",
110
+ "value": False
 
111
  },
112
+ "code_snippet": 'gr.Checkbox(label="{label}", value={value})'
113
+ }
114
+ }
115
+ }
116
+
117
+ TEMPLATE_CATEGORIES = {
118
+ "Basic": {
119
+ "Empty": {
120
+ "description": "Empty application template",
121
+ "components": [],
122
+ "layout": "vertical",
123
+ "css": "",
124
+ "dependencies": []
125
  },
126
+ "Text Input/Output": {
127
+ "description": "Simple text input/output template",
128
+ "components": [
129
+ {
130
+ "type": "Textbox",
131
+ "properties": {
132
+ "label": "Input",
133
+ "lines": 3
134
+ }
135
+ },
136
+ {
137
+ "type": "Button",
138
+ "properties": {
139
+ "text": "Process",
140
+ "variant": "primary"
141
+ }
142
+ },
143
+ {
144
+ "type": "Textbox",
145
+ "properties": {
146
+ "label": "Output",
147
+ "lines": 3
148
+ }
149
+ }
150
+ ],
151
+ "layout": "vertical",
152
+ "css": "",
153
+ "dependencies": []
154
  }
155
  },
156
+ "Media": {
157
+ "Image Processing": {
158
+ "description": "Image processing template",
159
+ "components": [
160
+ {
161
+ "type": "Image",
162
+ "properties": {
163
+ "label": "Input Image",
164
+ "source": "upload"
165
+ }
166
+ },
167
+ {
168
+ "type": "Button",
169
+ "properties": {
170
+ "text": "Process",
171
+ "variant": "primary"
172
+ }
173
+ },
174
+ {
175
+ "type": "Image",
176
+ "properties": {
177
+ "label": "Output Image",
178
+ "source": "upload"
179
+ }
180
+ }
181
+ ],
182
+ "layout": "vertical",
183
+ "css": "",
184
+ "dependencies": ["PIL"]
185
  }
186
  }
187
  }
188
+
189
+ DEFAULT_THEMES = {
190
+ "Light": """
191
+ /* Light theme CSS */
192
+ .gradio-container {
193
+ font-family: 'Arial', sans-serif;
194
+ background-color: #ffffff;
195
+ }
196
+ .gradio-button {
197
+ background-color: #2196F3;
198
+ color: white;
199
+ }
200
+ """,
201
+ "Dark": """
202
+ /* Dark theme CSS */
203
+ .gradio-container {
204
+ font-family: 'Arial', sans-serif;
205
+ background-color: #2c2c2c;
206
+ color: #ffffff;
207
+ }
208
+ .gradio-button {
209
+ background-color: #bb86fc;
210
+ color: black;
211
+ }
212
+ """
213
+ }
214
+
215
+ class ChatRole(Enum):
216
+ SYSTEM = "system"
217
+ USER = "user"
218
+ ASSISTANT = "assistant"
219
+
220
+ @dataclass
221
+ class ChatMessage:
222
+ role: ChatRole
223
+ content: str
224
+
225
+ class GradioAIBuilder:
226
+ def __init__(self, model_name: str = "HuggingFaceH4/starchat-beta"):
227
+ """Initialize the AI Builder with HuggingFace model"""
228
+ try:
229
+ self.tokenizer = AutoTokenizer.from_pretrained(model_name)
230
+ self.model = AutoModelForCausalLM.from_pretrained(
231
+ model_name,
232
+ torch_dtype=torch.float16,
233
+ device_map="auto",
234
+ trust_remote_code=True
235
+ )
236
+ self.chat_pipeline = pipeline(
237
+ "text-generation",
238
+ model=self.model,
239
+ tokenizer=self.tokenizer,
240
+ max_length=2048,
241
+ do_sample=True,
242
+ temperature=0.7,
243
+ top_p=0.95,
244
+ pad_token_id=self.tokenizer.eos_token_id
245
+ )
246
+
247
+ self.chat_history: List[ChatMessage] = []
248
+ self.current_app: Dict = {}
249
+ self.error_log: List[str] = []
250
+
251
+ # Initialize system prompt
252
+ self.initialize_system_prompt()
253
+
254
+ except Exception as e:
255
+ logger.error(f"Error initializing AI Builder: {str(e)}")
256
+ raise
257
+
258
+ def initialize_system_prompt(self):
259
+ """Set up the system prompt for the AI"""
260
+ system_prompt = """You are an expert Gradio application builder. Your role is to:
261
+ 1. Understand user requirements and convert them into Gradio components
262
+ 2. Generate and modify Python code for Gradio applications
263
+ 3. Help users customize their applications through natural language instructions
264
+ 4. Provide clear explanations of changes and suggestions for improvements
265
+
266
+ When generating code:
267
+ 1. Use proper Python and Gradio syntax
268
+ 2. Include necessary imports
269
+ 3. Structure the code clearly
270
+ 4. Add comments for clarity
271
+ 5. Handle errors appropriately
272
+
273
+ When responding to modifications:
274
+ 1. Explain what changes will be made
275
+ 2. Show the modified code
276
+ 3. Highlight any potential issues
277
+ 4. Suggest improvements if applicable
278
+
279
+ Available Components:
280
+ {components}
281
+
282
+ Available Templates:
283
+ {templates}
284
+
285
+ Response Format:
286
+ 1. Brief explanation of understanding
287
+ 2. Proposed solution
288
+ 3. Code block:
289
+ ```python
290
+ # Code here
291
+ ```
292
+ 4. Additional explanations or suggestions
293
+ """
294
+
295
+ # Format prompt with available components and templates
296
+ components_str = self._format_components_for_prompt()
297
+ templates_str = self._format_templates_for_prompt()
298
+
299
+ self.system_prompt = system_prompt.format(
300
+ components=components_str,
301
+ templates=templates_str
302
+ )
303
+ self.chat_history.append(ChatMessage(ChatRole.SYSTEM, self.system_prompt))
304
+
305
+ def _format_components_for_prompt(self) -> str:
306
+ """Format component information for the system prompt"""
307
+ components_info = []
308
+ for category, components in COMPONENT_CATEGORIES.items():
309
+ category_info = [f"\n{category}:"]
310
+ for name, info in components.items():
311
+ props = ", ".join(info["properties"].keys())
312
+ category_info.append(f" - {name}: {info['description']} (Properties: {props})")
313
+ components_info.extend(category_info)
314
+ return "\n".join(components_info)
315
+
316
+ def _format_templates_for_prompt(self) -> str:
317
+ """Format template information for the system prompt"""
318
+ templates_info = []
319
+ for category, templates in TEMPLATE_CATEGORIES.items():
320
+ category_info = [f"\n{category}:"]
321
+ for name, info in templates.items():
322
+ category_info.append(f" - {name}: {info['description']}")
323
+ templates_info.extend(category_info)
324
+ return "\n".join(templates_info)
325
+
326
+ async def generate_response(self, user_input: str) -> str:
327
+ """Generate AI response using HuggingFace model"""
328
+ try:
329
+ # Format conversation history
330
+ conversation = self._format_conversation_history()
331
+ conversation += f"\nuser: {user_input}\nassistant:"
332
+
333
+ # Generate response
334
+ response = self.chat_pipeline(
335
+ conversation,
336
+ max_new_tokens=1024,
337
+ do_sample=True,
338
+ temperature=0.7,
339
+ top_p=0.95
340
+ )[0]['generated_text']
341
+
342
+ # Extract assistant's response
343
+ response = response.split("assistant:")[-1].strip()
344
+
345
+ # Update chat history
346
+ self.chat_history.append(ChatMessage(ChatRole.USER, user_input))
347
+ self.chat_history.append(ChatMessage(ChatRole.ASSISTANT, response))
348
+
349
+ return response
350
+
351
+ except Exception as e:
352
+ error_msg = f"Error generating response: {str(e)}"
353
+ logger.error(error_msg)
354
+ self.error_log.append(error_msg)
355
+ raise
356
+
357
+ def _format_conversation_history(self) -> str:
358
+ """Format the conversation history for the model"""
359
+ return "\n".join([
360
+ f"{msg.role.value}: {msg.content}"
361
+ for msg in self.chat_history
362
+ ])
363
+
364
+ async def process_user_request(self, user_input: str) -> Dict[str, Any]:
365
+ """Process user request and return appropriate response"""
366
+ try:
367
+ response = await self.generate_response(user_input)
368
+
369
+ # Extract code if present
370
+ code_blocks = re.findall(r"```python\n(.*?)```", response, re.DOTALL)
371
+
372
+ result = {
373
+ "response": response,
374
+ "code_changes": code_blocks[0] if code_blocks else None,
375
+ "status": "success",
376
+ "preview_available": bool(code_blocks)
377
+ }
378
+
379
+ # If code changes were generated, update the current app
380
+ if code_blocks:
381
+ self.update_current_app(code_blocks[0])
382
+
383
+ return result
384
+
385
+ except Exception as e:
386
+ error_msg = f"Error processing request: {str(e)}"
387
+ logger.error(error_msg)
388
+ self.error_log.append(error_msg)
389
+ return {
390
+ "response": error_msg,
391
+ "status": "error",
392
+ "error": str(e)
393
+ }
394
+
395
+ def update_current_app(self, code: str):
396
+ """Update the current app with new code"""
397
+ try:
398
+ # Parse the code to extract components and layout
399
+ components = self.extract_components_from_code(code)
400
+ if components:
401
+ self.current_app["components"] = components
402
+
403
+ # Update layout if present
404
+ layout_match = re.search(r"with gr\.(Row|Column|Tabs)\(\):", code)
405
+ if layout_match:
406
+ layout_type = layout_match.group(1).lower()
407
+ self.current_app["layout"] = layout_type
408
+
409
+ # Extract CSS if present
410
+ css_match = re.search(r'css = """(.*?)"""', code, re.DOTALL)
411
+ if css_match:
412
+ self.current_app["css"] = css_match.group(1)
413
+
414
+ except Exception as e:
415
+ error_msg = f"Error updating current app: {str(e)}"
416
+ logger.error(error_msg)
417
+ self.error_log.append(error_msg)
418
+ raise
419
+
420
  class ComponentManager:
421
  def __init__(self):
422
+ self.components: List[Dict] = []
423
+ self.error_log: List[str] = []
 
 
424
 
425
+ def add_component(self, category: str, component_type: str, properties: Dict = None) -> Optional[Dict]:
426
+ """Add a new component with specified properties"""
427
+ try:
428
+ if category not in COMPONENT_CATEGORIES or component_type not in COMPONENT_CATEGORIES[category]:
429
+ raise ValueError(f"Invalid component type: {category}/{component_type}")
430
 
431
+ component_info = COMPONENT_CATEGORIES[category][component_type].copy()
432
+ if properties:
433
+ component_info["properties"].update(properties)
434
+
435
+ component = {
436
+ "id": len(self.components),
437
+ "category": category,
438
+ "type": component_type,
439
+ "properties": component_info["properties"]
440
+ }
441
+
442
+ self.components.append(component)
443
+ return component
444
+
445
+ except Exception as e:
446
+ error_msg = f"Error adding component: {str(e)}"
447
+ logger.error(error_msg)
448
+ self.error_log.append(error_msg)
449
+ return None
450
+
451
+ def update_component(self, component_id: int, properties: Dict) -> bool:
452
+ """Update properties of an existing component"""
453
+ try:
454
+ if not 0 <= component_id < len(self.components):
455
+ raise ValueError(f"Invalid component ID: {component_id}")
456
+
457
+ component = self.components[component_id]
458
+ component["properties"].update(properties)
459
+ return True
460
+
461
+ except Exception as e:
462
+ error_msg = f"Error updating component: {str(e)}"
463
+ logger.error(error_msg)
464
+ self.error_log.append(error_msg)
465
+ return False
466
 
467
+ def remove_component(self, component_id: int) -> bool:
468
  """Remove a component by ID"""
469
+ try:
470
+ if not 0 <= component_id < len(self.components):
471
+ raise ValueError(f"Invalid component ID: {component_id}")
472
+
473
+ self.components.pop(component_id)
474
+ # Update remaining component IDs
475
+ for i, component in enumerate(self.components):
476
+ component["id"] = i
477
+ return True
478
+
479
+ except Exception as e:
480
+ error_msg = f"Error removing component: {str(e)}"
481
+ logger.error(error_msg)
482
+ self.error_log.append(error_msg)
483
+ return False
484
+
485
+ def get_component(self, component_id: int) -> Optional[Dict]:
486
+ """Get component by ID"""
487
+ try:
488
+ if not 0 <= component_id < len(self.components):
489
+ raise ValueError(f"Invalid component ID: {component_id}")
490
+ return self.components[component_id]
491
+
492
+ except Exception as e:
493
+ error_msg = f"Error getting component: {str(e)}"
494
+ logger.error(error_msg)
495
+ self.error_log.append(error_msg)
496
+ return None
497
+
498
+ def get_components_json(self) -> str:
499
+ """Get all components as JSON string"""
500
+ try:
501
+ return json.dumps(self.components, indent=2)
502
+ except Exception as e:
503
+ error_msg = f"Error converting components to JSON: {str(e)}"
504
+ logger.error(error_msg)
505
+ self.error_log.append(error_msg)
506
+ return "[]"
507
 
508
+ def load_components_from_json(self, components_json: str) -> bool:
509
+ """Load components from JSON string"""
510
+ try:
511
+ if isinstance(components_json, str):
512
+ components = json.loads(components_json)
513
+ else:
514
+ components = components_json
515
+
516
+ self.components = components
517
+ return True
518
+
519
+ except Exception as e:
520
+ error_msg = f"Error loading components from JSON: {str(e)}"
521
+ logger.error(error_msg)
522
+ self.error_log.append(error_msg)
523
+ return False
524
 
525
  class TemplateManager:
526
  def __init__(self):
527
  self.templates = TEMPLATE_CATEGORIES
528
+ self.error_log: List[str] = []
529
 
530
+ def get_template(self, category: str, template_name: str) -> Optional[Dict]:
531
+ """Get a specific template by category and name"""
532
+ try:
533
+ if category not in self.templates or template_name not in self.templates[category]:
534
+ raise ValueError(f"Invalid template: {category}/{template_name}")
535
+ return self.templates[category][template_name]
536
+ except Exception as e:
537
+ error_msg = f"Error getting template: {str(e)}"
538
+ logger.error(error_msg)
539
+ self.error_log.append(error_msg)
540
+ return None
541
+
542
+ def add_custom_template(self, category: str, template_name: str, template_data: Dict) -> bool:
543
+ """Add a new custom template"""
544
+ try:
545
+ if not all(key in template_data for key in ["description", "components", "layout", "css", "dependencies"]):
546
+ raise ValueError("Invalid template data structure")
547
+
548
+ if category not in self.templates:
549
+ self.templates[category] = {}
550
+
551
+ self.templates[category][template_name] = template_data
552
+ return True
553
+ except Exception as e:
554
+ error_msg = f"Error adding custom template: {str(e)}"
555
+ logger.error(error_msg)
556
+ self.error_log.append(error_msg)
557
+ return False
558
+
559
+ def get_template_list(self) -> List[Dict]:
560
+ """Get list of all available templates"""
561
+ template_list = []
562
+ for category, templates in self.templates.items():
563
+ for name, data in templates.items():
564
+ template_list.append({
565
+ "category": category,
566
+ "name": name,
567
+ "description": data["description"]
568
+ })
569
+ return template_list
570
 
571
  class CodeGenerator:
572
  def __init__(self, template_manager: TemplateManager):
573
  self.template_manager = template_manager
574
+ self.error_log: List[str] = []
575
 
576
+ def generate_app_code(self, components: List[Dict], layout: str = "vertical",
577
+ theme: str = "Light", css: str = "") -> str:
578
+ """Generate complete Gradio application code"""
579
+ try:
580
+ code_parts = []
581
+
582
+ # Add imports
583
+ code_parts.append(self._generate_imports(components))
584
+
585
+ # Add any required helper functions
586
+ code_parts.append(self._generate_helper_functions(components))
 
587
 
588
+ # Generate the main app code
589
+ code_parts.append(self._generate_main_app_code(components, layout, theme, css))
590
+
591
+ return "\n\n".join(code_parts)
592
+ except Exception as e:
593
+ error_msg = f"Error generating app code: {str(e)}"
594
+ logger.error(error_msg)
595
+ self.error_log.append(error_msg)
596
+ return ""
597
 
598
+ def _generate_imports(self, components: List[Dict]) -> str:
599
+ """Generate necessary import statements"""
600
+ imports = ["import gradio as gr"]
 
 
 
 
 
 
 
 
 
601
 
602
+ # Add additional imports based on components
603
+ additional_imports = set()
604
+ for component in components:
605
+ if component["type"] == "Image":
606
+ additional_imports.add("from PIL import Image")
607
+ elif component["type"] in ["Audio", "Video"]:
608
+ additional_imports.add("import numpy as np")
609
 
610
+ return "\n".join(imports + sorted(list(additional_imports)))
611
+
612
+ def _generate_helper_functions(self, components: List[Dict]) -> str:
613
+ """Generate helper functions needed by components"""
614
+ helper_functions = []
615
+
616
+ # Add processing functions based on component types
617
+ processing_functions = set()
618
  for component in components:
619
+ if component["type"] == "Image":
620
+ processing_functions.add("""
621
+ def process_image(image):
622
+ \"\"\"Process the input image\"\"\"
623
+ # Add your image processing logic here
624
+ return image
625
+ """)
626
+ elif component["type"] == "Audio":
627
+ processing_functions.add("""
628
+ def process_audio(audio):
629
+ \"\"\"Process the input audio\"\"\"
630
+ # Add your audio processing logic here
631
+ return audio
632
+ """)
633
 
634
+ return "\n".join(helper_functions + sorted(list(processing_functions)))
635
 
636
+ def _generate_main_app_code(self, components: List[Dict], layout: str,
637
+ theme: str, css: str) -> str:
638
+ """Generate the main application code"""
639
+ code_lines = [
640
+ "# Create Gradio interface",
641
+ "with gr.Blocks(theme=gr.themes.Default(), css=css) as demo:",
642
+ " gr.Markdown(\"# Gradio Application\")\n"
643
  ]
644
 
645
+ # Add CSS
646
+ if css:
647
+ code_lines.insert(0, f'css = """{css}"""\n')
648
+
649
+ # Generate layout
650
+ if layout == "horizontal":
651
+ code_lines.append(" with gr.Row():")
652
+ indent = " "
653
+ else:
654
+ code_lines.append(" with gr.Column():")
655
+ indent = " "
656
+
657
+ # Add components
658
+ component_vars = []
659
+ for i, component in enumerate(components):
660
+ var_name = f"{component['type'].lower()}_{i}"
661
+ component_vars.append(var_name)
662
+
663
+ props = ", ".join([f"{k}={repr(v)}" for k, v in component["properties"].items()])
664
+ code_lines.append(f"{indent}{var_name} = gr.{component['type']}({props})")
665
 
666
+ # Add event handlers
667
+ if len(component_vars) > 1:
668
+ code_lines.extend(self._generate_event_handlers(component_vars))
 
 
669
 
670
  # Add launch code
671
+ code_lines.extend([
672
+ "\n# Launch the application",
673
+ "if __name__ == \"__main__\":",
674
+ " demo.launch()"
 
675
  ])
676
 
677
+ return "\n".join(code_lines)
678
+
679
+ def _generate_event_handlers(self, component_vars: List[str]) -> List[str]:
680
+ """Generate event handlers for components"""
681
+ handlers = []
682
+
683
+ # Look for input/output pairs
684
+ for i in range(len(component_vars) - 1):
685
+ if "button" in component_vars[i]:
686
+ handlers.extend([
687
+ f"\n def process_{i}({component_vars[i-1]}):",
688
+ f" # Add your processing logic here",
689
+ f" return {component_vars[i-1]}",
690
+ f"\n {component_vars[i]}.click(",
691
+ f" fn=process_{i},",
692
+ f" inputs=[{component_vars[i-1]}],",
693
+ f" outputs=[{component_vars[i+1]}]",
694
+ f" )"
695
+ ])
696
+
697
+ return handlers
698
 
699
  class AppBuilder:
700
  def __init__(self):
701
+ """Initialize the AppBuilder with necessary managers"""
702
+ self.component_manager = ComponentManager()
703
  self.template_manager = TemplateManager()
704
  self.code_generator = CodeGenerator(self.template_manager)
705
+ self.ai_builder = None # Will be initialized later if needed
706
+ self.current_app = {
707
+ "components": [],
708
+ "layout": "vertical",
709
+ "theme": "Light",
710
+ "css": DEFAULT_THEMES["Light"]
711
+ }
712
+ self.error_log: List[str] = []
713
+
714
+ def create_app_from_template(self, category: str, template_name: str) -> bool:
715
+ """Create a new app from a template"""
716
+ try:
717
+ template = self.template_manager.get_template(category, template_name)
718
+ if not template:
719
+ raise ValueError(f"Template not found: {category}/{template_name}")
720
+
721
+ self.current_app = {
722
+ "components": template["components"],
723
+ "layout": template["layout"],
724
+ "theme": "Light",
725
+ "css": template.get("css", DEFAULT_THEMES["Light"])
726
+ }
727
+
728
+ self.component_manager.load_components_from_json(template["components"])
729
+ return True
730
+ except Exception as e:
731
+ error_msg = f"Error creating app from template: {str(e)}"
732
+ logger.error(error_msg)
733
+ self.error_log.append(error_msg)
734
+ return False
735
+
736
+ def update_app_layout(self, layout: str) -> bool:
737
+ """Update the application layout"""
738
+ try:
739
+ if layout not in ["vertical", "horizontal", "tabs"]:
740
+ raise ValueError(f"Invalid layout: {layout}")
741
+
742
+ self.current_app["layout"] = layout
743
+ return True
744
+ except Exception as e:
745
+ error_msg = f"Error updating layout: {str(e)}"
746
+ logger.error(error_msg)
747
+ self.error_log.append(error_msg)
748
+ return False
749
+
750
+ def update_app_theme(self, theme: str) -> bool:
751
+ """Update the application theme"""
752
+ try:
753
+ if theme not in DEFAULT_THEMES:
754
+ raise ValueError(f"Invalid theme: {theme}")
755
+
756
+ self.current_app["theme"] = theme
757
+ self.current_app["css"] = DEFAULT_THEMES[theme]
758
+ return True
759
+ except Exception as e:
760
+ error_msg = f"Error updating theme: {str(e)}"
761
+ logger.error(error_msg)
762
+ self.error_log.append(error_msg)
763
+ return False
764
+
765
+ def generate_app_code(self) -> str:
766
+ """Generate the complete application code"""
767
+ try:
768
+ return self.code_generator.generate_app_code(
769
+ self.current_app["components"],
770
+ self.current_app["layout"],
771
+ self.current_app["theme"],
772
+ self.current_app["css"]
773
+ )
774
+ except Exception as e:
775
+ error_msg = f"Error generating app code: {str(e)}"
776
+ logger.error(error_msg)
777
+ self.error_log.append(error_msg)
778
+ return ""
779
+
780
+ def preview_app(self) -> Optional[gr.Blocks]:
781
+ """Generate and preview the current application"""
782
+ try:
783
+ code = self.generate_app_code()
784
+ if not code:
785
+ raise ValueError("No code generated")
786
+
787
+ # Create temporary file
788
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
789
+ f.write(code)
790
+ temp_file = f.name
791
+
792
+ # Execute the code in a separate process
793
+ result = subprocess.run(['python', temp_file], capture_output=True, text=True)
794
+
795
+ if result.returncode != 0:
796
+ raise ValueError(f"Error executing code: {result.stderr}")
797
+
798
+ return True
799
+ except Exception as e:
800
+ error_msg = f"Error previewing app: {str(e)}"
801
+ logger.error(error_msg)
802
+ self.error_log.append(error_msg)
803
+ return None
804
+
805
+ class GradioInterface:
806
+ def __init__(self):
807
+ """Initialize the Gradio interface"""
808
+ self.app_builder = AppBuilder()
809
+ self.current_tab = "builder"
810
+ self.error_log: List[str] = []
811
+
812
+ def create_interface(self) -> gr.Blocks:
813
+ """Create the main Gradio interface"""
814
+ try:
815
+ with gr.Blocks(theme=gr.themes.Default()) as interface:
816
+ gr.Markdown("# 🚀 Advanced Gradio App Builder")
817
 
818
+ with gr.Tabs() as tabs:
819
+ # Component Builder Tab
820
+ with gr.TabItem("🔧 Builder"):
821
+ self._create_builder_tab()
822
+
823
+ # Code Editor Tab
824
+ with gr.TabItem("📝 Code"):
825
+ self._create_code_tab()
826
+
827
+ # Preview Tab
828
+ with gr.TabItem("👁️ Preview"):
829
+ self._create_preview_tab()
830
+
831
+ # AI Assistant Tab
832
+ with gr.TabItem("🤖 AI Assistant"):
833
+ self._create_ai_tab()
834
+
835
+ # Settings Tab
836
+ with gr.TabItem("⚙️ Settings"):
837
+ self._create_settings_tab()
838
+
839
+ return interface
840
+
841
+ except Exception as e:
842
+ error_msg = f"Error creating interface: {str(e)}"
843
+ logger.error(error_msg)
844
+ self.error_log.append(error_msg)
845
+ raise
846
+
847
+ def _create_builder_tab(self):
848
+ """Create the component builder tab"""
849
+ with gr.Row():
850
+ # Left Column - Component Selection
851
+ with gr.Column(scale=1):
852
+ gr.Markdown("### 📦 Components")
853
+ category = gr.Dropdown(
854
+ choices=list(COMPONENT_CATEGORIES.keys()),
855
+ label="Category",
856
+ value="Basic"
857
  )
858
+ component_type = gr.Dropdown(
859
+ choices=list(COMPONENT_CATEGORIES["Basic"].keys()),
860
+ label="Component Type"
861
  )
862
+ add_component = gr.Button("Add Component", variant="primary")
863
+
864
+ # Middle Column - Component Properties
865
+ with gr.Column(scale=2):
866
+ gr.Markdown("### ⚙️ Properties")
867
+ properties_json = gr.JSON(label="Component Properties")
868
+ update_properties = gr.Button("Update Properties")
869
+
870
+ # Right Column - Component List
871
+ with gr.Column(scale=1):
872
+ gr.Markdown("### 📋 Current Components")
873
+ component_list = gr.JSON(label="Components")
874
+ remove_component = gr.Button("Remove Selected", variant="stop")
875
 
876
+ # Template Selection
877
+ with gr.Row():
878
+ gr.Markdown("### 📑 Templates")
879
+ template_category = gr.Dropdown(
880
+ choices=list(TEMPLATE_CATEGORIES.keys()),
881
+ label="Template Category"
882
+ )
883
+ template_name = gr.Dropdown(
884
+ choices=list(TEMPLATE_CATEGORIES["Basic"].keys()),
885
+ label="Template"
886
+ )
887
+ load_template = gr.Button("Load Template", variant="primary")
888
+
889
+ # Event handlers
890
+ def update_component_choices(category):
891
+ return gr.Dropdown(choices=list(COMPONENT_CATEGORIES[category].keys()))
892
+
893
+ category.change(
894
+ update_component_choices,
895
+ inputs=[category],
896
+ outputs=[component_type]
897
+ )
898
+
899
+ def add_new_component(category, comp_type):
900
+ success = self.app_builder.component_manager.add_component(category, comp_type)
901
+ components = self.app_builder.component_manager.get_components_json()
902
+ return components
903
+
904
+ add_component.click(
905
+ add_new_component,
906
+ inputs=[category, component_type],
907
+ outputs=[component_list]
908
+ )
909
+
910
+ def update_component_properties(props_json):
911
+ try:
912
+ props = json.loads(props_json)
913
+ success = self.app_builder.component_manager.update_component(
914
+ props["id"], props["properties"]
915
+ )
916
+ return self.app_builder.component_manager.get_components_json()
917
+ except Exception as e:
918
+ logger.error(f"Error updating properties: {str(e)}")
919
+ return None
920
+
921
+ update_properties.click(
922
+ update_component_properties,
923
+ inputs=[properties_json],
924
+ outputs=[component_list]
925
+ )
926
+
927
+ def _create_code_tab(self):
928
+ """Create the code editor tab"""
929
+ with gr.Row():
930
+ with gr.Column():
931
+ code_editor = gr.Code(
932
+ label="Application Code",
933
+ language="python",
934
+ value="# Your Gradio app code will appear here"
935
+ )
936
+ update_code = gr.Button("Update Code")
937
 
938
+ with gr.Column():
939
+ code_output = gr.Markdown("Code validation output will appear here")
940
+
941
+ def update_app_code():
942
+ try:
943
+ code = self.app_builder.generate_app_code()
944
+ return code, "✅ Code generated successfully"
945
+ except Exception as e:
946
+ return None, f"❌ Error generating code: {str(e)}"
947
+
948
+ update_code.click(
949
+ update_app_code,
950
+ outputs=[code_editor, code_output]
951
+ )
952
+
953
+ def _create_preview_tab(self):
954
+ """Create the preview tab"""
955
+ with gr.Row():
956
+ preview_button = gr.Button("Generate Preview", variant="primary")
957
+ preview_status = gr.Markdown("Click button to generate preview")
958
+
959
+ with gr.Row():
960
+ preview_frame = gr.HTML(label="App Preview")
961
+
962
+ def generate_preview():
963
+ try:
964
+ success = self.app_builder.preview_app()
965
+ if success:
966
+ return "✅ Preview generated successfully"
967
+ return "❌ Error generating preview"
968
+ except Exception as e:
969
+ return f"❌ Error: {str(e)}"
970
+
971
+ preview_button.click(
972
+ generate_preview,
973
+ outputs=[preview_status]
974
+ )
975
+
976
+ def _create_ai_tab(self):
977
+ """Create the AI assistant tab"""
978
+ with gr.Row():
979
+ with gr.Column(scale=2):
980
+ chat_history = gr.Chatbot(label="Chat History")
981
+ user_input = gr.Textbox(
982
+ label="Your Instructions",
983
+ placeholder="Describe what you want to build or modify...",
984
+ lines=3
985
  )
986
+ with gr.Row():
987
+ send_btn = gr.Button("Send", variant="primary")
988
+ clear_btn = gr.Button("Clear Chat")
989
+
990
+ with gr.Column(scale=1):
991
+ suggestions = gr.JSON(label="Suggested Components")
992
+ preview_btn = gr.Button("Update Preview")
993
+ preview_frame = gr.HTML(label="Live Preview")
994
 
995
+ chat_error = gr.Markdown(visible=False)
996
+
997
+ async def process_chat(message, history):
998
+ if not self.app_builder.ai_builder:
999
+ self.app_builder.ai_builder = GradioAIBuilder()
 
1000
 
1001
+ try:
1002
+ result = await self.app_builder.ai_builder.process_user_request(message)
1003
+
1004
+ if result["status"] == "error":
1005
+ return (
1006
+ history + [[message, "Error: " + result["response"]]],
1007
+ [],
1008
+ gr.Markdown(f"⚠️ {result['error']}", visible=True)
1009
+ )
1010
+
1011
+ new_history = history + [[message, result["response"]]]
1012
+
1013
+ return new_history, [], gr.Markdown(visible=False)
1014
+
1015
+ except Exception as e:
1016
+ error_msg = f"Error processing chat: {str(e)}"
1017
+ logger.error(error_msg)
1018
+ return (
1019
+ history + [[message, "An error occurred"]],
1020
+ [],
1021
+ gr.Markdown(f"⚠️ {error_msg}", visible=True)
1022
+ )
1023
 
1024
+ def clear_chat_history():
1025
+ if self.app_builder.ai_builder:
1026
+ self.app_builder.ai_builder.chat_history = []
1027
+ return [], [], gr.Markdown(visible=False)
 
1028
 
1029
+ send_btn.click(
1030
+ process_chat,
1031
+ inputs=[user_input, chat_history],
1032
+ outputs=[chat_history, suggestions, chat_error]
1033
+ )
1034
+
1035
+ clear_btn.click(
1036
+ clear_chat_history,
1037
+ outputs=[chat_history, suggestions, chat_error]
1038
+ )
1039
 
1040
+ def _create_settings_tab(self):
1041
+ """Create the settings tab"""
1042
+ with gr.Row():
1043
+ with gr.Column():
1044
+ gr.Markdown("### 🎨 Appearance")
1045
+ theme_dropdown = gr.Dropdown(
1046
+ choices=list(DEFAULT_THEMES.keys()),
1047
+ label="Theme",
1048
+ value="Light"
1049
+ )
1050
+ layout_dropdown = gr.Dropdown(
1051
+ choices=["vertical", "horizontal", "tabs"],
1052
+ label="Layout",
1053
+ value="vertical"
1054
+ )
1055
+
1056
+ with gr.Column():
1057
+ gr.Markdown("### 📝 Custom CSS")
1058
+ css_editor = gr.Code(
1059
+ label="Custom CSS",
1060
+ language="css",
1061
+ value=DEFAULT_THEMES["Light"]
1062
+ )
1063
+
1064
+ update_settings = gr.Button("Apply Settings", variant="primary")
1065
+
1066
+ def update_app_settings(theme, layout, css):
1067
+ try:
1068
+ self.app_builder.update_app_theme(theme)
1069
+ self.app_builder.update_app_layout(layout)
1070
+ self.app_builder.current_app["css"] = css
1071
+ return "✅ Settings updated successfully"
1072
+ except Exception as e:
1073
+ return f"❌ Error updating settings: {str(e)}"
1074
+
1075
+ update_settings.click(
1076
+ update_app_settings,
1077
+ inputs=[theme_dropdown, layout_dropdown, css_editor],
1078
+ outputs=[gr.Markdown()]
1079
+ )
1080
 
1081
+ def main():
1082
+ """Main execution function"""
1083
+ try:
1084
+ interface = GradioInterface()
1085
+ demo = interface.create_interface()
1086
+ demo.launch(
1087
+ server_name="0.0.0.0",
1088
+ server_port=7860,
1089
+ share=True,
1090
+ debug=True
1091
+ )
1092
+ except Exception as e:
1093
+ logger.error(f"Application failed to start: {str(e)}")
1094
+ raise
1095
 
1096
  if __name__ == "__main__":
1097
+ main()