diff --git a/plugins/tiddlywiki/ai-tools/modules/conversations-archive-importer.js b/plugins/tiddlywiki/ai-tools/modules/conversations-archive-importer.js new file mode 100644 index 000000000..22b2cb1bd --- /dev/null +++ b/plugins/tiddlywiki/ai-tools/modules/conversations-archive-importer.js @@ -0,0 +1,87 @@ +/*\ +title: $:/plugins/tiddlywiki/ai-tools/modules/conversations-archive-importer.js +type: application/javascript +module-type: library + +Conversations archive importer + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +function ConversationsArchiveImporter() { +} + +ConversationsArchiveImporter.prototype.import = function(widget,conversationsTitle) { + var logger = new $tw.utils.Logger("ai-tools"); + var jsonConversations = widget.wiki.getTiddlerData(conversationsTitle,[]); + var tiddlers = []; + $tw.utils.each(jsonConversations,function(jsonConversation) { + var conversationTitle = (jsonConversation.title || "Untitled") + " (" + jsonConversation.conversation_id + ")", + conversationCreated = convertDate(jsonConversation.create_time), + conversationModified = convertDate(jsonConversation.update_time); + var conversationFields = { + title: conversationTitle, + tags: $tw.utils.stringifyList(["$:/tags/AI/Conversation"]), + created: conversationCreated, + modified: conversationModified + }; + tiddlers.push(conversationFields); + var messageIndex = 1; + $tw.utils.each(jsonConversation.mapping,function(jsonMessage,messageId) { + // Skip messages where "message" is null + if(jsonMessage.message) { + var messageFields = { + title: conversationTitle + " " + (messageIndex + 1), + created: convertDate(jsonMessage.message.create_time) || conversationCreated, + modified: convertDate(jsonMessage.message.update_time) || conversationModified, + tags: $tw.utils.stringifyList([conversationTitle]), + role: jsonMessage.message.author.role, + "message-type": jsonMessage.message.content.content_type + } + switch(jsonMessage.message.content.content_type) { + case "code": + messageFields.text = jsonMessage.message.content.text; + messageFields.type = "text/plain"; + break; + case "execution_output": + messageFields.text = jsonMessage.message.content.text; + messageFields.type = "text/plain"; + break; + case "system_error": + messageFields.text = jsonMessage.message.content.text; + messageFields.type = "text/plain"; + break; + case "text": + messageFields.text = jsonMessage.message.content.parts.join(""); + messageFields.type = "text/markdown"; + break; + default: + messageFields.text = JSON.stringify(jsonMessage.message,null,4); + messageFields.type = "text/plain"; + break; + } + tiddlers.push(messageFields); + messageIndex += 1; + } + }); + }); + // Create summary tiddler + $tw.utils.each(tiddlers,function(tidder) { + + }); + // Create the tiddlers + widget.wiki.addTiddlers(tiddlers); + // widget.dispatchEvent({type: "tm-import-tiddlers", param: JSON.stringify(tiddlers)}); +}; + +function convertDate(unixTimestamp) { + return $tw.utils.stringifyDate(new Date(unixTimestamp * 1000)); +} + +exports.ConversationsArchiveImporter = ConversationsArchiveImporter; + +})(); diff --git a/plugins/tiddlywiki/ai-tools/modules/startup.js b/plugins/tiddlywiki/ai-tools/modules/startup.js new file mode 100644 index 000000000..247e06dfd --- /dev/null +++ b/plugins/tiddlywiki/ai-tools/modules/startup.js @@ -0,0 +1,30 @@ +/*\ +title: $:/plugins/tiddlywiki/ai-tools/modules/startup.js +type: application/javascript +module-type: startup + +Setup the root widget event handlers + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +// Export name and synchronous status +exports.name = "ai-tools"; +exports.platforms = ["browser"]; +exports.after = ["startup"]; +exports.synchronous = true; + +// Install the root widget event handlers +exports.startup = function() { + var ConversationsArchiveImporter = require("$:/plugins/tiddlywiki/ai-tools/modules/conversations-archive-importer.js").ConversationsArchiveImporter; + $tw.conversationsArchiveImporter = new ConversationsArchiveImporter(); + $tw.rootWidget.addEventListener("tm-import-conversations",function(event) { + $tw.conversationsArchiveImporter.import(event.widget,event.param); + }); +}; + +})(); diff --git a/plugins/tiddlywiki/ai-tools/plugin.info b/plugins/tiddlywiki/ai-tools/plugin.info index d074b2d4b..77db7165b 100644 --- a/plugins/tiddlywiki/ai-tools/plugin.info +++ b/plugins/tiddlywiki/ai-tools/plugin.info @@ -2,6 +2,6 @@ "title": "$:/plugins/tiddlywiki/ai-tools", "name": "AI Tools", "description": "AI Tools for TiddlyWiki", - "list": "readme docs settings", + "list": "readme docs tools settings", "stability": "STABILITY_1_EXPERIMENTAL" } diff --git a/plugins/tiddlywiki/ai-tools/tools.tid b/plugins/tiddlywiki/ai-tools/tools.tid new file mode 100644 index 000000000..c91a1de8f --- /dev/null +++ b/plugins/tiddlywiki/ai-tools/tools.tid @@ -0,0 +1,19 @@ +title: $:/plugins/tiddlywiki/ai-tools/tools + +! Import ~ChatGPT Export Archive + +Any tiddlers containing ~ChatGPT exported `conversation.json` files will be shown here for import. + +<$list filter="[all[tiddlers+shadows]type[application/json]sort[title]]" template="$:/plugins/tiddlywiki/ai-tools/view-templates/imported-conversations-json"/> + +! Loaded Conversations + + diff --git a/plugins/tiddlywiki/ai-tools/view-templates/imported-conversations-json.tid b/plugins/tiddlywiki/ai-tools/view-templates/imported-conversations-json.tid new file mode 100644 index 000000000..f7556c599 --- /dev/null +++ b/plugins/tiddlywiki/ai-tools/view-templates/imported-conversations-json.tid @@ -0,0 +1,45 @@ +title: $:/plugins/tiddlywiki/ai-tools/view-templates/imported-conversations-json +tags: $:/tags/ViewTemplate +list-before: $:/core/ui/ViewTemplate/body + +\whitespace trim + +\procedure importer() +

+

+ <$link> + <$text text=`$(currentTiddler)$ appears to be a ChatGPT export containing $(numberOfConversations)$ conversations`/> + +
+
+ <$button> + <$action-sendmessage $message="tm-import-conversations" $param=<>/> + {{$:/core/images/input-button}} Import + +
+

+\end importer + +<%if [type[application/json]] %> + <$let json={{{ [get[text]] }}} > + <%if [jsontype[]match[array]] %> + <$let + numberOfConversations={{{ [jsonindexes[]count[]] }}} + json={{{ [jsonextract[0]] }}} + > + <%if [jsontype[]match[object]] %> + <%if + [jsontype[title]match[string]] + :and[jsontype[create_time]match[number]] + :and[jsontype[update_time]match[number]] + :and[jsontype[mapping]match[object]] + :and[jsontype[id]match[string]] + %> + <> + <%endif%> + <%endif%> + + <%endif%> + +<%endif%> +