Skip to content

Commit

Permalink
Code interpreter docs (#352)
Browse files Browse the repository at this point in the history
Add docs for the code interpreter SDK
  • Loading branch information
mlejva committed Apr 25, 2024
2 parents cc7d392 + b66d190 commit 981d1c9
Show file tree
Hide file tree
Showing 51 changed files with 642 additions and 2,414 deletions.
6 changes: 6 additions & 0 deletions .changeset/green-items-exercise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@e2b/python-sdk": minor
"e2b": minor
---

Remove old code interpreter, use new dedicated [Code Interpreter SDK](https://github.com/e2b-dev/code-interpreter).
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
vale-styles
.vercel
.vscode

# Logs
logs
Expand Down
144 changes: 144 additions & 0 deletions apps/docs/src/app/code-interpreter/examples/page.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# Examples

Here are some examples of how to use the E2B Code Interpreter package. If you are missing something, please let us know.

## Minimal example with the sharing context

The following example demonstrates how to create a shared context between multiple code executions. This is useful when you want to share variables between different code cells.

<CodeGroup isRunnable={false}>
```js
import { CodeInterpreter } from '@e2b/code-interpreter'

const sandbox = await CodeInterpreter.create()
await sandbox.notebook.execCell('x = 1')

const execution = await sandbox.notebook.execCell('x+=1; x')
console.log(execution.text) // outputs 2

await sandbox.close()
```
```python
from e2b_code_interpreter import CodeInterpreter

with CodeInterpreter() as sandbox:
sandbox.notebook.exec_cell("x = 1")

execution = sandbox.notebook.exec_cell("x+=1; x")
print(execution.text) # outputs 2

```
</CodeGroup>

## Get charts and any display-able data

<CodeGroup isRunnable={false}>
```js
import { CodeInterpreter } from '@e2b/code-interpreter'

const sandbox = await CodeInterpreter.create()

const code = `
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 20, 100)
y = np.sin(x)
plt.plot(x, y)
plt.show()
`;

// you can install dependencies in "jupyter notebook style"
await sandbox.notebook.execCell("!pip install matplotlib")

const execution = await sandbox.notebook.execCell(code)

// this contains the image data, you can e.g. save it to file or send to frontend
execution.results[0].png

await sandbox.close()
```
```python
import base64
import io

from matplotlib import image as mpimg, pyplot as plt

from e2b_code_interpreter import CodeInterpreter

code = """
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 20, 100)
y = np.sin(x)
plt.plot(x, y)
plt.show()
"""

with CodeInterpreter() as sandbox:
# you can install dependencies in "jupyter notebook style"
sandbox.notebook.exec_cell("!pip install matplotlib")

# plot random graph
execution = sandbox.notebook.exec_cell(code)

# there's your image
image = execution.results[0].png

# example how to show the image / prove it works
i = base64.b64decode(image)
i = io.BytesIO(i)
i = mpimg.imread(i, format='PNG')

plt.imshow(i, interpolation='nearest')
plt.show()
```
</CodeGroup>

## Streaming code output

<CodeGroup isRunnable={false}>
```js
import { CodeInterpreter } from "@e2b/code-interpreter";

code = `
import time
import pandas as pd
print("hello")
time.sleep(3)
data = pd.DataFrame(data=[[1, 2], [3, 4]], columns=["A", "B"])
display(data.head(10))
time.sleep(3)
print("world")
`

const sandbox = await CodeInterpreter.create()

await sandbox.notebook.execCell(code, {
onStdout: (out) => console.log(out),
onStderr: (outErr) => console.error(outErr),
onResult: (result) => console.log(result.text)
})
````
```python
from e2b_code_interpreter import CodeInterpreter
code = """
import time
import pandas as pd
print("hello")
time.sleep(3)
data = pd.DataFrame(data=[[1, 2], [3, 4]], columns=["A", "B"])
display(data.head(10))
time.sleep(3)
print("world")
"""
with CodeInterpreter() as sandbox:
sandbox.notebook.exec_cell(code, on_stdout=print, on_stderr=print, on_result=(lambda result: print(result.text)))
```
</ CodeGroup>
195 changes: 195 additions & 0 deletions apps/docs/src/app/code-interpreter/execution/page.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
import Link from 'next/link'

# Code Execution

You can execute code using the notebook module, using the `execCell` method. The method takes a string of code as an argument and returns an object with the results of the execution.

<CodeGroup isRunnable={false}>
```js
import { CodeInterpreter } from '@e2b/code-interpreter'

const code = 'print("Hello, World!")'

const sandbox = CodeInterpreter.create()
const execution = await sandbox.notebook.execCell(code)
```

```python
import CodeInterpreter from e2b_code_interpreter

code = "print('Hello, World!')"

sandbox = CodeInterpreter.create()
execution = sandbox.notebook.exec_cell(code)
```
</CodeGroup>

The `execCell` method also accepts following optional arguments:
- `kernel id`: The ID of the kernel to execute the code on. If not provided, the default kernel is used. See <Link href="/code-interpreter/kernels">here</Link> for more info on kernels.
- `on stdout`: A callback function to handle standard output messages from the code execution.
- `on_stderr`: A callback function to handle standard error messages from the code execution.
- `on_result`: A callback function to handle the result and display calls of the code execution.

## Streaming response

You can use the `on_*` callbacks to handle the output of the code execution as it happens. This is useful for long-running code. You can stream the output to the user as it is generated.

## Execution object

The object returned by the `exec cell` method is little bit more complex, it's based on Jupyter. Here's an detailed explanation in the [Jupyter documentation](https://jupyter-client.readthedocs.io/en/stable/messaging.html).

It contains the following fields:

- `results`: A list containing result of the cell (interactively interpreted last line) and display calls (e.g. matplotlib plots).
- `logs`: Logs printed to stdout and stderr during execution.
- `error`: An error message, if there was an error during execution of the cell. It works only for Python code, not for system (`!` e.g `!pip install e2b`) commands.

### Result object

This object can be created in two different ways:
- Evaluation of the last line: If the last line of the code is an expression, the result is the value of that expression. As you would expect in REPL environments.
- Display calls: Calls to display functions, which can be used to display rich output in the notebook. E.g. [`img.show()`](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.show.html), [`display(img)`](https://ipython.readthedocs.io/en/stable/api/generated/IPython.display.html), etc.

Represents the data to be displayed as a result of executing a cell in a Jupyter notebook.
The result is similar to the structure returned by [ipython kernel](https://ipython.readthedocs.io/en/stable/development/execution.html#execution-semantics)

The result can contain multiple types of data, such as text, images, plots, etc. Each type of data is represented
as a string, and the result can contain multiple types of data. The display calls don't have to have text representation, it's always present for the actual result,
the other representations are optional.

The result has those basic data types:

#### Text types:
- `text`: text representation of the result
- `html`: html representation of the result
- `markdown`: markdown representation of the result
- `latex`: latex representation of the result

#### Image types:
- `png`: "base64 encoded png image",
- `jpeg`: "base64 encoded jpeg image",
- `svg`": "svg image",

#### Other types:
- `json`: "json representation",
- `javascript`: "javascript representation",
- `pdf`: "base64 encoded pdf"

<Note>
If you want to integrate your own display formats or how to implement them for your classes, you can read more in [here](https://github.com/ipython/ipython/blob/main/examples/IPython%20Kernel/Custom%20Display%20Logic.ipynb)
</Note>

### Logs object

Logs printed to stdout and stderr during execution. Examples of logs are print statements, warnings, subprocess output, etc.

It contains two fields:
- `stdout`: List of strings, each string is a line printed to stdout.
- `stderr`: List of strings, each string is a line printed to stderr.

### Error object

An error message, if there was an error during execution of the cell.
<Note>
It works only for Python code, not for system (e.g. `!pip install non_existent_package`) commands. The system commands are executed in a separate process and the output is in stdout/stderr.
</Note>

It contains three fields:
- `name`: Name of the error, e.g. `NameError`, `ValueError`, etc.
- `value`: Value of the error, e.g. `name 'non_existent_variable' is not defined`, etc.
- `traceback`: Traceback of the error.


## Example how to interpret the results to LLM

Here's an example how to return the results to LLM:

<CodeGroup isRunnable={false}>
```js
const code = '<CODE GENERATED BY LLM>'
const execution = await sandbox.notebook.execCell(code)

// There was an error during execution, return the error and its traceback
if (execution.error) {
return `There was an error during execution: ${execution.error.name}: ${execution.error.value}.\n
${execution.error.traceback}`
}

// The execution has some result, summarize to LLM, what are the results
if (execution.results.length > 0) {
let message = 'These are results of the execution:\n'
let counter = 1
for (const result of execution.results) {
message += `Result ${counter++}:\n`
if (result.isMainResult) {
message += `[Main result]: ${result.text}\n`
} else {
message += `[Display data]: ${result.text}\n`
}
if (result.formats().length > 0) {
message += `It has following formats: ${result.formats()}\n`
}
}

return message
}

// There were no results, check if there was something is stdout/err
if (
execution.logs.stdout.length > 0 ||
execution.logs.stderr.length > 0
) {
let message = 'There was no result of the execution, but here are the logs:\n'
if (execution.logs.stdout.length > 0) {
message += `Stdout: ${execution.logs.stdout.join('\n')}\n`
}
if (execution.logs.stderr.length > 0) {
message += `Stderr: ${execution.logs.stderr.join('\n')}\n`
}

return message
}

return 'There was no output of the execution.'
```

```python
code = "<CODE GENERATED BY LLM>"
execution = sandbox.notebook.exec_cell(code)

# There was an error during execution, return the error and its traceback
if execution.error:
return (
f"There was an error during execution: {execution.error.name}: {execution.error.value}.\n"
f"{execution.error.traceback}"
)

# The execution has some result, summarize to LLM, what are the results
if execution.results:
message = "These are results of the execution:\n"
for i, result in enumerate(execution.results):
message += f"Result {i + 1}:\n"
if result.is_main_result:
message += f"[Main result]: {result.text}\n"
else:
message += f"[Display data]: {result.text}\n"

if result.formats():
message += f"It has also following formats: {result.formats()}\n"

return message

# There were no results, check if there was something is stdout/err
if execution.logs.stdout or execution.logs.stderr:
message = "There was no result of the execution, but here are the logs:\n"
if execution.logs.stdout:
message += "Stdout: " + "\n".join(execution.logs.stdout) + "\n"

if execution.logs.stderr:
message += "Stderr: " + "\n".join(execution.logs.stderr) + "\n"

return message

return "There was no output of the execution."
```
</CodeGroup>
27 changes: 27 additions & 0 deletions apps/docs/src/app/code-interpreter/kernels/page.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import Link from 'next/link'

# Kernels

In this section you can find information about kernels and how to use them in Code Interpreter SDK

By default the template starts with one default kernel. This kernel is used to execute code, if you don't specify `kernelID`. You can imagine kernel as a separate environment where code is executed. You can have multiple kernels running at the same time. Each kernel has its own state, so you can have multiple kernels running different code at the same time.

Kernel will be kept kept alive with the sandbox even if you disconnect.

## Creating a new kernel

To create a new kernel there's a `create kernel` method in `CodeInterpreter` class. This method takes two optional arguments:
- `cwd` - working directory for the kernel, all system commands and file operations will be executed in this directory
- `kernel name` - kernel spec name (defaults to default kernel spec for server). In our case it's `python3`. If you want to use another kernel, you have to install in the template first. In that case you probably want to use <Link href='/code-interpreter/template'>Custom Template</Link>.

## Restarting a kernel

To restart a kernel you can use `restart` method. This method takes one argument - `kernelID`, if not specifed it will restart the default kernel. This method will restart the kernel and clear its state.

## Listing kernels

To list all kernels you can use `list` method. This method returns an array of all running kernels with their IDs and kernel spec names.

## Shutting down a kernel

To shutdown a kernel you can use `shutdown` method. This method takes one argument - `kernelID`, if not specifed it will delete the default kernel. This method will delete the kernel and all its state.
Loading

0 comments on commit 981d1c9

Please sign in to comment.