Skip to content

Instantly share code, notes, and snippets.

@moyix
Created November 15, 2023 23:18
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save moyix/fbed043f2609aa8f27f442a6d04291d8 to your computer and use it in GitHub Desktop.
Save moyix/fbed043f2609aa8f27f442a6d04291d8 to your computer and use it in GitHub Desktop.
Render LM-Studio Chat as HTML
import json
import argparse
import html
import os
from datetime import datetime
def generate_html(json_file, html_file="chat.html", metadata=None, date=None):
with open(json_file, 'r') as file:
data = json.load(file)
html_content = ""
html_content += '<!DOCTYPE html>'
html_content += '<html><head><link rel="stylesheet" href="style.css">'
html_content += f'<title>LM-Studio Chat with {metadata["lastUsedModel"]["title"]}</title>'
html_content += '<script src="https://cdnjs.cloudflare.com/ajax/libs/markdown-it/13.0.2/markdown-it.min.js" integrity="sha512-ohlWmsCxOu0bph1om5eDL0jm/83eH09fvqLDhiEdiqfDeJbEvz4FSbeY0gLJSVJwQAp0laRhTXbUQG+ZUuifUQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>'
html_content += '<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css">'
html_content += '<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>'
html_content += '</head><body>'
# Header with the model name and date
html_content += '<div class="header">'
html_content += '<h1>LM-Studio Chat</h1>'
html_content += f'<p><strong>Model</strong>: {metadata["lastUsedModel"]["title"]}</p>'
html_content += f'<p><strong>Date</strong>: {date.strftime("%B %d, %Y %H:%M:%S %p")}</p>'
html_content += '</div>'
# Chat messages
html_content += '<div class="chat">'
for message in data['messages']:
role_class = "user" if message['role'] == "user" else "assistant"
html_content += f'<h3 class="{role_class}">{message["role"].title()}</h3>'
html_content += f'<div class="{role_class}"><div class="content">{html.escape(message["content"])}</div></div>'
html_content += '</div>'
html_content += """
<script>
document.addEventListener('DOMContentLoaded', (event) => {
const md = new markdownit();
document.querySelectorAll(".content").forEach(block => {
block.innerHTML = md.render(block.textContent);
});
document.querySelectorAll("pre code").forEach(block => {
hljs.highlightElement(block);
});
});
</script>
"""
html_content += '</body></html>'
with open(html_file, "w") as output_file:
output_file.write(html_content)
def main():
parser = argparse.ArgumentParser(description='Generate HTML file from JSON file')
parser.add_argument('json_file', metavar='json_file', type=str, help='JSON file')
parser.add_argument('-O', '--output', metavar='output_file', type=str, help='output HTML file', default="chat.html")
args = parser.parse_args()
# Load the metadata file given the chat file
# If args.file is '/Users/moyix/.cache/lm-studio/chats/1700066024624.chat.json'
# metadata will be in '/Users/moyix/.cache/lm-studio/chats/1700066024624.metadata.chat.json'
metadata_file = args.json_file.replace(".chat.json", ".metadata.chat.json")
metadata = json.load(open(metadata_file, 'r'))
# Get the timestamp from the filename; it's in milliseconds since epoch
timestamp = int(os.path.basename(args.json_file).split(".")[0])
date = datetime.fromtimestamp(timestamp / 1000.0)
generate_html(args.json_file, args.output, metadata, date)
if __name__ == "__main__":
main()
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
}
.chat, .header {
max-width: 600px;
margin: 20px auto;
border: 1px solid #ddd;
padding: 10px;
background: white;
}
.user, .assistant {
margin-bottom: 10px;
}
.user {
text-align: left;
}
.assistant {
text-align: left;
}
.content {
padding: 5px 10px;
border-radius: 5px;
background: #eee;
}
pre code {
background-color: #f4f4f4;
border: 1px solid #ccc;
display: block;
padding: 10px;
overflow-x: auto;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment