diff --git a/interpreter/core/core.py b/interpreter/core/core.py index 7cd0d8852a..30fef50ad1 100644 --- a/interpreter/core/core.py +++ b/interpreter/core/core.py @@ -2,8 +2,10 @@ This file defines the Interpreter class. It's the main file. `from interpreter import interpreter` will import an instance of this class. """ + import json import os +import platform import threading import time from datetime import datetime @@ -213,6 +215,62 @@ def chat(self, message=None, display=True, stream=False, blocking=True): raise + def get_default_export_dir(self): + """ + Get the default directory for exporting conversations based on the operating system. + """ + system = platform.system() + home = os.path.expanduser("~") + + if system == "Windows": + return os.path.join(home, "AppData", "Local", "OpenInterpreter", "Exports") + elif system == "Darwin": # macOS + return os.path.join( + home, + "Library", + "Application\\ Support", + "OpenInterpreter", + "Exports", + ) + else: # Linux and other Unix-like systems + return os.path.join(home, ".local", "share", "OpenInterpreter", "Exports") + + def export_to_markdown(self, filename=None): + """ + Export the conversation history to a markdown file in the default export directory. + + :param filename: The name of the file to save the conversation to. If None, a default name will be used. + """ + export_dir = self.get_default_export_dir() + os.makedirs(export_dir, exist_ok=True) + if filename is None: + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + filename = f"conversation_{timestamp}.md" + + filepath = os.path.join(export_dir, filename) + + with open(filepath, "w", encoding="utf-8") as f: + for message in self.messages: + role = message.get("role", "") + content = message.get("content", "") + + if role == "system": + continue # Skip system messages + + f.write(f"## {role.capitalize()}\n\n") + + if message.get("type") == "code": + language = message.get("format", "") + f.write(f"```{language}\n{content}\n```\n\n") + else: + f.write(f"{content}\n\n") + + if message.get("type") == "console": + output = message.get("content", "") + f.write(f"```\n{output}\n```\n\n") + + display_markdown_message(f"""Conversation exported to {filepath}""") + def _streaming_chat(self, message=None, display=True): # Sometimes a little more code -> a much better experience! # Display mode actually runs interpreter.chat(display=False, stream=True) from within the terminal_interface. diff --git a/interpreter/terminal_interface/start_terminal_interface.py b/interpreter/terminal_interface/start_terminal_interface.py index 87191f200d..316337b242 100644 --- a/interpreter/terminal_interface/start_terminal_interface.py +++ b/interpreter/terminal_interface/start_terminal_interface.py @@ -15,6 +15,9 @@ from .utils.display_markdown_message import display_markdown_message from .validate_llm_settings import validate_llm_settings +EXPORT_ARG = None # This is a global variable that we store the export argument in so that we can use it outsid eof start_terminal_interfae. +# IDK if this is the best way to do it, but it works for now. + def start_terminal_interface(interpreter): """ @@ -150,6 +153,15 @@ def start_terminal_interface(interpreter): "default": False, "attribute": {"object": interpreter, "attr_name": "disable_telemetry"}, }, + { + "name": "export", + "nickname": "e", + "help_text": "export the conversation to a markdown file. Optionally specify a filename.", + "type": str, + "nargs": "?", + "const": "default", # This allows the argument to be specified without a value + "default": None, + }, { "name": "offline", "nickname": "o", @@ -361,6 +373,15 @@ def print_help(self, *args, **kwargs): ) sys.exit(1) + # Set the export argument to the global variable + if args.export: + global EXPORT_ARG + global EXPORT_ARG + if args.export.startswith("xport="): + EXPORT_ARG = args.export[len("xport=") :] + else: + EXPORT_ARG = args.export + if args.profiles: open_storage_dir("profiles") return @@ -555,6 +576,14 @@ def main(): start_terminal_interface(interpreter) except KeyboardInterrupt: try: + if EXPORT_ARG: + if ( + EXPORT_ARG == "default" or EXPORT_ARG == "xport" + ): # for some reason the export argument is being set to "xport" when it's not set + interpreter.export_to_markdown() + else: + interpreter.export_to_markdown(EXPORT_ARG) + interpreter.computer.terminate() if not interpreter.offline and not interpreter.disable_telemetry: