jupyter-agent-2 / app.py
lvwerra's picture
lvwerra HF Staff
fix system prompt
ed7f73f
import os
import gradio as gr
from gradio.utils import get_space
from huggingface_hub import InferenceClient
from e2b_code_interpreter import Sandbox
from pathlib import Path
from transformers import AutoTokenizer
import json
from openai import OpenAI
from huggingface_hub import HfApi, HfFolder
from jupyter_handler import JupyterNotebook
if not get_space():
try:
from dotenv import load_dotenv
load_dotenv()
except (ImportError, ModuleNotFoundError):
pass
from utils import (
run_interactive_notebook,
)
E2B_API_KEY = os.environ["E2B_API_KEY"]
HF_TOKEN = os.environ["HF_TOKEN"] #HfFolder.get_token() #
DEFAULT_MAX_TOKENS = 512
SANDBOXES = {}
SANDBOX_TIMEOUT = 300
TMP_DIR = './tmp/'
model="Qwen/Qwen3-Coder-480B-A35B-Instruct:cerebras"
init_notebook = JupyterNotebook()
if not os.path.exists(TMP_DIR):
os.makedirs(TMP_DIR)
with open(TMP_DIR+"jupyter-agent.ipynb", 'w', encoding='utf-8') as f:
json.dump(JupyterNotebook().data, f, indent=2)
with open("ds-system-prompt.txt", "r") as f:
DEFAULT_SYSTEM_PROMPT = f.read()
DEFAULT_SYSTEM_PROMPT = """You are a coding agent with access to a Jupyter Kernel. \
When possible break down tasks step-by-step. \
The following files are available (if any):
{}
List of available packages:
# Jupyter server requirements
jupyter-server==2.16.0
ipykernel==6.29.5
ipython==9.2.0
orjson==3.10.18
pandas==2.2.3
matplotlib==3.10.3
pillow==11.3.0
# Latest version for
e2b_charts
# Other packages
aiohttp==3.12.14
beautifulsoup4==4.13.4
bokeh==3.7.3
gensim==4.3.3 # unmaintained, blocking numpy and scipy bump
imageio==2.37.0
joblib==1.5.0
librosa==0.11.0
nltk==3.9.1
numpy==1.26.4 # bump blocked by gensim
numba==0.61.2
opencv-python==4.11.0.86
openpyxl==3.1.5
plotly==6.0.1
kaleido==1.0.0
pytest==8.3.5
python-docx==1.1.2
pytz==2025.2
requests==2.32.4
scikit-image==0.25.2
scikit-learn==1.6.1
scipy==1.13.1 # bump blocked by gensim
seaborn==0.13.2
soundfile==0.13.1
spacy==3.8.2 # doesn't work on 3.13.x
textblob==0.19.0
tornado==6.5.1
urllib3==2.5.0
xarray==2025.4.0
xlrd==2.0.1
sympy==1.14.0
If you need to install additional packages:
1. install uv first with `pip install uv`
2. then use uv to install the package with `uv pip install PACKAGE_NAME --system`.
"""
def execute_jupyter_agent(
user_input, files, message_history, request: gr.Request
):
if request.session_hash not in SANDBOXES:
SANDBOXES[request.session_hash] = Sandbox(api_key=E2B_API_KEY, timeout=SANDBOX_TIMEOUT)
sbx = SANDBOXES[request.session_hash]
save_dir = os.path.join(TMP_DIR, request.session_hash)
os.makedirs(save_dir, exist_ok=True)
save_dir = os.path.join(save_dir, 'jupyter-agent.ipynb')
with open(save_dir, 'w', encoding='utf-8') as f:
json.dump(init_notebook.data, f, indent=2)
yield init_notebook.render(), message_history, save_dir
client = OpenAI(
base_url="https://router.huggingface.co/v1",
api_key=HF_TOKEN,
)
filenames = []
if files is not None:
for filepath in files:
filpath = Path(filepath)
with open(filepath, "rb") as file:
print(f"uploading {filepath}...")
sbx.files.write(filpath.name, file)
filenames.append(filpath.name)
sytem_prompt = DEFAULT_SYSTEM_PROMPT
# Initialize message_history if it doesn't exist
if len(message_history) == 0:
if files is None:
sytem_prompt = sytem_prompt.format("- None")
else:
sytem_prompt = sytem_prompt.format("- " + "\n- ".join(filenames))
message_history.append(
{
"role": "system",
"content": sytem_prompt,
}
)
message_history.append({"role": "user", "content": user_input})
#print("history:", message_history)
for notebook_html, notebook_data, messages in run_interactive_notebook(
client, model, message_history, sbx,
):
message_history = messages
yield notebook_html, message_history, TMP_DIR+"jupyter-agent.ipynb"
with open(save_dir, 'w', encoding='utf-8') as f:
json.dump(notebook_data, f, indent=2)
yield notebook_html, message_history, save_dir
def clear(msg_state, request: gr.Request):
if request.session_hash in SANDBOXES:
SANDBOXES[request.session_hash].kill()
SANDBOXES.pop(request.session_hash)
msg_state = []
return init_notebook.render(), msg_state
css = """
#component-0 {
height: 100vh;
overflow-y: auto;
padding: 20px;
}
.gradio-container {
height: 100vh !important;
}
.contain {
height: 100vh !important;
}
"""
# Create the interface
with gr.Blocks() as demo:
msg_state = gr.State(value=[])
html_output = gr.HTML(value=JupyterNotebook().render())
user_input = gr.Textbox(
#value="Write code to multiply three numbers: 10048, 32, 19", lines=3, label="User input"
value="Solve the Lotka-Volterra equation and plot the results. Do it step by step and explain what you are doing and in the end make a super nice and clean plot.", label="Agent task"
)
with gr.Row():
generate_btn = gr.Button("Run!")
clear_btn = gr.Button("Clear Notebook")
with gr.Accordion("Upload files ⬆ | Download notebook⬇", open=False):
files = gr.File(label="Upload files to use", file_count="multiple")
file = gr.File(TMP_DIR+"jupyter-agent.ipynb", label="Download Jupyter Notebook")
powered_html = gr.HTML("""\
<p align="center">
<img style="max-height:100px; max-width:100%; height:auto;"src="https://huggingface.co/spaces/lvwerra/jupyter-agent-2/resolve/main/powered-by.png" alt="Powered by" />
</p>""")
generate_btn.click(
fn=execute_jupyter_agent,
inputs=[user_input, files, msg_state],
outputs=[html_output, msg_state, file],
show_progress="hidden",
)
clear_btn.click(fn=clear, inputs=[msg_state], outputs=[html_output, msg_state])
demo.load(
fn=None,
inputs=None,
outputs=None,
js=""" () => {
if (document.querySelectorAll('.dark').length) {
document.querySelectorAll('.dark').forEach(el => el.classList.remove('dark'));
}
}
"""
)
demo.launch(ssr_mode=False)