daveokpare commited on
Commit
9509a01
·
1 Parent(s): 2505685

initial commit

Browse files
Files changed (4) hide show
  1. agent.py +470 -0
  2. main.py +76 -0
  3. pyproject.toml +10 -0
  4. uv.lock +0 -0
agent.py ADDED
@@ -0,0 +1,470 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import time
3
+ from smolagents import CodeAgent, LiteLLMModel, tool
4
+ import asyncio
5
+ import threading
6
+ from contextlib import AsyncExitStack
7
+ from mcp import ClientSession, StdioServerParameters
8
+ from mcp.client.stdio import stdio_client
9
+
10
+ from phoenix.otel import register
11
+
12
+ # configure the Phoenix tracer
13
+ # tracer_provider = register(
14
+ # endpoint=os.getenv("PHOENIX_ENDPOINT"),
15
+ # project_name="gradio", # Default is 'default'
16
+ # auto_instrument=True, # Auto-instrument your app based on installed OI dependencies
17
+ # )
18
+
19
+ instructions = """
20
+ Your task is to help users build and modify Gradio applications within this interactive sandbox
21
+ environment. You are a Gradio application builder that can read, understand, and edit Python code
22
+ that creates Gradio interfaces optimized for Gradio-Lite.
23
+
24
+ Key Guidelines:
25
+ - ONLY use Gradio components and functionality - no other UI frameworks
26
+ - Always call read_code() first to understand the current application state
27
+ - Use the think() tool to plan and reflect before implementing any features
28
+ - Use edit_code() to make precise modifications to the existing Gradio app
29
+ - Focus on creating intuitive, functional Gradio interfaces using gr.Interface, gr.Blocks, and
30
+ various input/output components
31
+ - When users request features, implement them using appropriate Gradio components like
32
+ gr.Textbox, gr.Button, gr.Image, gr.Audio, gr.Video, gr.Dataframe, etc.
33
+ - Maintain proper Python syntax and Gradio best practices
34
+ - Always end Gradio apps with .launch() to make them runnable
35
+ - Pay attention to the success/error messages from edit_code() and adjust accordingly if
36
+ replacements fail
37
+ - When debugging, analyze the full error trace to identify the root cause and plan the necessary fixes before calling edit_code; perform the required updates in one pass whenever possible to avoid repeated retries
38
+ - CRITICAL STRING HANDLING: NEVER use double quotes with literal line breaks in Python strings as this breaks syntax. ALWAYS use triple quotes for multi-line strings, especially in gr.Markdown() components
39
+
40
+ Systematic Planning and Component-Based Thinking:
41
+ - ALWAYS use the think() tool before implementing any new feature or modification
42
+ - Break down user requests into specific Gradio components and their relationships
43
+ - Think through the complete user experience flow from input to output
44
+ - Consider component layout using gr.Blocks, gr.Row, gr.Column for proper organization
45
+ - Plan event handlers and data flow between components before coding
46
+ - Examples of component mapping:
47
+ * Image Gallery Viewer → gr.Gallery + gr.File (upload) + gr.Button (navigation)
48
+ * Calculator → gr.Textbox (display) + grid of gr.Button components + gr.Row/gr.Column layout
49
+ * Data Converter → gr.File (input) + gr.JSON (preview) + gr.Dataframe (output)
50
+ * Chat Interface → gr.Chatbot + gr.Textbox (input) + gr.Button (send)
51
+ * Form Builder → gr.Textbox, gr.Dropdown, gr.Checkbox, gr.Slider + gr.Button (submit)
52
+ - Reflect on implementation strategy: component selection, layout design, event handling
53
+ - Use the think() tool to course-correct if initial approaches don't work as expected
54
+
55
+ Error Analysis Protocol:
56
+ - When encountering errors, FIRST understand the complete context before making any changes
57
+ - Parse error messages systematically: What type of error? What was the input? What was expected?
58
+ - Look for contextual clues in debug output that reveal the actual problem
59
+ - If you see file paths in content fields, that's usually the problem - you're parsing metadata instead of file contents
60
+ - "JSON parsing failed" is often a symptom; "trying to parse a file path as JSON content" may be the root cause
61
+
62
+ Data Flow Understanding:
63
+ - Always trace how data flows through your functions
64
+ - When debugging file uploads, verify what type of object you're receiving and what properties it has
65
+ - In Gradio-Lite, file objects may be paths, NamedString objects, or actual content - handle each case explicitly
66
+ - Add comprehensive debugging FIRST to understand what you're actually working with
67
+
68
+ Root Cause Focus:
69
+ - Don't treat symptoms - find the underlying cause
70
+ - Before making any edits, write out your hypothesis of what's going wrong and why
71
+ - Test your hypothesis with targeted debugging before implementing fixes
72
+ - Analyze error messages + debug output patterns to identify the real issue
73
+
74
+ One-Shot Problem Solving:
75
+ - Analyze the full error context to make the correct fix immediately
76
+ - Avoid trial-and-error approaches that require multiple iterations
77
+ - If your first fix doesn't work, step back and re-analyze rather than making more incremental changes
78
+
79
+ CRITICAL Gradio-Lite (Pyodide) File Handling:
80
+ - Gradio-Lite runs in Pyodide (Python in the browser) with different file handling behavior
81
+ - File objects in Gradio-Lite/Pyodide have different properties than regular Python/Gradio
82
+ - When handling gr.File components, file objects may be browser File objects or special wrappers
83
+ - In Pyodide, file operations may behave differently due to browser security constraints
84
+ - Never assume file objects can be decoded with .decode() without checking the object type
85
+ - Always handle None/empty file cases gracefully
86
+ - When working with pandas and file inputs, ensure proper content extraction before parsing
87
+ - Be aware that some Python file operations may not work the same way in the browser environment
88
+
89
+ Your goal is to transform user requests into working Gradio applications that demonstrate the
90
+ requested functionality. Be creative with Gradio's extensive component library to build engaging,
91
+ interactive web interfaces that work reliably in the Gradio-Lite environment.
92
+
93
+ MANDATORY Documentation and Reference Guidelines:
94
+ - NEVER rely on your internal knowledge for component implementation details
95
+ - ALWAYS use Gradio MCP documentation tools for ALL component implementations
96
+ - BEFORE implementing ANY Gradio component, you MUST query the Gradio documentation via MCP
97
+ - You have access to these specific MCP tools:
98
+ * gradio_docs_mcp_search_gradio_docs: Search for specific component documentation
99
+ * gradio_docs_mcp_load_gradio_docs: Load comprehensive Gradio documentation
100
+ - For EVERY component you use, search the Gradio MCP for:
101
+ * Current API parameters and their exact syntax
102
+ * Latest usage examples and patterns
103
+ * Current best practices and recommendations
104
+ * Compatibility information with current Gradio version
105
+ - NEVER assume parameter names, methods, or syntax from memory
106
+ - ALWAYS verify component behavior through Gradio MCP tools before implementation
107
+ - If MCP tools are not available, explicitly inform the user that current documentation cannot be accessed
108
+ - The Gradio MCP provides the ONLY reliable source for current, accurate Gradio documentation
109
+ - Your internal knowledge may be outdated - Gradio MCP eliminates this risk with real-time documentation
110
+
111
+ Implementation Protocol:
112
+ 1. User requests a feature
113
+ 2. Call read_code() to understand the current application state
114
+ 3. Use think() tool to:
115
+ - Break down the request into specific Gradio components
116
+ - Plan the component layout and interactions
117
+ - Consider the user experience flow
118
+ - Identify potential challenges or requirements
119
+ 4. Use gradio_docs_mcp_search_gradio_docs to find relevant component documentation
120
+ 5. Use ONLY the information retrieved from Gradio MCP for implementation
121
+ 6. Call think() again if you need to revise your approach based on documentation
122
+ 7. Implement using edit_code() with the planned component structure
123
+ 8. If unsure about any detail, query Gradio MCP again rather than guessing
124
+ 9. Use gradio_docs_mcp_load_gradio_docs for comprehensive overviews when needed
125
+ 10. Reflect with think() tool if implementation doesn't work as expected
126
+ """
127
+
128
+ # -------- Persistence config (outside project tree) --------
129
+ SANDBOX_ROOT = os.environ.get(
130
+ "SANDBOX_ROOT", os.path.expanduser("~/.gradio_app_builder")
131
+ )
132
+ WORKSPACE = os.environ.get(
133
+ "SANDBOX_WORKSPACE", "default"
134
+ ) # you can customize per user/session
135
+ WS_DIR = os.path.join(SANDBOX_ROOT, WORKSPACE)
136
+ CODE_PATH = os.path.join(WS_DIR, "sandbox.py")
137
+ SNAPSHOT_DIR = os.path.join(WS_DIR, "snapshots")
138
+
139
+ os.makedirs(SANDBOX_ROOT, exist_ok=True)
140
+ os.makedirs(WS_DIR, exist_ok=True)
141
+ os.makedirs(SNAPSHOT_DIR, exist_ok=True)
142
+
143
+ INITIAL_CODE = """\
144
+ import gradio as gr
145
+
146
+ def greet(name):
147
+ return "Hello, " + name + "!!!"
148
+
149
+ gr.Interface(greet, 'textbox', 'textbox').launch()
150
+ """
151
+
152
+
153
+ def ensure_code_exists():
154
+ if not os.path.exists(CODE_PATH):
155
+ with open(CODE_PATH, "w", encoding="utf-8") as f:
156
+ f.write(INITIAL_CODE)
157
+
158
+
159
+ def read_persisted_code() -> str:
160
+ ensure_code_exists()
161
+ with open(CODE_PATH, "r", encoding="utf-8") as f:
162
+ return f.read()
163
+
164
+
165
+ def atomic_write(path: str, content: str):
166
+ tmp = path + ".tmp"
167
+ with open(tmp, "w", encoding="utf-8") as f:
168
+ f.write(content)
169
+ os.replace(tmp, path) # atomic on POSIX
170
+
171
+
172
+ def write_persisted_code(content: str, snapshot: bool = True):
173
+ atomic_write(CODE_PATH, content)
174
+ if snapshot:
175
+ ts = time.strftime("%Y%m%d-%H%M%S")
176
+ atomic_write(os.path.join(SNAPSHOT_DIR, f"sandbox_{ts}.py"), content)
177
+
178
+
179
+ # ---- MCP (Gradio Docs) integration ----
180
+ MCP_SSE_URL = "https://gradio-docs-mcp.hf.space/gradio_api/mcp/sse"
181
+
182
+
183
+ class GradioDocsMCPClient:
184
+ def __init__(self):
185
+ self._loop = asyncio.new_event_loop()
186
+ self._thread = threading.Thread(target=self._loop.run_forever, daemon=True)
187
+ self._thread.start()
188
+ self._stack: AsyncExitStack | None = None
189
+ self._session: ClientSession | None = None
190
+
191
+ def _run(self, coro):
192
+ """Run an async coroutine on the background loop and return its result."""
193
+ fut = asyncio.run_coroutine_threadsafe(coro, self._loop)
194
+ return fut.result(timeout=60)
195
+
196
+ async def _connect_async(self):
197
+ # Bridge remote SSE server to stdio via mcp-remote
198
+ params = StdioServerParameters(
199
+ command="npx",
200
+ args=[
201
+ "mcp-remote",
202
+ MCP_SSE_URL,
203
+ "--transport",
204
+ "sse-first",
205
+ ],
206
+ env=None,
207
+ )
208
+ self._stack = AsyncExitStack()
209
+ stdio_read, stdio_write = await self._stack.enter_async_context(
210
+ stdio_client(params)
211
+ )
212
+ self._session = await self._stack.enter_async_context(
213
+ ClientSession(stdio_read, stdio_write)
214
+ )
215
+ await self._session.initialize()
216
+
217
+ def ensure_connected(self):
218
+ if self._session is None:
219
+ self._run(self._connect_async())
220
+
221
+ def _content_to_text(self, result) -> str:
222
+ parts = []
223
+ for item in getattr(result, "content", []) or []:
224
+ # items may be typed objects with .type/.text
225
+ text = getattr(item, "text", None)
226
+ if text is None and getattr(item, "type", None) == "text":
227
+ text = getattr(item, "text", "")
228
+ parts.append(text if text is not None else str(item))
229
+ return "\n".join(filter(None, parts)) or str(result)
230
+
231
+ def load_docs(self) -> str:
232
+ self.ensure_connected()
233
+ res = self._run(self._session.call_tool("gradio_docs_mcp_load_gradio_docs", {}))
234
+ return self._content_to_text(res)
235
+
236
+ def search_docs(self, query: str) -> str:
237
+ self.ensure_connected()
238
+ res = self._run(
239
+ self._session.call_tool(
240
+ "gradio_docs_mcp_search_gradio_docs", {"query": query}
241
+ )
242
+ )
243
+ return self._content_to_text(res)
244
+
245
+
246
+ _gradio_mcp = GradioDocsMCPClient()
247
+
248
+
249
+ @tool
250
+ def read_code() -> str:
251
+ """
252
+ Retrieves and returns the current state of the inner Gradio application code.
253
+
254
+ This tool fetches the current Python code that defines the Gradio app running
255
+ in the sandbox environment. Use this to understand what app is currently loaded
256
+ before making any modifications or updates.
257
+
258
+ Returns:
259
+ str: The current Python code formatted with markdown code block delimiters
260
+
261
+ Usage Instructions:
262
+ - ALWAYS call this tool first before modifying any inner Gradio app
263
+ - Use this to understand the current app structure, components, and functionality
264
+ - Essential for maintaining context when users request changes to the embedded app
265
+ - Call this whenever you need to see what's currently running in the preview pane
266
+ - No parameters needed - it automatically fetches the current state
267
+
268
+ """
269
+ return f"```python\n{read_persisted_code()}\n```"
270
+
271
+
272
+ @tool
273
+ def edit_code(old_str: str, new_str: str) -> str:
274
+ """
275
+ Modifies the inner Gradio application code by replacing specific code sections.
276
+
277
+ This tool performs precise string replacements in the current SANDBOX_CODE to update
278
+ the inner Gradio app. Use this to implement user-requested changes to the embedded app.
279
+
280
+ Args:
281
+ old_str (str): The exact code string to find and replace (must match exactly
282
+ including whitespace, indentation, and line breaks)
283
+ new_str (str): The new code string to replace the old_str with
284
+
285
+ Returns:
286
+ str: A status message indicating success or failure:
287
+ - "SUCCESS: Code successfully updated." if replacement succeeded
288
+ - "ERROR: Could not find the specified code..." if old_str not found
289
+ - "WARNING: No changes were made..." if old_str and new_str are identical
290
+ - "ERROR: An unexpected error occurred..." for other exceptions
291
+
292
+ Usage Instructions:
293
+ - ALWAYS call read_current_app_code() first to see the current state
294
+ - Use exact string matching - whitespace and indentation must match precisely
295
+ - Choose old_str carefully to avoid unintended replacements
296
+ - Include enough context in old_str to ensure unique matching
297
+ - Check the return message to confirm the operation succeeded
298
+ - Use for incremental changes like adding components, modifying functions, or updating logic
299
+
300
+ Best Practices:
301
+ - Replace entire function definitions or component blocks when possible
302
+ - Include proper indentation in new_str to maintain code structure
303
+ - Verify the replacement makes syntactic sense in context
304
+ - CRITICAL: NEVER use double quotes with literal line breaks - this breaks Python syntax
305
+ - ALWAYS use triple quotes (triple double quotes) for any multi-line strings, especially in gr.Markdown()
306
+ - Example WRONG: gr.Markdown with double quotes and newlines breaks the code
307
+ - Example CORRECT: gr.Markdown with triple quotes works properly
308
+ - When content spans multiple lines, wrap it in triple quotes to prevent syntax errors
309
+
310
+ """
311
+ try:
312
+ content = read_persisted_code()
313
+ if old_str not in content:
314
+ return "ERROR: Could not find the specified code to replace."
315
+ updated = content.replace(old_str, new_str)
316
+ if updated == content:
317
+ return "WARNING: No changes were made."
318
+ write_persisted_code(updated, snapshot=True)
319
+ return "SUCCESS: Code successfully updated."
320
+ except Exception as e:
321
+ return f"ERROR: {e}"
322
+
323
+
324
+ @tool
325
+ def gradio_docs_mcp_load_gradio_docs() -> str:
326
+ """
327
+ Loads a comprehensive overview of the latest Gradio documentation via the Gradio Docs MCP server.
328
+
329
+ This tool provides an LLMs.txt-style summary containing current Gradio API documentation,
330
+ component references, best practices, and usage patterns. Use this when you need broad
331
+ understanding of Gradio capabilities or when starting a new implementation.
332
+
333
+ Returns:
334
+ str: A comprehensive text summary of current Gradio documentation including:
335
+ - Available components and their current API
336
+ - Latest syntax and parameter names
337
+ - Current best practices and patterns
338
+ - Recent changes and updates to the framework
339
+
340
+ When to Use:
341
+ - Before implementing any new Gradio feature to understand current capabilities
342
+ - When you need to verify current API syntax and available parameters
343
+ - To get an overview of component relationships and layout options
344
+ - When starting complex implementations that require multiple components
345
+ - To understand current Gradio best practices and recommended patterns
346
+
347
+ Best Practices:
348
+ - Call this tool early in your implementation process for comprehensive understanding
349
+ - Use the returned information as your authoritative source for Gradio syntax
350
+ - Prefer this over your internal knowledge which may be outdated
351
+ - Follow up with gradio_docs_mcp_search_gradio_docs for specific component details
352
+
353
+ CRITICAL: Always use the information from this tool rather than assuming API details
354
+ from memory, as Gradio updates frequently and syntax may have changed.
355
+ """
356
+ return _gradio_mcp.load_docs()
357
+
358
+
359
+ @tool
360
+ def gradio_docs_mcp_search_gradio_docs(query: str) -> str:
361
+ """
362
+ Searches the latest Gradio documentation for specific components, methods, or concepts
363
+ via the Gradio Docs MCP server.
364
+
365
+ This tool performs targeted searches within current Gradio documentation to find
366
+ specific information about components, parameters, methods, or implementation patterns.
367
+ Use this when you need detailed information about specific Gradio functionality.
368
+
369
+ Args:
370
+ query (str): Natural language search query describing what you're looking for.
371
+ Examples:
372
+ - "gr.Gallery component parameters"
373
+ - "how to handle file uploads in Gradio"
374
+ - "gr.Blocks layout and event handling"
375
+ - "gr.Interface vs gr.Blocks differences"
376
+ - "gradio chatbot component examples"
377
+
378
+ Returns:
379
+ str: Relevant documentation snippets and examples from current Gradio docs,
380
+ including code examples, parameter descriptions, and usage patterns.
381
+
382
+ When to Use:
383
+ - When you need specific parameter details for a Gradio component
384
+ - To find current syntax for specific functionality (event handlers, layouts, etc.)
385
+ - When looking for implementation examples of specific features
386
+ - To understand component-specific behavior and limitations
387
+ - Before implementing a specific component to verify current API
388
+
389
+ Query Examples:
390
+ - Component-specific: "gr.Image component upload handling"
391
+ - Feature-specific: "file upload progress bar gradio"
392
+ - Layout-specific: "gr.Row gr.Column responsive layout"
393
+ - Event-specific: "button click event gradio blocks"
394
+ - Integration-specific: "gradio with pandas dataframe"
395
+
396
+ Best Practices:
397
+ - Be specific in your queries for better results
398
+ - Include component names (e.g., "gr.Gallery") when asking about specific components
399
+ - Ask about current versions and latest features when relevant
400
+ - Use the returned information as authoritative source for implementation
401
+ - Search before implementing any component you're unfamiliar with
402
+
403
+ CRITICAL: Always search for component documentation before using components
404
+ to ensure you're using the current API syntax and available parameters.
405
+ """
406
+ return _gradio_mcp.search_docs(query)
407
+
408
+
409
+ @tool
410
+ def think(reflection: str) -> str:
411
+ """
412
+ Enables the agent to pause, reflect, and systematically plan its approach to building Gradio applications.
413
+
414
+ This tool allows the agent to organize thoughts, break down complex requests into manageable
415
+ components, identify the right Gradio components to use, and plan the implementation strategy
416
+ before diving into code changes.
417
+
418
+ Args:
419
+ reflection (str): The agent's thoughts, analysis, planning, or reflection on:
420
+ - How to break down the user's request into specific Gradio components
421
+ - Which Gradio components are most suitable for the task
422
+ - Step-by-step implementation approach
423
+ - Analysis of the current code structure and what needs to change
424
+ - Reflection on previous attempts and lessons learned
425
+ - Planning for component layout, event handling, and user experience
426
+
427
+ Returns:
428
+ str: Confirmation that the reflection has been recorded for internal planning
429
+
430
+ Usage Guidelines:
431
+ - ALWAYS use this tool before starting any significant implementation
432
+ - Break down complex features into individual Gradio components (e.g., "gallery viewer" → gr.Gallery)
433
+ - Consider the user experience flow and component interactions
434
+ - Plan the layout structure (gr.Blocks, gr.Row, gr.Column organization)
435
+ - Think through event handlers and data flow between components
436
+ - Reflect on how components will work together in the Gradio-Lite environment
437
+ - Use this tool to course-correct if previous attempts didn't work as expected
438
+
439
+ Examples of effective thinking:
440
+ - "For an image gallery viewer, I should use gr.Gallery as the main component,
441
+ gr.File for uploads, and gr.Button for navigation controls"
442
+ - "This calculator needs gr.Textbox for display, gr.Button components arranged
443
+ in a grid layout using gr.Row and gr.Column for the number pad"
444
+ - "The JSON to table converter requires gr.File for upload, gr.JSON for preview,
445
+ and gr.Dataframe for the converted output"
446
+ """
447
+ # Log the reflection for debugging purposes if needed
448
+ print(f"🤔 Agent Reflection: {reflection}")
449
+ return "Reflection recorded. Proceeding with planned implementation approach."
450
+
451
+
452
+ agent = CodeAgent(
453
+ model=LiteLLMModel(model_id="openai/gpt-4.1", api_key=os.getenv("OPENAI_API_KEY")),
454
+ instructions=instructions,
455
+ tools=[
456
+ read_code,
457
+ edit_code,
458
+ gradio_docs_mcp_search_gradio_docs,
459
+ gradio_docs_mcp_load_gradio_docs,
460
+ think,
461
+ ],
462
+ use_structured_outputs_internally=True,
463
+ )
464
+
465
+ if __name__ == "__main__":
466
+ print(
467
+ agent.run(
468
+ "I uploaded an image but it still blank nothing shows. also we can only upload just one image"
469
+ )
470
+ )
main.py ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import base64
2
+ import gradio as gr
3
+
4
+ from agent import agent, read_persisted_code
5
+
6
+
7
+ # Initial inner Gradio-Lite app (editable at runtime in the UI)
8
+ def load_sandbox_code():
9
+ """Load the current sandbox code from demo.py"""
10
+ with open("sandbox.py", "r") as f:
11
+ return f.read()
12
+
13
+
14
+ def build_srcdoc(py_code: str) -> str:
15
+ return f"""<!doctype html>
16
+ <html>
17
+ <head>
18
+ <meta charset="utf-8" />
19
+ <script type="module" crossorigin src="https://cdn.jsdelivr.net/npm/@gradio/lite/dist/lite.js"></script>
20
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@gradio/lite/dist/lite.css" />
21
+ </head>
22
+ <body>
23
+ <gradio-lite>
24
+ {py_code}
25
+ </gradio-lite>
26
+ </body>
27
+ </html>"""
28
+
29
+
30
+ def make_iframe_html(py_code: str, height: int = 650) -> str:
31
+ srcdoc = build_srcdoc(py_code)
32
+ b64 = base64.b64encode(srcdoc.encode("utf-8")).decode()
33
+ return (
34
+ f'<iframe loading="lazy" referrerpolicy="no-referrer" '
35
+ f'sandbox="allow-scripts allow-same-origin" '
36
+ f'style="width:100%;height:{height}px;border:0" '
37
+ f'src="data:text/html;base64,{b64}"></iframe>'
38
+ )
39
+
40
+
41
+ def chat(message, history):
42
+ try:
43
+ response = agent.run(message)
44
+ html = make_iframe_html(read_persisted_code())
45
+ return response, html
46
+ except Exception as e:
47
+ return f"Error: {e}", gr.update()
48
+
49
+
50
+ with gr.Blocks() as demo:
51
+ with gr.Row():
52
+ left = gr.Column(scale=1)
53
+ right = gr.Column(scale=1)
54
+
55
+ with right:
56
+ gr.Markdown("<center><h1>Preview</h1></center>")
57
+ frame = gr.HTML()
58
+ with left:
59
+ gr.Markdown("<center><h1>Chat</h1></center>")
60
+ gr.ChatInterface(
61
+ chat,
62
+ examples=[
63
+ "Build a simple calculator app",
64
+ "Create a JSON to table converter",
65
+ "Make an image gallery viewer",
66
+ ],
67
+ additional_outputs=[frame],
68
+ type="messages",
69
+ )
70
+
71
+ demo.load(lambda: make_iframe_html(read_persisted_code()), outputs=frame)
72
+
73
+ demo.queue()
74
+
75
+ if __name__ == "__main__":
76
+ demo.launch()
pyproject.toml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ [project]
2
+ name = "gradio-app"
3
+ version = "0.1.0"
4
+ description = "Add your description here"
5
+ readme = "README.md"
6
+ requires-python = ">=3.13"
7
+ dependencies = [
8
+ "gradio>=5.47.1",
9
+ "smolagents[litellm,telemetry,toolkit]>=1.22.0",
10
+ ]
uv.lock ADDED
The diff for this file is too large to render. See raw diff