chatgpt-to-markdown 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +106 -0
  2. package/cli.js +24 -0
  3. package/index.js +90 -0
  4. package/package.json +27 -0
package/README.md ADDED
@@ -0,0 +1,106 @@
1
+ # ChatGPT to Markdown
2
+
3
+ Convert ChatGPT conversation JSON files to Markdown format with ease.
4
+
5
+ [![npm version](https://badge.fury.io/js/chatgpt-to-markdown.svg)](https://badge.fury.io/js/chatgpt-to-markdown)
6
+
7
+ ## Usage
8
+
9
+ Go to [chat.openai.com](https://chat.openai.com/) > Settings > Data controls > Export data and export your data.
10
+
11
+ Unzip the file you're mailed and run:
12
+
13
+ ```bash
14
+ npx chatgpt-to-markdown path/to/your/conversations.json
15
+ ```
16
+
17
+ **NO NEED TO INSTALL** - `npx` will automatically install the package if it's not already installed.
18
+
19
+ This will generate one Markdown file for each chat same directory as the conversations JSON file. The file name will be the chat title, with invalid filename characters replaced by spaces.
20
+
21
+ ## Example
22
+
23
+ Here's an example of the Markdown output for a chat with the title `Medium-Style Table CSS`:
24
+
25
+ ````markdown
26
+ # Medium-Style Table CSS
27
+
28
+ - Created: 26/9/2023, 10:10:54 am
29
+ - Updated: 26/9/2023, 10:11:19 am
30
+
31
+ ## user
32
+
33
+ Generate CSS for a Medium-style table
34
+
35
+ ## assistant
36
+
37
+ Creating a Medium-style table requires a clean and minimalist design. Here's a simple CSS snippet to help you create a table that resembles the style seen on Medium. This code assumes that you have a basic HTML table structure in place.
38
+
39
+ ```css
40
+ /* Resetting some table styles */
41
+ table {
42
+ border-collapse: collapse;
43
+ width: 100%;
44
+ margin-bottom: 20px;
45
+ }
46
+ ...
47
+ ```
48
+ ````
49
+
50
+ ## Installation
51
+
52
+ ```bash
53
+ npm install chatgpt-to-markdown
54
+ ```
55
+
56
+ ## API
57
+
58
+ You can also use `chatgpt-to-markdown` programmatically in your JavaScript or TypeScript projects.
59
+
60
+ ```javascript
61
+ import chatgptToMarkdown from "chatgpt-to-markdown";
62
+
63
+ const json = [
64
+ // ... your ChatGPT conversation data
65
+ ];
66
+
67
+ const sourceDir = "./output";
68
+
69
+ chatgptToMarkdown(json, sourceDir);
70
+ ```
71
+
72
+ ## Options
73
+
74
+ Currently, there are no additional options. Feel free to open an issue or submit a PR if there's a feature you'd like to see added!
75
+
76
+ ## Contributing
77
+
78
+ - Create a new branch for your feature or bugfix.
79
+ - Make your changes.
80
+
81
+ # Contributing
82
+
83
+ - Fork the repository on GitHub and clone the fork to your machine.
84
+ - Run `npm install` to install dependencies
85
+ - Edit [`index.js`](index.js) or [`cli.js`](cli.js), documenting your changes
86
+ - Push your changes back to your fork on GitHub and submit a pull request to the main repository.
87
+
88
+ # Release
89
+
90
+ ```shell
91
+ npm version minor
92
+ npm publish
93
+ git push --follow-tags
94
+ ```
95
+
96
+ ## Release notes
97
+
98
+ - 1.0.0: 26 Sep 2023. Initial release
99
+
100
+ ## License
101
+
102
+ MIT
103
+
104
+ ## Support
105
+
106
+ If you encounter any problems or have suggestions, please [open an issue](https://github.com/sanand0/chatgpt-to-markdown/issues) or submit a pull request.
package/cli.js ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+ import path from "path";
3
+ import { promises as fs } from "fs";
4
+ import chatgptToMarkdown from "./index.js";
5
+
6
+ async function run() {
7
+ const filePath = process.argv[2];
8
+ if (!filePath) {
9
+ console.error("Please provide a file path as a command line argument.");
10
+ process.exit(1);
11
+ }
12
+
13
+ try {
14
+ const data = await fs.readFile(filePath, "utf8");
15
+ const json = JSON.parse(data);
16
+ const sourceDir = path.dirname(filePath);
17
+ await chatgptToMarkdown(json, sourceDir);
18
+ } catch (err) {
19
+ console.error("Error:", err.message);
20
+ process.exit(1);
21
+ }
22
+ }
23
+
24
+ run();
package/index.js ADDED
@@ -0,0 +1,90 @@
1
+ import { promises as fs } from "fs";
2
+ import path from "path";
3
+
4
+ /**
5
+ * Sanitizes a file name by replacing invalid characters with spaces.
6
+ * @param {string} title - The title to sanitize.
7
+ * @returns {string} - The sanitized title.
8
+ */
9
+ function sanitizeFileName(title) {
10
+ return title
11
+ .replace(/[<>:"\/\\|?*\n]/g, " ")
12
+ .replace(/\s+/g, " ")
13
+ .trim();
14
+ }
15
+
16
+ /**
17
+ * Wraps HTML tags in backticks.
18
+ * @param {string} text - The text to process.
19
+ * @returns {string} - The text with HTML tags wrapped in backticks.
20
+ */
21
+ function wrapHtmlTagsInBackticks(text) {
22
+ return text.replace(/<[^>]+>/g, (match) => `\`${match}\``);
23
+ }
24
+
25
+ /**
26
+ * Indents a string by 4 spaces.
27
+ * @param {string} str - The string to indent.
28
+ * @returns {string} - The indented string.
29
+ * @example
30
+ * indent("foo\nbar\nbaz");
31
+ * //=> " foo\n bar\n baz"
32
+ */
33
+ function indent(str) {
34
+ return str
35
+ .split("\n")
36
+ .map((v) => ` ${v}`)
37
+ .join("\n");
38
+ }
39
+
40
+ /**
41
+ * Converts a JSON object to markdown and saves it to a file.
42
+ * @param {Object[]} json - The JSON object to convert.
43
+ * @param {string} sourceDir - The directory to save the markdown files in.
44
+ */
45
+ async function chatgptToMarkdown(json, sourceDir) {
46
+ if (!Array.isArray(json)) {
47
+ throw new TypeError("The first argument must be an array.");
48
+ }
49
+ if (typeof sourceDir !== "string") {
50
+ throw new TypeError("The second argument must be a string.");
51
+ }
52
+
53
+ for (const conversation of json) {
54
+ const sanitizedTitle = sanitizeFileName(conversation.title);
55
+ const fileName = `${sanitizedTitle}.md`;
56
+ const filePath = path.join(sourceDir, fileName);
57
+ const title = `# ${wrapHtmlTagsInBackticks(conversation.title)}\n`;
58
+ const metadata = [
59
+ `- Created: ${new Date(conversation.create_time * 1000).toLocaleString()}\n`,
60
+ `- Updated: ${new Date(conversation.update_time * 1000).toLocaleString()}\n`,
61
+ ].join("");
62
+ const messages = Object.values(conversation.mapping)
63
+ .map((node) => {
64
+ let content = node.message?.content;
65
+ if (!content) return "";
66
+ // Format the body based on the content type
67
+ let body =
68
+ content.content_type == "text"
69
+ ? content.parts.join("\n")
70
+ : content.content_type == "code"
71
+ ? "```" + content.language.replace("unknown", "") + "\n" + content.text + "\n```"
72
+ : content.content_type == "execution_output"
73
+ ? "```\n" + content.text + "\n```"
74
+ : content;
75
+ // Ignore empty content
76
+ if (!body.trim()) return "";
77
+ // Indent user / tool messages. The sometimes contain code and whitespaces are relevant
78
+ const author = node.message.author;
79
+ if (author.role == "user") body = indent(body);
80
+ if (author.role == "tool" && !body.startsWith("```") && !body.endsWith("```")) body = indent(body);
81
+ return `## ${author.role}${author.name ? ` (${author.name})` : ""}\n\n${body}\n\n`;
82
+ })
83
+ .join("");
84
+ const markdownContent = `${title}\n${metadata}\n${messages}`;
85
+ await fs.writeFile(filePath, markdownContent, "utf8");
86
+ }
87
+ }
88
+
89
+ // Export the convertToMarkdown function as the default export
90
+ export default chatgptToMarkdown;
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "chatgpt-to-markdown",
3
+ "version": "1.0.0",
4
+ "description": "Convert ChatGPT exported conversations.json to Markdown",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "chatgpt-to-markdown": "cli.js"
9
+ },
10
+ "scripts": {
11
+ "prepublishOnly": "npx prettier --write *.js *.md package.json",
12
+ "test": "echo \"Error: no test specified\" && exit 1"
13
+ },
14
+ "keywords": [
15
+ "chatgpt",
16
+ "markdown",
17
+ "converter"
18
+ ],
19
+ "author": "S Anand <root.node@gmail.com>",
20
+ "license": "MIT",
21
+ "prettier": {
22
+ "printWidth": 120
23
+ },
24
+ "devDependencies": {
25
+ "prettier": "^3.0.3"
26
+ }
27
+ }