Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/lint-and-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
- name: Install dependencies
run: |
pip install poetry
poetry install --with dev --extras "vllm code_execution"
poetry install --with dev --extras "vllm"

- name: Run ruff
run: |
Expand Down
11 changes: 3 additions & 8 deletions examples/code-execution/chart-generation/charts.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,16 +108,11 @@ def code_output(self, row, execution_output):
tar.extractall(path=temp_dir)

# read the chart image
# it is in workspace/chart.png for 'docker' backend and chart.png for 'multiprocessing' backend
try:
with open(os.path.join(temp_dir, "workspace/chart.png"), "rb") as f:
with open(os.path.join(temp_dir, "chart.png"), "rb") as f:
row["chart_image"] = f.read()
except Exception:
try:
with open(os.path.join(temp_dir, "chart.png"), "rb") as f:
row["chart_image"] = f.read()
except Exception:
row["chart_image"] = None
row["chart_image"] = None

return row

Expand All @@ -126,7 +121,7 @@ def code_output(self, row, execution_output):
# This section demonstrates how to use the ChartCodeExecutor

# Initialize executor with the multiprocessing backend (runs code in a separate process)
executor = ChartCodeExecutor(backend="multiprocessing") # or ray, docker (with matplotlib image)
executor = ChartCodeExecutor(backend="local") # or docker, e2b, modal, daytona

# Create a simple dataset with one example
dataset = Dataset.from_list([{"id": 1}])
Expand Down
4 changes: 2 additions & 2 deletions examples/code-execution/code-verification/code_verify.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""This example demonstrates how to use Curator's code execution functionality with Ray backend for executing code on large datasets.
"""This example demonstrates how to use Curator's code execution functionality for executing code on large datasets.

It shows how to verify code solutions against expected outputs.

Expand Down Expand Up @@ -60,7 +60,7 @@ def code_output(self, row, execution_output):


if __name__ == "__main__":
executor = TACOCodeExecutor(backend="ray") # or multiprocessing, docker, e2b
executor = TACOCodeExecutor(backend="local") # or docker, e2b, modal, daytona
dataset = load_dataset("bespokelabs/sky-t1-taco-test-rejection-sampled-shreyas")
execution_output = executor(dataset["train"].select(range(10)))

Expand Down
6 changes: 3 additions & 3 deletions examples/code-execution/math-animation/execute_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ def code_output(self, input: Dict, output) -> Dict:
with tarfile.open(fileobj=bytes_io) as tar:
tar.extractall(path=temp_dir)

# get the video file
video_file = os.path.join(temp_dir, "workspace/media/videos/temp_animation/720p30/video.mp4")
# get the video file (path relative to sandbox workspace)
video_file = os.path.join(temp_dir, "media/videos/temp_animation/720p30/video.mp4")
if os.path.exists(video_file):
# Copy the video file to the output dataset
input["video"] = open(video_file, "rb").read()
Expand Down Expand Up @@ -111,7 +111,7 @@ def execute_manim_code(dataset_name="pimpalgaonkar/manim_codes_10k", output_data
executor = ManimCodeExecutor(
backend="docker",
backend_params={
"docker_image": "manimcommunity/manim:latest",
"image": "manimcommunity/manim:latest",
},
)

Expand Down
79 changes: 22 additions & 57 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 1 addition & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,14 @@ aiofiles = ">=22.0,<26.0"
anthropic = "^0.84.0"
vertexai = "1.71.1"
vllm = { version = "^0.6.3", optional = true }
aiodocker = { version = "^0.24.0", optional = true }
ray = { version = "^2.41.0", optional = true }
e2b-code-interpreter = { version = "1.0.3", optional = true }
bespokelabs-sandbox = "0.1.1"
tinker = { version = "^0.8.0", optional = true, python = ">=3.11" }

posthog = "^3.11.0"
mistralai = "^1.5.1"

[tool.poetry.extras]
vllm = ["vllm"]
code_execution = ["ray", "aiodocker", "e2b-code-interpreter"]
finetune = ["tinker"]

[tool.poetry.group.dev.dependencies]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@
"""Factory for creating code execution backends."""

from typing import Optional

from bespokelabs.curator.code_executor.types import CodeExecutionBackendConfig

# Map old backend names to sandbox backend names
_BACKEND_ALIASES = {
"multiprocessing": "local",
}


class _CodeExecutionBackendFactory:
@classmethod
def create(cls, backend: str, backend_params: Optional[CodeExecutionBackendConfig] = None):
if backend_params is None:
backend_params = {}
"""Factory for creating code execution backends."""

if backend == "multiprocessing":
from bespokelabs.curator.code_executor.code_execution_backend.multiprocessing_backend import MultiprocessingCodeExecutionBackend
@classmethod
def create(cls, backend: str, backend_params: Optional[dict] = None):
"""Create a code execution backend.

