ambivo-agents 1.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,108 @@
1
+ # ambivo_agents/executors/docker_executor.py
2
+ """
3
+ Docker executor for secure code execution.
4
+ """
5
+
6
+ import time
7
+ import tempfile
8
+ from pathlib import Path
9
+ from typing import Dict, Any
10
+
11
+ from ..config.loader import load_config, get_config_section
12
+
13
+ try:
14
+ import docker
15
+ DOCKER_AVAILABLE = True
16
+ except ImportError:
17
+ DOCKER_AVAILABLE = False
18
+
19
+
20
+ class DockerCodeExecutor:
21
+ """Secure code execution using Docker containers"""
22
+
23
+ def __init__(self, config: Dict[str, Any] = None):
24
+ # Load from YAML if config not provided
25
+ if config is None:
26
+ try:
27
+ full_config = load_config()
28
+ config = get_config_section('docker', full_config)
29
+ except Exception:
30
+ config = {}
31
+
32
+ self.config = config
33
+ self.work_dir = config.get("work_dir", '/opt/ambivo/work_dir')
34
+ self.docker_images = config.get("images", ["sgosain/amb-ubuntu-python-public-pod"])
35
+ self.timeout = config.get("timeout", 60)
36
+ self.memory_limit = config.get("memory_limit", "512m")
37
+ self.default_image = self.docker_images[0] if self.docker_images else "sgosain/amb-ubuntu-python-public-pod"
38
+
39
+ if not DOCKER_AVAILABLE:
40
+ raise ImportError("Docker package is required but not installed")
41
+
42
+ try:
43
+ self.docker_client = docker.from_env()
44
+ self.docker_client.ping()
45
+ self.available = True
46
+ except Exception as e:
47
+ raise ConnectionError(f"Failed to connect to Docker: {e}")
48
+
49
+ def execute_code(self, code: str, language: str = "python", files: Dict[str, str] = None) -> Dict[str, Any]:
50
+ """Execute code in Docker container"""
51
+ try:
52
+ with tempfile.TemporaryDirectory() as temp_dir:
53
+ temp_path = Path(temp_dir)
54
+
55
+ if language == "python":
56
+ code_file = temp_path / "code.py"
57
+ code_file.write_text(code)
58
+ cmd = ["python", "/workspace/code.py"]
59
+ elif language == "bash":
60
+ code_file = temp_path / "script.sh"
61
+ code_file.write_text(code)
62
+ cmd = ["bash", "/workspace/script.sh"]
63
+ else:
64
+ raise ValueError(f"Unsupported language: {language}")
65
+
66
+ if files:
67
+ for filename, content in files.items():
68
+ file_path = temp_path / filename
69
+ file_path.write_text(content)
70
+
71
+ container_config = {
72
+ 'image': self.default_image,
73
+ 'command': cmd,
74
+ 'volumes': {str(temp_path): {'bind': '/workspace', 'mode': 'rw'}},
75
+ 'working_dir': '/workspace',
76
+ 'mem_limit': self.memory_limit,
77
+ 'network_disabled': True,
78
+ 'remove': True,
79
+ 'stdout': True,
80
+ 'stderr': True
81
+ }
82
+
83
+ start_time = time.time()
84
+ container = self.docker_client.containers.run(**container_config)
85
+ execution_time = time.time() - start_time
86
+
87
+ output = container.decode('utf-8') if isinstance(container, bytes) else str(container)
88
+
89
+ return {
90
+ 'success': True,
91
+ 'output': output,
92
+ 'execution_time': execution_time,
93
+ 'language': language
94
+ }
95
+
96
+ except docker.errors.ContainerError as e:
97
+ return {
98
+ 'success': False,
99
+ 'error': f"Container error: {e.stderr.decode('utf-8') if e.stderr else 'Unknown error'}",
100
+ 'exit_code': e.exit_status,
101
+ 'language': language
102
+ }
103
+ except Exception as e:
104
+ return {
105
+ 'success': False,
106
+ 'error': str(e),
107
+ 'language': language
108
+ }
@@ -0,0 +1,237 @@
1
+ # ambivo_agents/executors/media_executor.py
2
+ """
3
+ Media Docker executor for FFmpeg operations.
4
+ """
5
+
6
+ import asyncio
7
+ import json
8
+ import time
9
+ import tempfile
10
+ import shutil
11
+ from pathlib import Path
12
+ from typing import Dict, Any
13
+
14
+ from ..config.loader import load_config, get_config_section
15
+
16
+ try:
17
+ import docker
18
+ DOCKER_AVAILABLE = True
19
+ except ImportError:
20
+ DOCKER_AVAILABLE = False
21
+
22
+
23
+ class MediaDockerExecutor:
24
+ """Specialized Docker executor for media processing with ffmpeg"""
25
+
26
+ def __init__(self, config: Dict[str, Any] = None):
27
+ # Load from YAML if config not provided
28
+ if config is None:
29
+ try:
30
+ full_config = load_config()
31
+ config = get_config_section('media_editor', full_config)
32
+ except Exception:
33
+ config = {}
34
+
35
+ self.config = config
36
+ self.work_dir = config.get("work_dir", '/opt/ambivo/work_dir')
37
+ self.docker_image = config.get("docker_image", "sgosain/amb-ubuntu-python-public-pod")
38
+ self.timeout = config.get("timeout", 300) # 5 minutes for media processing
39
+ self.memory_limit = config.get("memory_limit", "2g")
40
+
41
+ # Media specific directories
42
+ self.input_dir = Path(config.get("input_dir", "./media_input"))
43
+ self.output_dir = Path(config.get("output_dir", "./media_output"))
44
+
45
+ # Ensure directories exist
46
+ self.input_dir.mkdir(exist_ok=True)
47
+ self.output_dir.mkdir(exist_ok=True)
48
+
49
+ if not DOCKER_AVAILABLE:
50
+ raise ImportError("Docker package is required for media processing")
51
+
52
+ try:
53
+ self.docker_client = docker.from_env()
54
+ self.docker_client.ping()
55
+ self.available = True
56
+ except Exception as e:
57
+ raise ConnectionError(f"Failed to connect to Docker for media processing: {e}")
58
+
59
+ def execute_ffmpeg_command(self,
60
+ ffmpeg_command: str,
61
+ input_files: Dict[str, str] = None,
62
+ output_filename: str = None,
63
+ work_files: Dict[str, str] = None) -> Dict[str, Any]:
64
+ """
65
+ Execute ffmpeg command in Docker container
66
+
67
+ Args:
68
+ ffmpeg_command: FFmpeg command to execute
69
+ input_files: Dict of {container_path: host_path} for input files
70
+ output_filename: Expected output filename
71
+ work_files: Additional working files needed
72
+ """
73
+ try:
74
+ with tempfile.TemporaryDirectory() as temp_dir:
75
+ temp_path = Path(temp_dir)
76
+
77
+ # Create input and output directories in temp
78
+ container_input = temp_path / "input"
79
+ container_output = temp_path / "output"
80
+ container_input.mkdir()
81
+ container_output.mkdir()
82
+
83
+ # Copy input files to temp directory
84
+ file_mapping = {}
85
+ if input_files:
86
+ for container_name, host_path in input_files.items():
87
+ if Path(host_path).exists():
88
+ dest_path = container_input / container_name
89
+ shutil.copy2(host_path, dest_path)
90
+ file_mapping[container_name] = f"/workspace/input/{container_name}"
91
+ else:
92
+ return {
93
+ 'success': False,
94
+ 'error': f'Input file not found: {host_path}',
95
+ 'command': ffmpeg_command
96
+ }
97
+
98
+ # Copy additional work files
99
+ if work_files:
100
+ for container_name, content in work_files.items():
101
+ work_file = temp_path / container_name
102
+ work_file.write_text(content)
103
+
104
+ # Prepare the ffmpeg command with proper paths
105
+ final_command = ffmpeg_command
106
+ for container_name, container_path in file_mapping.items():
107
+ final_command = final_command.replace(f"${{{container_name}}}", container_path)
108
+
109
+ # Add output path
110
+ if output_filename:
111
+ final_command = final_command.replace("${OUTPUT}", f"/workspace/output/{output_filename}")
112
+
113
+ # Create execution script
114
+ script_content = f"""#!/bin/bash
115
+ set -e
116
+ cd /workspace
117
+
118
+ echo "FFmpeg version:"
119
+ ffmpeg -version | head -1
120
+
121
+ echo "Starting media processing..."
122
+ echo "Command: {final_command}"
123
+
124
+ # Execute the command
125
+ {final_command}
126
+
127
+ echo "Media processing completed successfully"
128
+ ls -la /workspace/output/
129
+ """
130
+
131
+ script_file = temp_path / "process_media.sh"
132
+ script_file.write_text(script_content)
133
+ script_file.chmod(0o755)
134
+
135
+ # Container configuration for media processing
136
+ container_config = {
137
+ 'image': self.docker_image,
138
+ 'command': ["bash", "/workspace/process_media.sh"],
139
+ 'volumes': {str(temp_path): {'bind': '/workspace', 'mode': 'rw'}},
140
+ 'working_dir': '/workspace',
141
+ 'mem_limit': self.memory_limit,
142
+ 'network_disabled': True,
143
+ 'remove': True,
144
+ 'stdout': True,
145
+ 'stderr': True,
146
+ 'environment': {
147
+ 'FFMPEG_PATH': '/usr/bin/ffmpeg',
148
+ 'FFPROBE_PATH': '/usr/bin/ffprobe'
149
+ }
150
+ }
151
+
152
+ start_time = time.time()
153
+
154
+ try:
155
+ result = self.docker_client.containers.run(**container_config)
156
+ execution_time = time.time() - start_time
157
+
158
+ output = result.decode('utf-8') if isinstance(result, bytes) else str(result)
159
+
160
+ # Check if output file was created
161
+ output_files = list(container_output.glob("*"))
162
+ output_info = {}
163
+
164
+ if output_files:
165
+ output_file = output_files[0] # Take first output file
166
+ output_info = {
167
+ 'filename': output_file.name,
168
+ 'size_bytes': output_file.stat().st_size,
169
+ 'path': str(output_file)
170
+ }
171
+
172
+ # Move output file to permanent location
173
+ permanent_output = self.output_dir / output_file.name
174
+ shutil.move(str(output_file), str(permanent_output))
175
+ output_info['final_path'] = str(permanent_output)
176
+
177
+ return {
178
+ 'success': True,
179
+ 'output': output,
180
+ 'execution_time': execution_time,
181
+ 'command': final_command,
182
+ 'output_file': output_info,
183
+ 'temp_dir': str(temp_path)
184
+ }
185
+
186
+ except Exception as container_error:
187
+ return {
188
+ 'success': False,
189
+ 'error': f"Container execution failed: {str(container_error)}",
190
+ 'command': final_command,
191
+ 'execution_time': time.time() - start_time
192
+ }
193
+
194
+ except Exception as e:
195
+ return {
196
+ 'success': False,
197
+ 'error': f"Media processing setup failed: {str(e)}",
198
+ 'command': ffmpeg_command
199
+ }
200
+
201
+ def get_media_info(self, file_path: str) -> Dict[str, Any]:
202
+ """Get media file information using ffprobe"""
203
+
204
+ if not Path(file_path).exists():
205
+ return {
206
+ 'success': False,
207
+ 'error': f'File not found: {file_path}'
208
+ }
209
+
210
+ # Use ffprobe to get media information
211
+ ffprobe_command = (
212
+ f"ffprobe -v quiet -print_format json -show_format -show_streams "
213
+ f"${{input_file}}"
214
+ )
215
+
216
+ result = self.execute_ffmpeg_command(
217
+ ffmpeg_command=ffprobe_command,
218
+ input_files={'input_file': file_path}
219
+ )
220
+
221
+ if result['success']:
222
+ try:
223
+ # Parse JSON output from ffprobe
224
+ media_info = json.loads(result['output'].split('\n')[-2]) # Get JSON from output
225
+ return {
226
+ 'success': True,
227
+ 'media_info': media_info,
228
+ 'file_path': file_path
229
+ }
230
+ except:
231
+ return {
232
+ 'success': True,
233
+ 'raw_output': result['output'],
234
+ 'file_path': file_path
235
+ }
236
+
237
+ return result