hari7261 commited on
Commit
2b166d7
Β·
verified Β·
1 Parent(s): 5494f83

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +841 -0
  2. requirements.txt +31 -0
app.py ADDED
@@ -0,0 +1,841 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from agno.agent import Agent
3
+ from agno.models.google import Gemini
4
+ from typing import Optional, Dict, Any
5
+ import tempfile
6
+ import os
7
+ import ast
8
+ import contextlib
9
+ import io
10
+ import sys
11
+ from PIL import Image
12
+ import subprocess
13
+ import json
14
+
15
+ class MultiLanguageExecutor:
16
+ """A safer alternative to sandbox execution with support for multiple languages"""
17
+
18
+ def __init__(self, timeout=10):
19
+ self.timeout = timeout
20
+ self.allowed_modules = [
21
+ 'math', 'datetime', 'collections', 'itertools',
22
+ 'functools', 'heapq', 'bisect', 'array', 'string'
23
+ ]
24
+
25
+ # Language configurations
26
+ self.language_configs = {
27
+ 'python': {
28
+ 'extension': '.py',
29
+ 'run_command': lambda file: f'python "{file}"',
30
+ 'comment_syntax': '#',
31
+ 'sample_template': '''def main():
32
+ # Your code here
33
+ pass
34
+
35
+ if __name__ == "__main__":
36
+ main()'''
37
+ },
38
+ 'javascript': {
39
+ 'extension': '.js',
40
+ 'run_command': lambda file: f'node "{file}"',
41
+ 'comment_syntax': '//',
42
+ 'sample_template': '''function main() {
43
+ // Your code here
44
+ }
45
+
46
+ main();'''
47
+ },
48
+ 'typescript': {
49
+ 'extension': '.ts',
50
+ 'run_command': lambda file: f'npx ts-node "{file}"',
51
+ 'comment_syntax': '//',
52
+ 'sample_template': '''function main(): void {
53
+ // Your code here
54
+ }
55
+
56
+ main();'''
57
+ },
58
+ 'html': {
59
+ 'extension': '.html',
60
+ 'run_command': None, # HTML doesn't execute, just validate
61
+ 'comment_syntax': '<!--',
62
+ 'sample_template': '''<!DOCTYPE html>
63
+ <html lang="en">
64
+ <head>
65
+ <meta charset="UTF-8">
66
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
67
+ <title>Document</title>
68
+ </head>
69
+ <body>
70
+ <!-- Your content here -->
71
+ </body>
72
+ </html>'''
73
+ },
74
+ 'css': {
75
+ 'extension': '.css',
76
+ 'run_command': None, # CSS doesn't execute, just validate
77
+ 'comment_syntax': '/*',
78
+ 'sample_template': '''/* Your CSS styles here */
79
+ body {
80
+ font-family: Arial, sans-serif;
81
+ margin: 0;
82
+ padding: 0;
83
+ }'''
84
+ },
85
+ 'tsx': {
86
+ 'extension': '.tsx',
87
+ 'run_command': lambda file: f'npx ts-node "{file}"',
88
+ 'comment_syntax': '//',
89
+ 'sample_template': '''import React from 'react';
90
+
91
+ const Component: React.FC = () => {
92
+ return (
93
+ <div>
94
+ {/* Your JSX here */}
95
+ </div>
96
+ );
97
+ };
98
+
99
+ export default Component;'''
100
+ },
101
+ 'java': {
102
+ 'extension': '.java',
103
+ 'run_command': lambda file: f'javac "{file}" && java "{os.path.splitext(os.path.basename(file))[0]}"',
104
+ 'comment_syntax': '//',
105
+ 'sample_template': '''public class Main {
106
+ public static void main(String[] args) {
107
+ // Your code here
108
+ }
109
+ }'''
110
+ },
111
+ 'c': {
112
+ 'extension': '.c',
113
+ 'run_command': lambda file: f'gcc "{file}" -o "{os.path.splitext(file)[0]}" && "{os.path.splitext(file)[0]}"',
114
+ 'comment_syntax': '//',
115
+ 'sample_template': '''#include <stdio.h>
116
+
117
+ int main() {
118
+ // Your code here
119
+ return 0;
120
+ }'''
121
+ },
122
+ 'cpp': {
123
+ 'extension': '.cpp',
124
+ 'run_command': lambda file: f'g++ "{file}" -o "{os.path.splitext(file)[0]}" && "{os.path.splitext(file)[0]}"',
125
+ 'comment_syntax': '//',
126
+ 'sample_template': '''#include <iostream>
127
+ using namespace std;
128
+
129
+ int main() {
130
+ // Your code here
131
+ return 0;
132
+ }'''
133
+ }
134
+ }
135
+
136
+ def run_code(self, code: str, language: str = 'python') -> Dict[str, Any]:
137
+ """Execute code in the specified language with restrictions"""
138
+ result = {
139
+ "success": False,
140
+ "output": "",
141
+ "error": "",
142
+ "logs": "",
143
+ "language": language
144
+ }
145
+
146
+ if language not in self.language_configs:
147
+ result["error"] = f"Unsupported language: {language}"
148
+ return result
149
+
150
+ config = self.language_configs[language]
151
+
152
+ # For markup languages (HTML, CSS), just validate syntax
153
+ if language in ['html', 'css']:
154
+ return self._validate_markup(code, language)
155
+
156
+ # For other languages, attempt execution
157
+ return self._execute_code(code, config, result)
158
+
159
+ def _validate_markup(self, code: str, language: str) -> Dict[str, Any]:
160
+ """Validate HTML/CSS syntax"""
161
+ result = {
162
+ "success": True,
163
+ "output": f"βœ… {language.upper()} code appears to be well-formed.",
164
+ "error": "",
165
+ "logs": "",
166
+ "language": language
167
+ }
168
+
169
+ # Basic validation
170
+ if language == 'html':
171
+ if not code.strip().startswith('<!DOCTYPE') and not code.strip().startswith('<html'):
172
+ result["logs"] = "Note: Consider adding DOCTYPE and html tags for complete HTML structure."
173
+ elif language == 'css':
174
+ if '{' in code and '}' not in code:
175
+ result["error"] = "CSS syntax error: Missing closing brace '}'"
176
+ result["success"] = False
177
+
178
+ return result
179
+
180
+ def _execute_code(self, code: str, config: Dict, result: Dict) -> Dict[str, Any]:
181
+ """Execute code for compilable/interpretable languages"""
182
+ try:
183
+ # Create temporary file
184
+ with tempfile.NamedTemporaryFile(
185
+ mode='w',
186
+ suffix=config['extension'],
187
+ delete=False,
188
+ encoding='utf-8'
189
+ ) as tmp_file:
190
+ tmp_file.write(code)
191
+ tmp_file_path = tmp_file.name
192
+
193
+ # Special handling for Python (use the safer execution)
194
+ if result["language"] == 'python':
195
+ return self._run_python_safe(code)
196
+
197
+ # For other languages, use subprocess with timeout
198
+ if config['run_command']:
199
+ cmd = config['run_command'](tmp_file_path)
200
+ process = subprocess.run(
201
+ cmd,
202
+ shell=True,
203
+ capture_output=True,
204
+ text=True,
205
+ timeout=self.timeout,
206
+ cwd=os.path.dirname(tmp_file_path)
207
+ )
208
+
209
+ result["output"] = process.stdout
210
+ result["error"] = process.stderr
211
+ result["success"] = process.returncode == 0
212
+
213
+ if not result["success"] and not result["error"]:
214
+ result["error"] = f"Process exited with code {process.returncode}"
215
+
216
+ except subprocess.TimeoutExpired:
217
+ result["error"] = f"Execution timed out after {self.timeout} seconds"
218
+ except FileNotFoundError as e:
219
+ result["error"] = f"Required compiler/interpreter not found: {str(e)}"
220
+ except Exception as e:
221
+ result["error"] = f"Execution error: {str(e)}"
222
+ finally:
223
+ # Clean up temporary file
224
+ try:
225
+ if 'tmp_file_path' in locals() and os.path.exists(tmp_file_path):
226
+ os.remove(tmp_file_path)
227
+ # Also remove compiled files for C/C++/Java
228
+ base_name = os.path.splitext(tmp_file_path)[0]
229
+ for ext in ['.exe', '.class', '']:
230
+ compiled_file = base_name + ext
231
+ if os.path.exists(compiled_file):
232
+ os.remove(compiled_file)
233
+ except:
234
+ pass
235
+
236
+ return result
237
+
238
+ def _run_python_safe(self, code: str) -> Dict[str, Any]:
239
+ """Execute Python code safely with restrictions (same as original SafeCodeExecutor)"""
240
+ stdout_capture = io.StringIO()
241
+ stderr_capture = io.StringIO()
242
+
243
+ result = {
244
+ "success": False,
245
+ "output": "",
246
+ "error": "",
247
+ "logs": "",
248
+ "language": "python"
249
+ }
250
+
251
+ try:
252
+ # Parse and validate the code
253
+ parsed = ast.parse(code)
254
+
255
+ # Check for disallowed constructs
256
+ for node in ast.walk(parsed):
257
+ if isinstance(node, (ast.Import, ast.ImportFrom)):
258
+ for alias in node.names:
259
+ module_name = alias.name if isinstance(node, ast.Import) else node.module
260
+ if module_name and not any(module_name == allowed or module_name.startswith(allowed + '.')
261
+ for allowed in self.allowed_modules):
262
+ result["error"] = f"Import of module '{module_name}' is not allowed"
263
+ return result
264
+
265
+ # Disable dangerous functions/constructs
266
+ if isinstance(node, ast.Call) and isinstance(node.func, ast.Name):
267
+ if node.func.id in ['eval', 'exec', 'open', 'exit', 'quit', 'compile']:
268
+ result["error"] = f"Use of '{node.func.id}' function is not allowed"
269
+ return result
270
+
271
+ # Execute the code with restrictions
272
+ with contextlib.redirect_stdout(stdout_capture), contextlib.redirect_stderr(stderr_capture):
273
+ locals_dict = {}
274
+ exec(code, {"__builtins__": self._get_safe_builtins()}, locals_dict)
275
+
276
+ # Check if there's a main function or similar output
277
+ output = stdout_capture.getvalue()
278
+ if not output and "main" in locals_dict and callable(locals_dict["main"]):
279
+ output = str(locals_dict["main"]())
280
+
281
+ result["success"] = True
282
+ result["output"] = output
283
+
284
+ except Exception as e:
285
+ result["error"] = f"Execution error: {str(e)}"
286
+
287
+ result["logs"] = stderr_capture.getvalue()
288
+ return result
289
+
290
+ def _get_safe_builtins(self):
291
+ """Create a safe subset of builtins"""
292
+ safe_builtins = {
293
+ 'None': None,
294
+ 'True': True,
295
+ 'False': False,
296
+ 'bool': bool,
297
+ 'int': int,
298
+ 'float': float,
299
+ 'str': str,
300
+ 'list': list,
301
+ 'tuple': tuple,
302
+ 'dict': dict,
303
+ 'set': set,
304
+ 'len': len,
305
+ 'range': range,
306
+ 'sum': sum,
307
+ 'min': min,
308
+ 'max': max,
309
+ 'abs': abs,
310
+ 'round': round,
311
+ 'zip': zip,
312
+ 'enumerate': enumerate,
313
+ 'isinstance': isinstance,
314
+ 'issubclass': issubclass,
315
+ 'hasattr': hasattr,
316
+ 'getattr': getattr,
317
+ 'setattr': setattr,
318
+ }
319
+ return safe_builtins
320
+
321
+ class MultimodalCodingAgent:
322
+ def __init__(self, gemini_api_key: str):
323
+ self.gemini_api_key = gemini_api_key
324
+ self.executor = MultiLanguageExecutor()
325
+
326
+ # Create a single agent for all tasks
327
+ self.agent = Agent(
328
+ model=Gemini(id="gemini-2.0-flash", api_key=gemini_api_key),
329
+ markdown=True
330
+ )
331
+
332
+ # Store system prompt for use in individual requests
333
+ self.system_prompt = """You are a multimodal coding assistant. Your capabilities include:
334
+ 1. Analyzing images containing code or problem statements
335
+ 2. Generating code solutions for coding problems in multiple programming languages
336
+ 3. Explaining and debugging code execution results
337
+
338
+ Follow these guidelines:
339
+ - For image analysis, extract and describe any code or problem statements clearly
340
+ - For code generation, write clean, efficient code with proper documentation in the requested language
341
+ - For execution results, provide clear explanations of outputs or errors
342
+ - Always prioritize security and avoid suggesting dangerous code constructs
343
+ - Generate code in the exact format and language requested by the user
344
+ - Match the user's requirements precisely without deviation"""
345
+
346
+ def process_image(self, image: Image.Image, language: str = 'python') -> str:
347
+ """Process an image containing code or problem statement"""
348
+ prompt = f"""{self.system_prompt}
349
+
350
+ Analyze this image and extract any coding problem or code snippet shown.
351
+ Be very specific about what you see in the image. If you see actual code, transcribe it exactly.
352
+ Describe it in clear natural language, including any:
353
+ 1. Problem statement or code functionality
354
+ 2. Variable assignments and function definitions
355
+ 3. Logic flow and conditions
356
+ 4. Expected behavior or output
357
+ Format it as a proper coding problem description for {language} language.
358
+
359
+ IMPORTANT: If you see actual code in the image, describe exactly what the code does, don't create a generic problem."""
360
+
361
+ # Save image to a temporary file
362
+ with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
363
+ image.save(tmp.name, format="PNG")
364
+ tmp_path = tmp.name
365
+
366
+ try:
367
+ response = self.agent.run(
368
+ prompt,
369
+ images=[{"filepath": tmp_path}]
370
+ )
371
+ return response.content
372
+ except Exception as e:
373
+ error_msg = str(e)
374
+ if "503" in error_msg or "Service Unavailable" in error_msg:
375
+ return """⚠️ **Gemini API Temporarily Unavailable**
376
+
377
+ The Gemini vision service is currently experiencing issues (503 error). This is a temporary server-side problem.
378
+
379
+ **What you can do:**
380
+ 1. Wait a few minutes and try again
381
+ 2. Check the Gemini API status page
382
+ 3. Or describe your code/problem in text instead
383
+
384
+ **Based on common code patterns, I can still help you if you describe what you saw in the image in the text field below.**"""
385
+ elif "API key" in error_msg:
386
+ return "❌ **API Key Error**: Please check that your Gemini API key is valid and has access to vision features."
387
+ elif "quota" in error_msg.lower() or "limit" in error_msg.lower():
388
+ return "❌ **Rate Limit/Quota Error**: You've exceeded the API usage limits. Please wait or upgrade your plan."
389
+ else:
390
+ return f"❌ **Error processing image**: {error_msg}\n\nπŸ’‘ **Tip**: Try describing your code/problem in text instead."
391
+ finally:
392
+ # Clean up temporary file
393
+ if os.path.exists(tmp_path):
394
+ os.remove(tmp_path)
395
+
396
+ def generate_code(self, problem_description: str, language: str = 'python') -> str:
397
+ """Generate code for a given problem description in the specified language"""
398
+
399
+ # Check if this is a multi-file project request
400
+ multi_file_keywords = [
401
+ 'landing page', 'website', 'web app', 'mvp', 'portfolio',
402
+ 'dashboard', 'form', 'html css js', 'html, css, js',
403
+ 'html css javascript', 'full website', 'complete website'
404
+ ]
405
+
406
+ is_multi_file = any(keyword in problem_description.lower() for keyword in multi_file_keywords)
407
+
408
+ if is_multi_file and language in ['html', 'css', 'javascript']:
409
+ return self._generate_multi_file_project(problem_description)
410
+
411
+ # Language-specific requirements and templates
412
+ language_specs = {
413
+ 'python': {
414
+ 'requirements': """1. Write clean, efficient Python code with proper documentation
415
+ 2. Include proper function definitions with type hints
416
+ 3. Handle edge cases appropriately
417
+ 4. Include example usage if applicable
418
+ 5. Only use standard library modules (no external dependencies)""",
419
+ 'format_instruction': "Format your response with the code in a ```python code block."
420
+ },
421
+ 'javascript': {
422
+ 'requirements': """1. Write modern JavaScript (ES6+) code with proper documentation
423
+ 2. Use appropriate function declarations/expressions
424
+ 3. Handle edge cases appropriately
425
+ 4. Include example usage if applicable
426
+ 5. Use built-in JavaScript features and methods""",
427
+ 'format_instruction': "Format your response with the code in a ```javascript code block."
428
+ },
429
+ 'typescript': {
430
+ 'requirements': """1. Write TypeScript code with proper type annotations
431
+ 2. Use interfaces and types where appropriate
432
+ 3. Handle edge cases appropriately
433
+ 4. Include example usage if applicable
434
+ 5. Follow TypeScript best practices""",
435
+ 'format_instruction': "Format your response with the code in a ```typescript code block."
436
+ },
437
+ 'html': {
438
+ 'requirements': """1. Write semantic HTML5 code
439
+ 2. Use proper HTML structure and tags
440
+ 3. Include appropriate meta tags and attributes
441
+ 4. Follow accessibility best practices
442
+ 5. Use semantic elements where applicable""",
443
+ 'format_instruction': "Format your response with the code in a ```html code block."
444
+ },
445
+ 'css': {
446
+ 'requirements': """1. Write clean, organized CSS code
447
+ 2. Use appropriate selectors and properties
448
+ 3. Follow CSS best practices and conventions
449
+ 4. Include responsive design considerations if applicable
450
+ 5. Use modern CSS features where appropriate""",
451
+ 'format_instruction': "Format your response with the code in a ```css code block."
452
+ },
453
+ 'tsx': {
454
+ 'requirements': """1. Write React TypeScript (TSX) code with proper types
455
+ 2. Use React hooks and modern patterns
456
+ 3. Include proper component structure
457
+ 4. Follow React and TypeScript best practices
458
+ 5. Handle props and state appropriately""",
459
+ 'format_instruction': "Format your response with the code in a ```tsx code block."
460
+ },
461
+ 'java': {
462
+ 'requirements': """1. Write clean Java code following conventions
463
+ 2. Use appropriate access modifiers and OOP principles
464
+ 3. Handle exceptions properly
465
+ 4. Include proper class and method structure
466
+ 5. Follow Java naming conventions""",
467
+ 'format_instruction': "Format your response with the code in a ```java code block."
468
+ },
469
+ 'c': {
470
+ 'requirements': """1. Write clean C code with proper structure
471
+ 2. Include necessary headers
472
+ 3. Handle memory management carefully
473
+ 4. Use appropriate data types and functions
474
+ 5. Follow C programming conventions""",
475
+ 'format_instruction': "Format your response with the code in a ```c code block."
476
+ },
477
+ 'cpp': {
478
+ 'requirements': """1. Write modern C++ code (C++11 or later)
479
+ 2. Use appropriate STL containers and algorithms
480
+ 3. Follow RAII principles and best practices
481
+ 4. Include proper headers and namespaces
482
+ 5. Handle exceptions and edge cases appropriately""",
483
+ 'format_instruction': "Format your response with the code in a ```cpp code block."
484
+ }
485
+ }
486
+
487
+ spec = language_specs.get(language, language_specs['python'])
488
+
489
+ prompt = f"""{self.system_prompt}
490
+
491
+ Based on this problem description, write {language} code to solve it:
492
+
493
+ {problem_description}
494
+
495
+ Requirements:
496
+ {spec['requirements']}
497
+
498
+ {spec['format_instruction']}
499
+
500
+ IMPORTANT: Generate code that exactly matches what the user requested. Do not add extra features or modify the requirements. Provide the exact output format requested."""
501
+
502
+ try:
503
+ response = self.agent.run(prompt)
504
+ return response.content
505
+ except Exception as e:
506
+ return f"Error generating code: {str(e)}"
507
+
508
+ def _generate_multi_file_project(self, problem_description: str) -> str:
509
+ """Generate a complete multi-file web project (HTML, CSS, JS)"""
510
+ prompt = f"""{self.system_prompt}
511
+
512
+ Create a complete web project based on this description:
513
+ {problem_description}
514
+
515
+ Generate a fully functional website with:
516
+ 1. HTML file (index.html) - semantic, accessible structure
517
+ 2. CSS file (styles.css) - modern, responsive styling
518
+ 3. JavaScript file (script.js) - interactive functionality
519
+
520
+ Requirements:
521
+ - Make it responsive and mobile-friendly
522
+ - Use modern web standards (HTML5, CSS3, ES6+)
523
+ - Include proper meta tags and SEO basics
524
+ - Add smooth animations and interactions
525
+ - Follow accessibility best practices
526
+ - Make it visually appealing and professional
527
+
528
+ Format your response EXACTLY like this:
529
+
530
+ ## πŸ“ Project Files
531
+
532
+ ### πŸ“„ index.html
533
+ ```html
534
+ [Complete HTML code here]
535
+ ```
536
+
537
+ ### 🎨 styles.css
538
+ ```css
539
+ [Complete CSS code here]
540
+ ```
541
+
542
+ ### ⚑ script.js
543
+ ```javascript
544
+ [Complete JavaScript code here]
545
+ ```
546
+
547
+ ### πŸ“‹ Instructions
548
+ [Brief setup and usage instructions]
549
+
550
+ IMPORTANT:
551
+ - Generate complete, working code for each file
552
+ - Make sure all files work together seamlessly
553
+ - Include all necessary functionality requested
554
+ - Use proper file structure and organization
555
+ - Follow the exact format specified above"""
556
+
557
+ try:
558
+ response = self.agent.run(prompt)
559
+ return response.content
560
+ except Exception as e:
561
+ return f"Error generating multi-file project: {str(e)}"
562
+
563
+ def execute_and_explain(self, code: str, language: str = 'python') -> str:
564
+ """Execute code and provide explanation of results"""
565
+ # Extract code from markdown if needed
566
+ code_blocks = [f'```{language}', f'```{language.lower()}', '```']
567
+ extracted_code = code
568
+
569
+ for block_start in code_blocks:
570
+ if block_start in code:
571
+ parts = code.split(block_start)
572
+ if len(parts) > 1:
573
+ extracted_code = parts[1].split("```")[0].strip()
574
+ break
575
+
576
+ # Execute the code
577
+ result = self.executor.run_code(extracted_code, language)
578
+
579
+ # Generate explanation
580
+ if result["success"]:
581
+ prompt = f"""{self.system_prompt}
582
+
583
+ The following {language} code was executed successfully:
584
+
585
+ ```{language}
586
+ {extracted_code}
587
+ ```
588
+
589
+ Output: {result['output']}
590
+ Logs: {result['logs']}
591
+
592
+ Please explain what the code does and the execution results for this {language} program."""
593
+ else:
594
+ prompt = f"""{self.system_prompt}
595
+
596
+ The following {language} code failed to execute:
597
+
598
+ ```{language}
599
+ {extracted_code}
600
+ ```
601
+
602
+ Error: {result['error']}
603
+ Logs: {result['logs']}
604
+
605
+ Please analyze the error and suggest fixes for this {language} code."""
606
+
607
+ try:
608
+ response = self.agent.run(prompt)
609
+ return response.content
610
+ except Exception as e:
611
+ return f"Error explaining execution: {str(e)}\n\nRaw execution result: {str(result)}"
612
+
613
+ def save_project_files(self, content: str, project_name: str = "generated_project") -> str:
614
+ """Save multi-file project to disk and return the file paths"""
615
+ if "## πŸ“ Project Files" not in content:
616
+ return ""
617
+
618
+ try:
619
+ # Create project directory
620
+ project_dir = os.path.join(os.getcwd(), project_name)
621
+ os.makedirs(project_dir, exist_ok=True)
622
+
623
+ saved_files = []
624
+
625
+ # Extract and save HTML file
626
+ if "### πŸ“„ index.html" in content:
627
+ html_start = content.find("```html")
628
+ if html_start != -1:
629
+ html_start = html_start + 7
630
+ html_end = content.find("```", html_start)
631
+ if html_end != -1:
632
+ html_content = content[html_start:html_end].strip()
633
+ html_path = os.path.join(project_dir, "index.html")
634
+ with open(html_path, 'w', encoding='utf-8') as f:
635
+ f.write(html_content)
636
+ saved_files.append("index.html")
637
+
638
+ # Extract and save CSS file
639
+ if "### 🎨 styles.css" in content:
640
+ css_start = content.find("```css")
641
+ if css_start != -1:
642
+ css_start = css_start + 6
643
+ css_end = content.find("```", css_start)
644
+ if css_end != -1:
645
+ css_content = content[css_start:css_end].strip()
646
+ css_path = os.path.join(project_dir, "styles.css")
647
+ with open(css_path, 'w', encoding='utf-8') as f:
648
+ f.write(css_content)
649
+ saved_files.append("styles.css")
650
+
651
+ # Extract and save JavaScript file
652
+ if "### ⚑ script.js" in content:
653
+ js_start = content.find("```javascript")
654
+ if js_start != -1:
655
+ js_start = js_start + 13
656
+ js_end = content.find("```", js_start)
657
+ if js_end != -1:
658
+ js_content = content[js_start:js_end].strip()
659
+ js_path = os.path.join(project_dir, "script.js")
660
+ with open(js_path, 'w', encoding='utf-8') as f:
661
+ f.write(js_content)
662
+ saved_files.append("script.js")
663
+
664
+ if saved_files:
665
+ return f"\n\n### πŸ’Ύ Files Saved Successfully!\nπŸ“ Project saved to: `{project_dir}`\nπŸ“‹ Files created: {', '.join(saved_files)}\n\n🌐 **To view your website**: Open `index.html` in your web browser!"
666
+
667
+ except Exception as e:
668
+ return f"\n\n❌ Error saving files: {str(e)}"
669
+
670
+ return ""
671
+
672
+ def create_gradio_interface():
673
+ """Create the Gradio interface for the coding agent"""
674
+
675
+ agent_instance = None
676
+
677
+ def process_input(api_key, language, image, text_input, save_files):
678
+ nonlocal agent_instance
679
+
680
+ # Initialize agent if not already done
681
+ if not agent_instance:
682
+ if not api_key:
683
+ return "Please enter your Gemini API key first."
684
+ try:
685
+ agent_instance = MultimodalCodingAgent(api_key)
686
+ except Exception as e:
687
+ return f"Error initializing agent: {str(e)}"
688
+
689
+ # Check if this is a multi-file project request
690
+ multi_file_keywords = [
691
+ 'landing page', 'website', 'web app', 'mvp', 'portfolio',
692
+ 'dashboard', 'form', 'html css js', 'html, css, js',
693
+ 'html css javascript', 'full website', 'complete website'
694
+ ]
695
+
696
+ input_text = text_input if text_input else ""
697
+ is_multi_file_request = any(keyword in input_text.lower() for keyword in multi_file_keywords)
698
+
699
+ # Process based on input type
700
+ if image is not None:
701
+ # Process image
702
+ problem_description = agent_instance.process_image(image, language)
703
+
704
+ # Check if image processing failed
705
+ if "⚠️" in problem_description or "❌" in problem_description:
706
+ return problem_description
707
+
708
+ # Generate code from the problem description
709
+ code = agent_instance.generate_code(problem_description, language)
710
+
711
+ # Handle multi-file projects
712
+ if is_multi_file_request or "## πŸ“ Project Files" in code:
713
+ result = f"**Extracted Problem ({language.upper()}):**\n{problem_description}\n\n{code}"
714
+ if save_files:
715
+ save_result = agent_instance.save_project_files(code, "extracted_project")
716
+ result += save_result
717
+ return result
718
+
719
+ # Execute and explain the code (if it's an executable language)
720
+ elif language in ['python', 'javascript', 'typescript', 'tsx', 'java', 'c', 'cpp']:
721
+ explanation = agent_instance.execute_and_explain(code, language)
722
+ return f"**Extracted Problem ({language.upper()}):**\n{problem_description}\n\n**Generated Code:**\n{code}\n\n**Execution Results:**\n{explanation}"
723
+ else:
724
+ return f"**Extracted Problem ({language.upper()}):**\n{problem_description}\n\n**Generated Code:**\n{code}\n\n**Note:** {language.upper()} code cannot be executed but has been validated for syntax."
725
+
726
+ elif text_input:
727
+ # Generate code from text input
728
+ code = agent_instance.generate_code(text_input, language)
729
+
730
+ # Handle multi-file projects
731
+ if is_multi_file_request or "## πŸ“ Project Files" in code:
732
+ result = f"{code}"
733
+ if save_files:
734
+ save_result = agent_instance.save_project_files(code, "generated_project")
735
+ result += save_result
736
+ return result
737
+
738
+ # Execute and explain the code (if it's an executable language)
739
+ elif language in ['python', 'javascript', 'typescript', 'tsx', 'java', 'c', 'cpp']:
740
+ explanation = agent_instance.execute_and_explain(code, language)
741
+ return f"**Generated Code ({language.upper()}):**\n{code}\n\n**Execution Results:**\n{explanation}"
742
+ else:
743
+ return f"**Generated Code ({language.upper()}):**\n{code}\n\n**Note:** {language.upper()} code cannot be executed but has been validated for syntax."
744
+
745
+ else:
746
+ return "Please provide either an image or text input."
747
+
748
+ # Create Gradio interface
749
+ with gr.Blocks(title="Multimodal Coding Agent", theme=gr.themes.Soft()) as demo:
750
+ gr.Markdown("# πŸš€ Multimodal Coding Agent")
751
+ gr.Markdown("Upload an image of a coding problem or describe it in text, and I'll generate and execute a solution in your chosen programming language!")
752
+
753
+ with gr.Row():
754
+ api_key = gr.Textbox(
755
+ label="πŸ”‘ Gemini API Key",
756
+ type="password",
757
+ placeholder="Enter your Gemini API key here",
758
+ scale=3
759
+ )
760
+ language_dropdown = gr.Dropdown(
761
+ label="πŸ’» Programming Language",
762
+ choices=[
763
+ "python", "javascript", "typescript", "tsx",
764
+ "java", "c", "cpp", "html", "css"
765
+ ],
766
+ value="python",
767
+ scale=1
768
+ )
769
+
770
+ with gr.Row():
771
+ with gr.Column():
772
+ image_input = gr.Image(
773
+ label="πŸ“Έ Upload Image of Coding Problem",
774
+ type="pil"
775
+ )
776
+ text_input = gr.Textbox(
777
+ label="✏️ Or Describe Your Coding Problem",
778
+ lines=5,
779
+ placeholder="Example: Write a function to reverse a string\n\nFor web projects, try:\n- Make a MVP landing page using HTML, CSS and JS\n- Create a portfolio website\n- Build a responsive dashboard"
780
+ )
781
+
782
+ with gr.Row():
783
+ submit_btn = gr.Button("🎯 Generate & Execute Solution", variant="primary", scale=3)
784
+ save_files_checkbox = gr.Checkbox(
785
+ label="πŸ’Ύ Save files to disk",
786
+ value=False,
787
+ scale=1,
788
+ info="Auto-save multi-file projects"
789
+ )
790
+
791
+ with gr.Column():
792
+ output = gr.Markdown(label="πŸ“‹ Results", value="", height=600)
793
+
794
+ # Language info display
795
+ with gr.Row():
796
+ gr.Markdown("""
797
+ ### πŸ“š Supported Languages & Features:
798
+ - **Python**: Full execution with safety restrictions
799
+ - **JavaScript/TypeScript**: Requires Node.js/ts-node
800
+ - **Java**: Requires JDK for compilation and execution
801
+ - **C/C++**: Requires GCC/G++ compiler
802
+ - **HTML/CSS**: Syntax validation + Multi-file web projects
803
+ - **TSX**: React TypeScript components (requires setup)
804
+
805
+ ### 🌐 Multi-File Web Projects:
806
+ Use keywords like "landing page", "website", "MVP", "portfolio" to generate complete web projects with HTML, CSS, and JavaScript files automatically organized and saved!
807
+
808
+ ### πŸ“Έ Image Processing Tips:
809
+ - **If image processing fails (503 errors)**: This is usually temporary - wait a few minutes and retry
810
+ - **Alternative**: Describe your code in text instead of uploading an image
811
+ - **Best images**: Clear, high-contrast code screenshots work best
812
+
813
+ ### ⚠️ Prerequisites:
814
+ Make sure you have the required compilers/interpreters installed for code execution.
815
+ """)
816
+
817
+ submit_btn.click(
818
+ fn=process_input,
819
+ inputs=[api_key, language_dropdown, image_input, text_input, save_files_checkbox],
820
+ outputs=output
821
+ )
822
+
823
+ # Add examples
824
+ gr.Examples(
825
+ examples=[
826
+ ["python", None, "Write a function to find the factorial of a number", False],
827
+ ["javascript", None, "Create a function to check if a string is a palindrome", False],
828
+ ["html", None, "Make a MVP landing page using HTML, CSS and JS", True],
829
+ ["html", None, "Create a responsive portfolio website", True],
830
+ ["html", None, "Build a modern dashboard with navigation", True],
831
+ ["java", None, "Write a class to implement a simple calculator", False],
832
+ ["css", None, "Design a card component with hover effects", False],
833
+ ],
834
+ inputs=[language_dropdown, image_input, text_input, save_files_checkbox],
835
+ )
836
+
837
+ return demo
838
+
839
+ if __name__ == "__main__":
840
+ demo = create_gradio_interface()
841
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Core Dependencies
2
+ gradio>=4.0.0
3
+ agno>=0.1.0
4
+ pillow>=9.0.0
5
+
6
+ # Google AI Dependencies
7
+ google-generativeai>=0.3.0
8
+
9
+ # Utility Dependencies
10
+ requests>=2.28.0
11
+ typing-extensions>=4.0.0
12
+
13
+ # Development Dependencies (Optional)
14
+ pytest>=7.0.0
15
+ black>=22.0.0
16
+ flake8>=5.0.0
17
+
18
+ # System Dependencies for Multi-language Support
19
+ # Note: The following require system-level installation:
20
+ # - Node.js (for JavaScript/TypeScript)
21
+ # - OpenJDK or Oracle JDK (for Java)
22
+ # - GCC/G++ (for C/C++)
23
+ # - ts-node (npm install -g ts-node) for TypeScript
24
+
25
+ # Optional: For enhanced image processing
26
+ opencv-python>=4.5.0
27
+ numpy>=1.21.0
28
+
29
+ # Web Server (if deploying)
30
+ uvicorn>=0.18.0
31
+ fastapi>=0.85.0