Skip to content

Jupyter export magic command #986

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
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
1 change: 1 addition & 0 deletions docs/guides/advanced-terminal-usage.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ Magic commands can be used to control the interpreter's behavior in interactive
- `%undo`: Remove the last message and its response
- `%save_message [path]`: Save messages to a JSON file
- `%load_message [path]`: Load messages from a JSON file
- `%jupyter`: Export the current session to a Jupyter notebook file (.ipynb) to the Downloads folder.
79 changes: 79 additions & 0 deletions interpreter/terminal_interface/magic_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
import os
import subprocess
import time
import sys

from datetime import datetime
from ..core.utils.system_debug_info import system_info
from .utils.count_tokens import count_messages_tokens
from .utils.display_markdown_message import display_markdown_message
Expand Down Expand Up @@ -55,6 +57,7 @@ def handle_help(self, arguments):
"%tokens [prompt]": "EXPERIMENTAL: Calculate the tokens used by the next request based on the current conversation's messages and estimate the cost of that request; optionally provide a prompt to also calulate the tokens used by that prompt and the total amount of tokens that will be sent with the next request",
"%help": "Show this help message.",
"%info": "Show system and interpreter information",
"%jupyter": "Export the conversation to a Jupyter notebook file",
}

base_message = ["> **Available Commands:**\n\n"]
Expand Down Expand Up @@ -172,6 +175,81 @@ def handle_count_tokens(self, prompt):

display_markdown_message("\n".join(outputs))

def get_downloads_path():
if os.name == 'nt':
# For Windows
downloads = os.path.join(os.environ['USERPROFILE'], 'Downloads')
else:
# For MacOS and Linux
downloads = os.path.join(os.path.expanduser('~'), 'Downloads')
return downloads

def install_and_import(package):
try:
module = __import__(package)
except ImportError:
try:
# Install the package silently with pip
print("")
print(f"Installing {package}...")
print("")
subprocess.check_call([sys.executable, "-m", "pip", "install", package],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
)
module = __import__(package)
except subprocess.CalledProcessError:
# If pip fails, try pip3
try:
subprocess.check_call([sys.executable, "-m", "pip3", "install", package],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
)
except subprocess.CalledProcessError:
print(f"Failed to install package {package}.")
return
finally:
globals()[package] = module
return module

def jupyter(self, arguments):
# Dynamically install nbformat if not already installed
nbformat = install_and_import('nbformat')
from nbformat.v4 import new_notebook, new_code_cell, new_markdown_cell

downloads = get_downloads_path()
current_time = datetime.now()
formatted_time = current_time.strftime("%m-%d-%y-%I%M%p")
filename = f"open-interpreter-{formatted_time}.ipynb"
notebook_path = os.path.join(downloads, filename)
nb = new_notebook()
cells = []

for msg in self.messages:
if msg['role'] == 'user' and msg['type'] == 'message':
# Prefix user messages with '>' to render them as block quotes, so they stand out
content = f"> {msg['content']}"
cells.append(new_markdown_cell(content))
elif msg['role'] == 'assistant' and msg['type'] == 'message':
cells.append(new_markdown_cell(msg['content']))
elif msg['type'] == 'code':
# Handle the language of the code cell
if 'format' in msg and msg['format']:
language = msg['format']
else:
language = 'python' # Default to Python if no format specified
code_cell = new_code_cell(msg['content'])
code_cell.metadata.update({"language": language})
cells.append(code_cell)

nb['cells'] = cells

with open(notebook_path, 'w', encoding='utf-8') as f:
nbformat.write(nb, f)

print("")
display_markdown_message(f"Jupyter notebook file exported to {os.path.abspath(notebook_path)}")


def handle_magic_command(self, user_input):
# Handle shell
Expand All @@ -191,6 +269,7 @@ def handle_magic_command(self, user_input):
"undo": handle_undo,
"tokens": handle_count_tokens,
"info": handle_info,
"jupyter": jupyter,
}

user_input = user_input[1:].strip() # Capture the part after the `%`
Expand Down