Skip to content

Commit e19b890

Browse files
authored
Merge pull request #1282 from glass-city/export-conversation-to-markdown
Export conversation to markdown
2 parents 65ce8f9 + 16e7ea2 commit e19b890

File tree

4 files changed

+59
-1
lines changed

4 files changed

+59
-1
lines changed

docs/guides/advanced-terminal-usage.mdx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ Magic commands can be used to control the interpreter's behavior in interactive
1313
- `%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 calculate the tokens used by that prompt and the total amount of tokens that will be sent with the next request.
1414
- `%info`: Show system and interpreter information.
1515
- `%help`: Show this help message.
16-
- `%jupyter`: Export the current session to a Jupyter notebook file (.ipynb) to the Downloads folder.
16+
- `%jupyter`: Export the current session to a Jupyter notebook file (.ipynb) to the Downloads folder.
17+
- `%markdown [path]`: Export the conversation to a specified Markdown path. If no path is provided, it will be saved to the Downloads folder with a generated conversation name.

docs/usage/terminal/magic-commands.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ Magic commands can be used to control the interpreter's behavior in interactive
1313
- `%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 calculate the tokens used by that prompt and the total amount of tokens that will be sent with the next request.
1414
- `%info`: Show system and interpreter information.
1515
- `%help`: Show this help message.
16+
- `%markdown [path]`: Export the conversation to a specified Markdown path. If no path is provided, it will be saved to the Downloads folder with a generated conversation name.

interpreter/terminal_interface/magic_commands.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from ..core.utils.system_debug_info import system_info
99
from .utils.count_tokens import count_messages_tokens
1010
from .utils.display_markdown_message import display_markdown_message
11+
from .utils.export_to_markdown import export_to_markdown
1112

1213

1314
def handle_undo(self, arguments):
@@ -58,6 +59,7 @@ def handle_help(self, arguments):
5859
"%help": "Show this help message.",
5960
"%info": "Show system and interpreter information",
6061
"%jupyter": "Export the conversation to a Jupyter notebook file",
62+
"%markdown [path]": "Export the conversation to a specified Markdown path. If no path is provided, it will be saved to the Downloads folder with a generated conversation name.",
6163
}
6264

6365
base_message = ["> **Available Commands:**\n\n"]
@@ -220,6 +222,9 @@ def get_downloads_path():
220222
else:
221223
# For MacOS and Linux
222224
downloads = os.path.join(os.path.expanduser("~"), "Downloads")
225+
# For some GNU/Linux distros, there's no '~/Downloads' dir by default
226+
if not os.path.exists(downloads):
227+
os.makedirs(downloads)
223228
return downloads
224229

225230

@@ -295,6 +300,19 @@ def jupyter(self, arguments):
295300
)
296301

297302

303+
def markdown(self, export_path: str):
304+
# If it's an empty conversations
305+
if len(self.messages) == 0:
306+
print("No messages to export.")
307+
return
308+
309+
# If user doesn't specify the export path, then save the exported PDF in '~/Downloads'
310+
if not export_path:
311+
export_path = get_downloads_path() + f"/{self.conversation_filename[:-4]}md"
312+
313+
export_to_markdown(self.messages, export_path)
314+
315+
298316
def handle_magic_command(self, user_input):
299317
# Handle shell
300318
if user_input.startswith("%%"):
@@ -316,6 +334,7 @@ def handle_magic_command(self, user_input):
316334
"tokens": handle_count_tokens,
317335
"info": handle_info,
318336
"jupyter": jupyter,
337+
"markdown": markdown,
319338
}
320339

321340
user_input = user_input[1:].strip() # Capture the part after the `%`
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
def export_to_markdown(messages: list[dict], export_path: str):
2+
markdown = messages_to_markdown(messages)
3+
with open(export_path, 'w') as f:
4+
f.write(markdown)
5+
print(f"Exported current conversation to {export_path}")
6+
7+
8+
def messages_to_markdown(messages: list[dict]) -> str:
9+
# Convert interpreter.messages to Markdown text
10+
markdown_content = ""
11+
previous_role = None
12+
for chunk in messages:
13+
current_role = chunk["role"]
14+
if current_role == previous_role:
15+
rendered_chunk = ""
16+
else:
17+
rendered_chunk = f"## {current_role}\n\n"
18+
previous_role = current_role
19+
20+
# User query message
21+
if chunk["role"] == "user":
22+
rendered_chunk += chunk["content"] + "\n\n"
23+
markdown_content += rendered_chunk
24+
continue
25+
26+
# Message
27+
if chunk["type"] == "message":
28+
rendered_chunk += chunk["content"] + "\n\n"
29+
30+
# Code
31+
if chunk["type"] == "code" or chunk["type"] == "console":
32+
code_format = chunk.get("format", "")
33+
rendered_chunk += f"```{code_format}\n{chunk['content']}\n```\n\n"
34+
35+
markdown_content += rendered_chunk
36+
37+
return markdown_content

0 commit comments

Comments
 (0)