acecalisto3 commited on
Commit
0e9bf0c
·
verified ·
1 Parent(s): 26a0f9f

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +1371 -0
app.py ADDED
@@ -0,0 +1,1371 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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,
43
+ "minimum": None,
44
+ "maximum": None
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
+ def create_gradio_interface():
976
+ """Create Gradio interface for the code executor"""
977
+
978
+ def process_code(code: str, autonomy_level: int) -> Dict:
979
+ executor.set_autonomy_level(autonomy_level)
980
+ result = executor.execute_code(code)
981
+ return {
982
+ "Success": result["success"],
983
+ "Output": result["output"],
984
+ "Error": result["error"] or "None",
985
+ "Fixed Code": result["fixed_code"] or code,
986
+ "Iterations": result["iterations"]
987
+ }
988
+
989
+ with gr.Blocks() as interface:
990
+ gr.Markdown("# 🤖 Autonomous Code Executor")
991
+
992
+ with gr.Tab("Code Execution"):
993
+ code_input = gr.Code(
994
+ label="Code Input",
995
+ language="python",
996
+ lines=10,
997
+ placeholder="Enter your Python code here..."
998
+ )
999
+
1000
+ autonomy_slider = gr.Slider(
1001
+ minimum=0,
1002
+ maximum=10,
1003
+ step=1,
1004
+ value=5,
1005
+ label="Autonomy Level",
1006
+ info="0: No fixes, 5: Balanced, 10: Fully autonomous"
1007
+ )
1008
+
1009
+ execute_btn = gr.Button("Execute Code", variant="primary")
1010
+
1011
+ output_json = gr.JSON(label="Execution Result")
1012
+
1013
+ execute_btn.click(
1014
+ fn=process_code,
1015
+ inputs=[code_input, autonomy_slider],
1016
+ outputs=output_json
1017
+ )
1018
+
1019
+ with gr.Tab("Settings"):
1020
+ gr.Markdown("""
1021
+ ### Configuration
1022
+ - Model: bigcode/starcoder
1023
+ - Embedding Model: sentence-transformers/all-mpnet-base-v2
1024
+ - Temperature: 0.1
1025
+ - Max Length: 2048
1026
+ """)
1027
+
1028
+ with gr.Tab("Help"):
1029
+ gr.Markdown("""
1030
+ ### How to Use
1031
+ 1. Enter your Python code in the Code Input area
1032
+ 2. Adjust the Autonomy Level:
1033
+ - 0: No automatic fixes
1034
+ - 5: Balanced approach
1035
+ - 10: Fully autonomous operation
1036
+ 3. Click "Execute Code" to run
1037
+
1038
+ ### Features
1039
+ - Automatic code analysis
1040
+ - Error detection and fixing
1041
+ - Code formatting
1042
+ - Syntax validation
1043
+ """)
1044
+
1045
+ return interface
1046
+
1047
+ def create_gradio_interface():
1048
+ """Create Gradio interface for the code executor"""
1049
+
1050
+ def process_code(code: str, autonomy_level: int) -> Dict:
1051
+ executor.set_autonomy_level(autonomy_level)
1052
+ result = executor.execute_code(code)
1053
+ return {
1054
+ "Success": result["success"],
1055
+ "Output": result["output"],
1056
+ "Error": result["error"] or "None",
1057
+ "Fixed Code": result["fixed_code"] or code,
1058
+ "Iterations": result["iterations"]
1059
+ }
1060
+
1061
+ with gr.Blocks() as interface:
1062
+ gr.Markdown("# 🤖 Autonomous Code Executor")
1063
+
1064
+ with gr.Tab("Code Execution"):
1065
+ # Corrected Code component initialization
1066
+ code_input = gr.Code(
1067
+ label="Code Input",
1068
+ language="python",
1069
+ lines=10,
1070
+ value="# Enter your Python code here..." # Using value instead of placeholder
1071
+ )
1072
+
1073
+ autonomy_slider = gr.Slider(
1074
+ minimum=0,
1075
+ maximum=10,
1076
+ step=1,
1077
+ value=5,
1078
+ label="Autonomy Level",
1079
+ info="0: No fixes, 5: Balanced, 10: Fully autonomous"
1080
+ )
1081
+
1082
+ execute_btn = gr.Button("Execute Code", variant="primary")
1083
+ output_json = gr.JSON(label="Execution Result")
1084
+
1085
+ # Add example inputs
1086
+ gr.Examples(
1087
+ examples=[
1088
+ ["def hello():\n print('Hello, World!')", 5],
1089
+ ["for i in range(5):\n print(i)", 5]
1090
+ ],
1091
+ inputs=[code_input, autonomy_slider],
1092
+ outputs=output_json,
1093
+ label="Example Code"
1094
+ )
1095
+
1096
+ execute_btn.click(
1097
+ fn=process_code,
1098
+ inputs=[code_input, autonomy_slider],
1099
+ outputs=output_json
1100
+ )
1101
+
1102
+ with gr.Tab("Settings"):
1103
+ gr.Markdown("""
1104
+ ### Configuration
1105
+ - Model: bigcode/starcoder
1106
+ - Embedding Model: sentence-transformers/all-mpnet-base-v2
1107
+ - Temperature: 0.1
1108
+ - Max Length: 2048
1109
+ """)
1110
+
1111
+ with gr.Tab("Help"):
1112
+ gr.Markdown("""
1113
+ ### How to Use
1114
+ 1. Enter your Python code in the Code Input area
1115
+ 2. Adjust the Autonomy Level:
1116
+ - 0: No automatic fixes
1117
+ - 5: Balanced approach
1118
+ - 10: Fully autonomous operation
1119
+ 3. Click "Execute Code" to run
1120
+
1121
+ ### Features
1122
+ - Automatic code analysis
1123
+ - Error detection and fixing
1124
+ - Code formatting
1125
+ - Syntax validation
1126
+ """)
1127
+
1128
+ return interface
1129
+
1130
+ # Create Gradio interface
1131
+ interface = create_gradio_interface()
1132
+
1133
+ if __name__ == "__main__":
1134
+ # Run Flask and Gradio in separate threads
1135
+ flask_thread = threading.Thread(target=run_flask, daemon=True)
1136
+ gradio_thread = threading.Thread(target=run_gradio, daemon=True)
1137
+
1138
+ flask_thread.start()
1139
+ gradio_thread.start()
1140
+
1141
+ # Keep the main thread alive
1142
+ try:
1143
+ while True:
1144
+ time.sleep(1)
1145
+ except KeyboardInterrupt:
1146
+ print("Shutting down...")
1147
+ class ChatState:
1148
+ def __init__(self):
1149
+ self.current_step = 0
1150
+ self.command = None
1151
+ self.context = {}
1152
+
1153
+ def reset(self):
1154
+ self.current_step = 0
1155
+ self.command = None
1156
+ self.context = {}
1157
+
1158
+ chat_state = ChatState()
1159
+
1160
+ def get_next_question(command, step, previous_answer=None):
1161
+ """Generate next question based on command and current step"""
1162
+ questions = {
1163
+ "create": [
1164
+ "Do you need user input components?",
1165
+ "Do you need data processing functionality?",
1166
+ "Would you like to add styling/themes?"
1167
+ ],
1168
+ "component": [
1169
+ "Is this for user input?",
1170
+ "Do you need media handling (image/audio/video)?",
1171
+ "Should the component have real-time updates?"
1172
+ ],
1173
+ "layout": [
1174
+ "Do you want a multi-tab layout?",
1175
+ "Do you need responsive design?",
1176
+ "Should components be arranged horizontally?"
1177
+ ],
1178
+ "style": [
1179
+ "Do you want a dark theme?",
1180
+ "Do you need custom CSS?",
1181
+ "Should components have rounded corners?"
1182
+ ],
1183
+ "data": [
1184
+ "Will you be handling file uploads?",
1185
+ "Do you need data visualization?",
1186
+ "Should data be stored persistently?"
1187
+ ],
1188
+ "api": [
1189
+ "Do you need authentication for API?",
1190
+ "Will you be handling JSON data?",
1191
+ "Do you need error handling?"
1192
+ ],
1193
+ "auth": [
1194
+ "Do you need user registration?",
1195
+ "Should sessions be persistent?",
1196
+ "Do you need role-based access?"
1197
+ ],
1198
+ "file": [
1199
+ "Will you handle multiple file types?",
1200
+ "Do you need file preprocessing?",
1201
+ "Should files be stored locally?"
1202
+ ],
1203
+ "viz": [
1204
+ "Do you need interactive plots?",
1205
+ "Will you use real-time data?",
1206
+ "Do you need multiple chart types?"
1207
+ ],
1208
+ "db": [
1209
+ "Do you need real-time updates?",
1210
+ "Will you use SQL database?",
1211
+ "Do you need data caching?"
1212
+ ]
1213
+ }
1214
+
1215
+ if step < len(questions[command]):
1216
+ return questions[command][step]
1217
+ return None
1218
+
1219
+ def generate_code(command, context):
1220
+ """Generate code based on collected context"""
1221
+ base_templates = {
1222
+ "create": """
1223
+ ```python
1224
+ import gradio as gr
1225
+
1226
+ def process_input({input_params}):
1227
+ {processing_logic}
1228
+ return result
1229
+
1230
+ with gr.Blocks({style_params}) as demo:
1231
+ {components}
1232
+ {layout}
1233
+ {event_handlers}
1234
+
1235
+ demo.launch()
1236
+ ```""",
1237
+ "component": """
1238
+ ```python
1239
+ {import_statements}
1240
+
1241
+ {component_definition}
1242
+
1243
+ {event_handling}
1244
+ ```""",
1245
+ # Add other base templates for each command...
1246
+ }
1247
+
1248
+ # Customize template based on context
1249
+ if command == "create":
1250
+ input_params = "user_input"
1251
+ processing_logic = "result = user_input"
1252
+ style_params = "theme=gr.themes.Default()" if not context.get("dark_theme") else "theme=gr.themes.Monochrome()"
1253
+ components = "input_component = gr.Textbox(label='Input')\noutput_component = gr.Textbox(label='Output')"
1254
+ layout = "gr.Button('Process')"
1255
+ event_handlers = "input_component.change(process_input, inputs=input_component, outputs=output_component)"
1256
+
1257
+ return base_templates[command].format(
1258
+ input_params=input_params,
1259
+ processing_logic=processing_logic,
1260
+ style_params=style_params,
1261
+ components=components,
1262
+ layout=layout,
1263
+ event_handlers=event_handlers
1264
+ )
1265
+
1266
+ def process_chat(command, answer, history):
1267
+ """Process chat interaction"""
1268
+ try:
1269
+ if command and chat_state.command != command:
1270
+ # New command started
1271
+ chat_state.reset()
1272
+ chat_state.command = command
1273
+ question = get_next_question(command, 0)
1274
+ return history + [[None, question]], True, question
1275
+
1276
+ if answer:
1277
+ # Store answer and get next question
1278
+ chat_state.context[f"step_{chat_state.current_step}"] = answer == "Yes"
1279
+ chat_state.current_step += 1
1280
+
1281
+ next_question = get_next_question(chat_state.command, chat_state.current_step)
1282
+
1283
+ if next_question:
1284
+ # More questions to ask
1285
+ return history + [[answer, next_question]], True, next_question
1286
+ else:
1287
+ # Generate final code
1288
+ code = generate_code(chat_state.command, chat_state.context)
1289
+ return history + [[answer, f"Here's your code:\n{code}"]], False, None
1290
+
1291
+ return history, True, None
1292
+
1293
+ except Exception as e:
1294
+ error_msg = f"Error: {str(e)}"
1295
+ logger.error(error_msg)
1296
+ return history + [[None, error_msg]], False, None
1297
+
1298
+ def reset_chat():
1299
+ """Reset chat state and history"""
1300
+ chat_state.reset()
1301
+ return None, None, False, None
1302
+
1303
+ # Set up event handlers
1304
+ send_btn.click(
1305
+ process_chat,
1306
+ inputs=[command_input, user_input, chat_history],
1307
+ outputs=[chat_history, user_input, user_input]
1308
+ )
1309
+
1310
+ restart_btn.click(
1311
+ reset_chat,
1312
+ outputs=[chat_history, command_input, user_input, user_input]
1313
+ )
1314
+ def _create_settings_tab(self):
1315
+ """Create the settings tab"""
1316
+ with gr.Row():
1317
+ with gr.Column():
1318
+ gr.Markdown("### 🎨 Appearance")
1319
+ theme_dropdown = gr.Dropdown(
1320
+ choices=list(DEFAULT_THEMES.keys()),
1321
+ label="Theme",
1322
+ value="Light"
1323
+ )
1324
+ layout_dropdown = gr.Dropdown(
1325
+ choices=["vertical", "horizontal", "tabs"],
1326
+ label="Layout",
1327
+ value="vertical"
1328
+ )
1329
+
1330
+ with gr.Column():
1331
+ gr.Markdown("### 📝 Custom CSS")
1332
+ css_editor = gr.Code(
1333
+ label="Custom CSS",
1334
+ language="css",
1335
+ value=DEFAULT_THEMES["Light"]
1336
+ )
1337
+
1338
+ update_settings = gr.Button("Apply Settings", variant="primary")
1339
+
1340
+ def update_app_settings(theme, layout, css):
1341
+ try:
1342
+ self.app_builder.update_app_theme(theme)
1343
+ self.app_builder.update_app_layout(layout)
1344
+ self.app_builder.current_app["css"] = css
1345
+ return "✅ Settings updated successfully"
1346
+ except Exception as e:
1347
+ return f"❌ Error updating settings: {str(e)}"
1348
+
1349
+ update_settings.click(
1350
+ update_app_settings,
1351
+ inputs=[theme_dropdown, layout_dropdown, css_editor],
1352
+ outputs=[gr.Markdown()]
1353
+ )
1354
+
1355
+ def main():
1356
+ """Main execution function"""
1357
+ try:
1358
+ interface = GradioInterface()
1359
+ demo = interface.create_interface()
1360
+ demo.launch(
1361
+ server_name="0.0.0.0",
1362
+ server_port=7860,
1363
+ share=True,
1364
+ debug=True
1365
+ )
1366
+ except Exception as e:
1367
+ logger.error(f"Application failed to start: {str(e)}")
1368
+ raise
1369
+
1370
+ if __name__ == "__main__":
1371
+ main()