chatgpt-to-markdown 1.5.2 → 1.5.4

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.
package/README.md CHANGED
@@ -97,6 +97,8 @@ git push --follow-tags
97
97
 
98
98
  ## Release notes
99
99
 
100
+ - 1.5.4: 02 Nov 2024. Skip `user_editable_context` to avoid polluting Markdown with custom instructions
101
+ - 1.5.3: 05 Aug 2024. Show text from multimodal prompts
100
102
  - 1.5.2: 05 Aug 2024. Show tether_browsing_display summary
101
103
  - 1.5.1: 22 Mar 2024. Handle unicode filenames
102
104
  - 1.5.0: 28 Nov 2023. Handle `tether_browsing_display`, `tether_quote` and `system_error`
package/cli.js CHANGED
@@ -10,15 +10,10 @@ async function run() {
10
10
  process.exit(1);
11
11
  }
12
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
- }
13
+ const data = await fs.readFile(filePath, "utf8");
14
+ const json = JSON.parse(data);
15
+ const sourceDir = path.dirname(filePath);
16
+ await chatgptToMarkdown(json, sourceDir);
22
17
  }
23
18
 
24
19
  run();
package/index.js CHANGED
@@ -34,7 +34,7 @@ function wrapHtmlTagsInBackticks(text) {
34
34
  function indent(str) {
35
35
  return str
36
36
  .split("\n")
37
- .map((v) => ` ${v}\n`)
37
+ .map((v) => (v.trim() ? ` ${v}\n` : ""))
38
38
  .join("");
39
39
  }
40
40
 
@@ -96,9 +96,11 @@ async function chatgptToMarkdown(json, sourceDir, { dateFormat } = { dateFormat:
96
96
  case "multimodal_text":
97
97
  body = content.parts
98
98
  .map((part) =>
99
- part.content_type === "image_asset_pointer"
100
- ? `Image (${part.width}x${part.height}): ${part?.metadata?.dalle?.prompt ?? ""}\n\n`
101
- : `${part.content_type}\n\n`,
99
+ typeof part == "string"
100
+ ? `${part}\n\n`
101
+ : part.content_type === "image_asset_pointer"
102
+ ? `Image (${part.width}x${part.height}): ${part?.metadata?.dalle?.prompt ?? ""}\n\n`
103
+ : `${part.content_type}\n\n`,
102
104
  )
103
105
  .join("");
104
106
  break;
@@ -111,6 +113,11 @@ async function chatgptToMarkdown(json, sourceDir, { dateFormat } = { dateFormat:
111
113
  case "system_error":
112
114
  body = `${content.name}\n\n${content.text}\n\n`;
113
115
  break;
116
+ case "user_editable_context":
117
+ // We don't want to pollute all Markdown with custom instuctions
118
+ // in content.user_instructions. So skip it
119
+ body = "";
120
+ break;
114
121
  default:
115
122
  body = content;
116
123
  break;
package/index.test.js CHANGED
@@ -226,4 +226,138 @@ describe("chatgptToMarkdown", () => {
226
226
  const fileContent = await fs.readFile(path.join(tempDir, "Test Conversation.md"), "utf8");
227
227
  expect(fileContent).toContain('```javascript\nconsole.log("Hello, world!");\n```\n');
228
228
  });
229
+
230
+ it("should skip user_editable_context content", async () => {
231
+ const json = [
232
+ {
233
+ title: "Test Conversation",
234
+ create_time: 1630454400,
235
+ update_time: 1630458000,
236
+ mapping: {
237
+ 0: {
238
+ message: {
239
+ author: { role: "user" },
240
+ content: {
241
+ content_type: "user_editable_context",
242
+ user_profile: "test profile",
243
+ user_instructions: "test instructions",
244
+ },
245
+ },
246
+ },
247
+ },
248
+ },
249
+ ];
250
+ await chatgptToMarkdown(json, tempDir);
251
+ const fileContent = await fs.readFile(path.join(tempDir, "Test Conversation.md"), "utf8");
252
+ expect(fileContent).not.toContain("test profile");
253
+ expect(fileContent).not.toContain("test instructions");
254
+ });
255
+
256
+ it("should handle system_error content", async () => {
257
+ const json = [
258
+ {
259
+ title: "Test Conversation",
260
+ create_time: 1630454400,
261
+ update_time: 1630458000,
262
+ mapping: {
263
+ 0: {
264
+ message: {
265
+ author: { role: "system" },
266
+ content: {
267
+ content_type: "system_error",
268
+ name: "Error Name",
269
+ text: "Error details",
270
+ },
271
+ },
272
+ },
273
+ },
274
+ },
275
+ ];
276
+
277
+ await chatgptToMarkdown(json, tempDir);
278
+ const fileContent = await fs.readFile(path.join(tempDir, "Test Conversation.md"), "utf8");
279
+ expect(fileContent).toContain("Error Name\n\nError details\n\n");
280
+ });
281
+
282
+ it("should handle execution_output content", async () => {
283
+ const json = [
284
+ {
285
+ title: "Test Conversation",
286
+ create_time: 1630454400,
287
+ update_time: 1630458000,
288
+ mapping: {
289
+ 0: {
290
+ message: {
291
+ author: { role: "assistant" },
292
+ content: {
293
+ content_type: "execution_output",
294
+ text: "Program output",
295
+ },
296
+ },
297
+ },
298
+ },
299
+ },
300
+ ];
301
+
302
+ await chatgptToMarkdown(json, tempDir);
303
+ const fileContent = await fs.readFile(path.join(tempDir, "Test Conversation.md"), "utf8");
304
+ expect(fileContent).toContain("```\nProgram output\n```");
305
+ });
306
+
307
+ it("should handle code content with unknown language", async () => {
308
+ const json = [
309
+ {
310
+ title: "Test Conversation",
311
+ create_time: 1630454400,
312
+ update_time: 1630458000,
313
+ mapping: {
314
+ 0: {
315
+ message: {
316
+ author: { role: "assistant" },
317
+ content: {
318
+ content_type: "code",
319
+ language: "unknown",
320
+ text: "some code",
321
+ },
322
+ },
323
+ },
324
+ },
325
+ },
326
+ ];
327
+
328
+ await chatgptToMarkdown(json, tempDir);
329
+ const fileContent = await fs.readFile(path.join(tempDir, "Test Conversation.md"), "utf8");
330
+ expect(fileContent).toContain("```\nsome code\n```");
331
+ });
332
+
333
+ it("should handle tether_browsing_display with summary", async () => {
334
+ const json = [
335
+ {
336
+ title: "Test Conversation",
337
+ create_time: 1630454400,
338
+ update_time: 1630458000,
339
+ mapping: {
340
+ 0: {
341
+ message: {
342
+ author: { role: "tool" },
343
+ content: {
344
+ content_type: "tether_browsing_display",
345
+ summary: "Page Summary",
346
+ result: "Search Result",
347
+ },
348
+ },
349
+ },
350
+ },
351
+ },
352
+ ];
353
+
354
+ await chatgptToMarkdown(json, tempDir);
355
+ const fileContent = await fs.readFile(path.join(tempDir, "Test Conversation.md"), "utf8");
356
+ expect(fileContent).toContain("```\nPage Summary\nSearch Result\n```");
357
+ });
358
+
359
+ it("should throw TypeError for invalid arguments", async () => {
360
+ await expect(chatgptToMarkdown("not an array", tempDir)).rejects.toThrow(TypeError);
361
+ await expect(chatgptToMarkdown([], 123)).rejects.toThrow(TypeError);
362
+ });
229
363
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chatgpt-to-markdown",
3
- "version": "1.5.2",
3
+ "version": "1.5.4",
4
4
  "description": "Convert ChatGPT exported conversations.json to Markdown",
5
5
  "main": "index.js",
6
6
  "type": "module",