_code_executor = MultiprocessingCodeExecutionBackend(CodeExecutionBackendConfig(**backend_params))
elif backend == "docker":
from bespokelabs.curator.code_executor.code_execution_backend.docker_backend import DockerCodeExecutionBackend
Args:
backend: Backend name (e.g. "local", "docker", "e2b", "modal", "daytona")
backend_params: Configuration parameters for the backend

_code_executor = DockerCodeExecutionBackend(CodeExecutionBackendConfig(**backend_params))
elif backend == "ray":
from bespokelabs.curator.code_executor.code_execution_backend.ray_backend import RayCodeExecutionBackend
Returns:
SandboxCodeExecutionBackend instance
"""
if backend_params is None:
backend_params = {}

_code_executor = RayCodeExecutionBackend(CodeExecutionBackendConfig(**backend_params))
elif backend == "e2b":
from bespokelabs.curator.code_executor.code_execution_backend.e2b_backend import E2BCodeExecutionBackend
backend_name = _BACKEND_ALIASES.get(backend, backend)
config = CodeExecutionBackendConfig(**backend_params)

_code_executor = E2BCodeExecutionBackend(CodeExecutionBackendConfig(**backend_params))
else:
raise ValueError(f"Unsupported backend: {backend}")
from bespokelabs.curator.code_executor.code_execution_backend.sandbox_backend import SandboxCodeExecutionBackend

return _code_executor
return SandboxCodeExecutionBackend(config, backend_name=backend_name)
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@

import asyncio
import glob
import io
import json
import os
import resource
import tarfile
import time
from abc import abstractmethod
from typing import TYPE_CHECKING, List, Optional
Expand Down Expand Up @@ -656,47 +654,3 @@ async def append_execution_response(self, data: dict, filename: str) -> None:
async with aiofiles.open(filename, "a") as f:
await f.write(json_string + "\n")
logger.debug(f"Successfully appended response to {filename}")

@classmethod
def _create_temp_file(cls, content: str, execution_directory: str) -> str:
"""Create a temporary file with the given content.

Args:
content: Content to write to temp file
execution_directory: Directory to create the temp file in

Returns:
Path to the created temp file
"""
# create execution directory if it doesn't exist
os.makedirs(execution_directory, exist_ok=True)

temp_file_path = os.path.join(execution_directory, "program.py")
with open(temp_file_path, "w", encoding="utf-8") as temp_file:
temp_file.write(content)
return temp_file_path

@classmethod
def _get_created_files(cls, program_dir: str) -> bytes:
"""Get any files created during code execution.

Args:
program_dir: Directory containing the executed program and created files

Returns:
Bytes containing a zip archive of any created files
"""
# Create a BytesIO object to store the zip data
tar_buffer = io.BytesIO()

# Create a zip archive containing all files in program_dir
with tarfile.open(fileobj=tar_buffer, mode="w") as tar:
# Add all files in program_dir to the archive
for filename in os.listdir(program_dir):
file_path = os.path.join(program_dir, filename)
if os.path.isfile(file_path):
tar.add(file_path, arcname=filename)

# Get the bytes from the buffer
tar_buffer.seek(0)
return str(tar_buffer.getvalue())
Loading
Loading