CoolFace
Apppublic

Vignesh-1918/Kaggle_Agent

sourceHugging Faceupdated 1y agoView on Hugging Face
2likes
kernel_client.py406 linesDownload Raw Back to kaggle_agent
1"""
2Safe kernel client for code execution in HF Spaces Docker environment
3"""
4
5import time
6import random
7import re
8import os
9import tempfile
10from typing import Dict, Any, List, Optional
11import json
12
13class KernelClient:
14    """Safe kernel client optimized for Hugging Face Spaces Docker deployment."""
15    
16    def __init__(self):
17        self.execution_count = 0
18        self.variables = {
19            'df': 'DataFrame(sample_data)',
20            'X': 'Feature matrix',
21            'y': 'Target variable'
22        }
23        self.imports = set()
24        self.execution_history = []
25        self.temp_dir = '/tmp'
26        
27        # Ensure temp directory exists
28        os.makedirs(self.temp_dir, exist_ok=True)
29    
30    def execute(self, code: str, namespace: Dict[str, Any] = None) -> Dict[str, Any]:
31        """
32        Main execution method compatible with HF Spaces.
33        Simulates safe code execution with realistic outputs.
34        """
35        return self.execute_code(code, namespace=namespace)
36        
37    def execute_code(self, code: str, timeout: int = 30, namespace: Dict[str, Any] = None) -> Dict[str, Any]:
38        """
39        Simulate code execution safely for HF Spaces environment.
40        """
41        self.execution_count += 1
42        
43        # Merge provided namespace with existing variables
44        if namespace:
45            self.variables.update(namespace)
46        
47        # Simulate execution time based on code complexity
48        execution_time = self._estimate_execution_time(code)
49        
50        # Store execution history
51        self.execution_history.append({
52            'code': code,
53            'execution_count': self.execution_count,
54            'timestamp': time.time()
55        })
56        
57        # Analyze code to provide realistic simulation
58        result = self._simulate_execution(code)
59        result.update({
60            'success': result.get('status') == 'ok',
61            'execution_count': self.execution_count,
62            'execution_time_s': execution_time,
63            'variables': self.get_variables(),
64            'plots': result.get('plots', [])
65        })
66        
67        return result
68    
69    def _estimate_execution_time(self, code: str) -> float:
70        """Estimate execution time based on code complexity."""
71        base_time = 0.05
72        
73        # Add time based on operations
74        complexity_factors = {
75            ('read_csv', 'load_data', 'pd.read'): 0.3,
76            ('plot', 'show', 'heatmap', 'hist', 'scatter'): 0.2,
77            ('fit', 'train', 'cross_val', 'GridSearch'): 0.8,
78            ('for ', 'while ', 'apply'): 0.15,
79            ('merge', 'join', 'concat'): 0.1
80        }
81        
82        for patterns, time_add in complexity_factors.items():
83            if any(pattern in code.lower() for pattern in patterns):
84                base_time += time_add
85        
86        return min(base_time, 2.0)  # Cap at 2 seconds for HF Spaces
87    
88    def _simulate_execution(self, code: str) -> Dict[str, Any]:
89        """Simulate code execution results optimized for HF Spaces."""
90        
91        lines = code.strip().split('\n')
92        outputs = []
93        plots = []
94        
95        # Track imports
96        self._update_imports(code)
97        
98        # Check for syntax errors first
99        if self._has_syntax_errors(code):
100            return {
101                'status': 'error',
102                'success': False,
103                'error': 'Syntax error in code',
104                'ename': 'SyntaxError',
105                'evalue': 'invalid syntax',
106                'traceback': ['SyntaxError: invalid syntax'],
107                'output': 'Error: Invalid syntax detected',
108                'outputs': [],
109                'plots': []
110            }
111        
112        # Process code line by line
113        stdout_output = []
114        
115        for line in lines:
116            line = line.strip()
117            if not line or line.startswith('#'):
118                continue
119                
120            # Handle different types of operations
121            line_output = self._process_code_line(line)
122            if line_output:
123                if line_output.get('type') == 'stdout':
124                    stdout_output.append(line_output['content'])
125                elif line_output.get('type') == 'plot':
126                    plots.append(line_output['content'])
127                else:
128                    outputs.append(line_output)
129        
130        # Combine stdout outputs
131        combined_output = '\n'.join(stdout_output) if stdout_output else 'Code executed successfully.'
132        
133        return {
134            'status': 'ok',
135            'success': True,
136            'output': combined_output,
137            'outputs': outputs,
138            'plots': plots,
139            'error': None
140        }
141    
142    def _process_code_line(self, line: str) -> Optional[Dict[str, Any]]:
143        """Process individual code line and return appropriate output."""
144        
145        # Print statements
146        if 'print(' in line:
147            content = self._simulate_print_output(line)
148            return {'type': 'stdout', 'content': content}
149        
150        # DataFrame operations
151        elif any(op in line for op in ['.head()', '.info()', '.describe()', '.shape']):
152            content = self._simulate_dataframe_text_output(line)
153            return {'type': 'stdout', 'content': content}
154        
155        # Plotting operations
156        elif any(plot in line for plot in ['plt.show()', 'plt.savefig(', 'sns.', 'plot(', 'hist(', 'scatter(']):
157            plot_path = self._generate_plot_file()
158            return {'type': 'plot', 'content': plot_path}
159        
160        # Model training and ML operations
161        elif any(ml in line for ml in ['fit(', 'train', 'cross_val_score', 'accuracy_score']):
162            content = self._simulate_ml_output(line)
163            return {'type': 'stdout', 'content': content}
164        
165        # Variable assignments
166        elif '=' in line and not any(op in line for op in ['==', '!=', '>=', '<=']):
167            self._update_variables(line)
168            return None
169        
170        return None
171    
172    def _generate_plot_file(self) -> str:
173        """Generate a placeholder plot file path."""
174        plot_filename = f'plot_{self.execution_count}_{int(time.time())}.png'
175        plot_path = os.path.join(self.temp_dir, plot_filename)
176        
177        # Create a minimal placeholder file (1x1 pixel PNG)
178        png_data = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x02\x00\x00\x00\x90wS\xde\x00\x00\x00\tpHYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\x00\x00\x00\nIDATx\x9cc```\x00\x00\x00\x04\x00\x01\xdd\x8d\xb4\x1c\x00\x00\x00\x00IEND\xaeB`\x82'
179        
180        try:
181            with open(plot_path, 'wb') as f:
182                f.write(png_data)
183        except Exception:
184            # Fallback if file creation fails
185            pass
186            
187        return plot_path
188    
189    def _update_imports(self, code: str):
190        """Track imported libraries."""
191        import_patterns = [
192            r'import (\w+)',
193            r'from (\w+) import',
194            r'import (\w+) as'
195        ]
196        
197        for pattern in import_patterns:
198            matches = re.findall(pattern, code)
199            self.imports.update(matches)
200    
201    def _simulate_print_output(self, print_statement: str) -> str:
202        """Simulate realistic output from print statements."""
203        
204        # Extract content between parentheses
205        try:
206            start = print_statement.find('(') + 1
207            end = print_statement.rfind(')')
208            content = print_statement[start:end].strip()
209        except:
210            return 'Print output'
211        
212        # Common patterns and their outputs
213        patterns = {
214            'df.shape': '(1000, 15)',
215            'shape': '(1000, 15)', 
216            'df.columns': "Index(['feature1', 'feature2', 'feature3', 'target'], dtype='object')",
217            'columns': "['feature1', 'feature2', 'feature3', 'target']",
218            'len(df)': '1000',
219            'len(': '1000',
220            'dataset': 'Dataset loaded successfully!',
221            'loaded': 'Data loaded successfully!',
222            'shape': '(1000, 15)',
223            'accuracy': 'Accuracy: 0.8563',
224            'score': 'Model Score: 0.8234', 
225            'training': 'Training completed successfully',
226            'model': 'Model training completed',
227            'cross': 'Cross-validation scores: [0.85, 0.83, 0.87, 0.84, 0.86]'
228        }
229        
230        # Match patterns
231        content_lower = content.lower()
232        for pattern, output in patterns.items():
233            if pattern in content_lower:
234                return output
235        
236        # Handle f-strings and formatted strings
237        if 'f"' in content or "f'" in content:
238            return f'Formatted output: {random.choice(["value = 42", "result = 0.85", "count = 1000"])}'
239        elif content.startswith('"') or content.startswith("'"):
240            # String literal - remove quotes
241            return content.strip('"\'')
242        else:
243            return f'Output: {content}'
244    
245    def _simulate_dataframe_text_output(self, line: str) -> str:
246        """Simulate DataFrame operations as text output for HF Spaces."""
247        
248        if '.head()' in line:
249            return """   feature1  feature2  feature3  target
2500      1.23      4.56      7.89       0
2511      2.34      5.67      8.90       1
2522      3.45      6.78      9.01       0
2533      4.56      7.89      0.12       1
2544      5.67      8.90      1.23       0"""
255        
256        elif '.info()' in line:
257            return """<class 'pandas.core.frame.DataFrame'>
258RangeIndex: 1000 entries, 0 to 999
259Data columns (total 4 columns):
260 #   Column    Non-Null Count  Dtype  
261---  ------    --------------  -----  
262 0   feature1  1000 non-null   float64
263 1   feature2  1000 non-null   float64
264 2   feature3  1000 non-null   float64
265 3   target    1000 non-null   int64  
266dtypes: float64(3), int64(1)
267memory usage: 31.4 KB"""
268        
269        elif '.describe()' in line:
270            return """         feature1    feature2    feature3      target
271count  1000.000000  1000.000000  1000.000000  1000.000000
272mean      2.456789     5.123456     7.890123     0.489000
273std       1.234567     2.345678     3.456789     0.500122
274min       0.100000     1.200000     2.300000     0.000000
27525%       1.800000     3.900000     5.600000     0.000000
27650%       2.400000     5.100000     7.800000     0.000000
27775%       3.100000     6.300000     9.100000     1.000000
278max       5.900000     8.700000    12.500000     1.000000"""
279        
280        elif '.shape' in line:
281            return '(1000, 4)'
282        
283        else:
284            return 'DataFrame operation completed'
285    
286    def _simulate_ml_output(self, line: str) -> str:
287        """Simulate machine learning operation outputs."""
288        
289        if 'fit(' in line:
290            return 'Model training completed successfully'
291        elif 'cross_val_score' in line:
292            scores = [round(0.8 + random.uniform(-0.1, 0.1), 4) for _ in range(5)]
293            return f'Cross-validation scores: {scores}\nMean CV score: {sum(scores)/len(scores):.4f}'
294        elif 'accuracy_score' in line or '.score(' in line:
295            score = round(0.8 + random.uniform(-0.15, 0.15), 4)
296            return f'Model Accuracy: {score}'
297        elif 'predict(' in line:
298            return 'Predictions generated successfully'
299        elif 'classification_report' in line:
300            return """              precision    recall  f1-score   support
301
302           0       0.85      0.82      0.83       120
303           1       0.83      0.86      0.85       130
304
305    accuracy                           0.84       250
306   macro avg       0.84      0.84      0.84       250
307weighted avg       0.84      0.84      0.84       250"""
308        else:
309            return 'Machine learning operation completed'
310    
311    def _update_variables(self, assignment_line: str):
312        """Update tracked variables based on assignments."""
313        try:
314            var_name = assignment_line.split('=')[0].strip()
315            right_side = assignment_line.split('=')[1].strip()
316            
317            if var_name.replace('_', '').replace('[', '').replace(']', '').isalnum():
318                var_type = self._determine_variable_type(right_side)
319                self.variables[var_name] = var_type
320        except:
321            pass
322    
323    def _determine_variable_type(self, assignment_right: str) -> str:
324        """Determine variable type from assignment."""
325        
326        type_patterns = {
327            'pd.read_csv': 'DataFrame',
328            'pd.read_excel': 'DataFrame', 
329            'pd.DataFrame': 'DataFrame',
330            'train_test_split': 'Split Data',
331            'RandomForest': 'RandomForest Model',
332            'LogisticRegression': 'LogisticRegression Model',
333            'LinearRegression': 'LinearRegression Model',
334            'np.array': 'NumPy Array',
335            '.fit(': 'Trained Model',
336            '.predict(': 'Predictions',
337            '.transform(': 'Transformed Data'
338        }
339        
340        for pattern, var_type in type_patterns.items():
341            if pattern in assignment_right:
342                return var_type
343        
344        return 'Variable'
345    
346    def _has_syntax_errors(self, code: str) -> bool:
347        """Check for basic syntax errors."""
348        try:
349            # Basic syntax validation
350            compile(code, '<string>', 'exec')
351            return False
352        except SyntaxError:
353            return True
354        except:
355            # Other errors (like undefined variables) are OK for simulation
356            return False
357    
358    def get_variables(self) -> Dict[str, str]:
359        """Get currently tracked variables."""
360        return self.variables.copy()
361    
362    def get_imports(self) -> List[str]:
363        """Get list of imported libraries."""
364        return list(self.imports)
365    
366    def get_execution_history(self) -> List[Dict[str, Any]]:
367        """Get execution history."""
368        return self.execution_history.copy()
369    
370    def reset_kernel(self):
371        """Reset the kernel state."""
372        self.execution_count = 0
373        self.variables = {'df': 'DataFrame(sample_data)'}
374        self.imports = set()
375        self.execution_history = []
376        
377        # Clean up temp files
378        try:
379            for file in os.listdir(self.temp_dir):
380                if file.startswith('plot_'):
381                    os.remove(os.path.join(self.temp_dir, file))
382        except:
383            pass
384    
385    def shutdown(self):
386        """Shutdown the kernel client and cleanup."""
387        try:
388            # Clean up temporary files
389            for file in os.listdir(self.temp_dir):
390                if file.startswith('plot_'):
391                    os.remove(os.path.join(self.temp_dir, file))
392        except:
393            pass
394        
395        print(f"Kernel client shutdown after {self.execution_count} executions")
396    
397    def get_status(self) -> Dict[str, Any]:
398        """Get kernel status information."""
399        return {
400            'status': 'ready',
401            'execution_count': self.execution_count,
402            'variables_count': len(self.variables),
403            'imports_count': len(self.imports),
404            'temp_dir': self.temp_dir,
405            'history_length': len(self.execution_history)
406        }