mirror of
				https://github.com/SillyTavern/SillyTavern.git
				synced 2025-06-05 21:59:27 +02:00 
			
		
		
		
	Export chats as .txt files
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -4,6 +4,7 @@ public/characters/ | ||||
| public/User Avatars/ | ||||
| public/backgrounds/ | ||||
| public/groups/ | ||||
| public/group chats/ | ||||
| public/worlds/ | ||||
| public/css/bg_load.css | ||||
| public/themes/ | ||||
|   | ||||
| @@ -2363,6 +2363,7 @@ | ||||
|             </div> | ||||
|             <div class="flex-container height100pSpaceEvenly"> | ||||
|                 <div class="renameChatButton fa-solid fa-pen"></div> | ||||
|                 <div class="exportChatButton fa-solid fa-file-export"></div> | ||||
|                 <div file_name="" class="PastChat_cross fa-solid fa-circle-xmark"></div> | ||||
|             </div> | ||||
|         </div> | ||||
|   | ||||
| @@ -5795,6 +5795,43 @@ $(document).ready(function () { | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     $(document).on("click", ".exportChatButton", async function () { | ||||
|         const filenamefull = $(this).closest('.select_chat_block_wrapper').find('.select_chat_block_filename').text(); | ||||
|         const filename = filenamefull.replace('.jsonl', ''); | ||||
|         const body = { | ||||
|             is_group: !!selected_group, | ||||
|             avatar_url: characters[this_chid]?.avatar, | ||||
|             file: `${filename}.jsonl`, | ||||
|             exportfilename: `${filename}.txt`, | ||||
|         } | ||||
|         console.log(body); | ||||
|         try { | ||||
|             const response = await fetch('/exportchat', { | ||||
|                 method: 'POST', | ||||
|                 body: JSON.stringify(body), | ||||
|                 headers: getRequestHeaders(), | ||||
|             }); | ||||
|             const data = await response.json(); | ||||
|             if (!response.ok) { | ||||
|                 // display error message | ||||
|                 console.log(data.message); | ||||
|                 await delay(250); | ||||
|                 toastr.error(`Error: ${data.message}`); | ||||
|                 return; | ||||
|             } else { | ||||
|                 // success, handle response data | ||||
|                 console.log(data); | ||||
|                 await delay(250); | ||||
|                 toastr.success(data.message); | ||||
|             } | ||||
|         } catch (error) { | ||||
|             // display error message | ||||
|             console.log(`An error has occurred: ${error.message}`); | ||||
|             await delay(250); | ||||
|             toastr.error(`Error: ${error.message}`); | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     $("#talkativeness_slider").on("input", function () { | ||||
|         if (menu_type == "create") { | ||||
|             create_save_talkativeness = $("#talkativeness_slider").val(); | ||||
|   | ||||
| @@ -2618,7 +2618,8 @@ h5 { | ||||
|     flex: 1 | ||||
| } | ||||
|  | ||||
| .renameChatButton { | ||||
| .renameChatButton, | ||||
| .exportChatButton { | ||||
|     cursor: pointer; | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										57
									
								
								server.js
									
									
									
									
									
								
							
							
						
						
									
										57
									
								
								server.js
									
									
									
									
									
								
							| @@ -1593,6 +1593,63 @@ app.post("/dupecharacter", jsonParser, async function (request, response) { | ||||
|     } | ||||
| }); | ||||
|  | ||||
| app.post("/exportchat", jsonParser, async function (request, response) { | ||||
|     if (!request.body.file || (!request.body.avatar_url && request.body.is_group === false)) { | ||||
|         return response.sendStatus(400); | ||||
|     } | ||||
|     const pathToFolder = request.body.is_group | ||||
|         ? directories.groupChats | ||||
|         : path.join(directories.chats, String(request.body.avatar_url).replace('.png', '')); | ||||
|     //let charname = String(sanitize(request.body.avatar_url)).replace('.png', ''); | ||||
|     let filename = path.join(pathToFolder, request.body.file); | ||||
|     let exportfilename = path.join(pathToFolder, request.body.exportfilename) | ||||
|     if (!fs.existsSync(filename)) { | ||||
|         const errorMessage = { | ||||
|             message: `Could not find JSONL file to export. Source chat file: ${filename}. Intended destination file: ${exportfilename}.` | ||||
|         } | ||||
|         console.log(errorMessage.message); | ||||
|         return response.status(404).json(errorMessage); | ||||
|     } | ||||
|     if (fs.existsSync(exportfilename)) { | ||||
|         const errorMessage = { | ||||
|             message: `File by that name already exists. Export chat aborted.` | ||||
|         } | ||||
|         console.log(errorMessage.message); | ||||
|         return response.status(400).json(errorMessage); | ||||
|     } | ||||
|     try { | ||||
|         const readline = require('readline'); | ||||
|         const fs = require('fs'); | ||||
|         const readStream = fs.createReadStream(filename); | ||||
|         const writeStream = fs.createWriteStream(exportfilename); | ||||
|         const rl = readline.createInterface({ | ||||
|             input: readStream, | ||||
|         }); | ||||
|         rl.on('line', (line) => { | ||||
|             const data = JSON.parse(line); | ||||
|             if (data.mes) { | ||||
|                 const name = data.name; | ||||
|                 const message = data.mes.replace(/\r?\n/g, '\n'); | ||||
|                 writeStream.write(`${name}: ${message}\n\n`); | ||||
|             } | ||||
|         }); | ||||
|         rl.on('close', () => { | ||||
|             writeStream.end(); | ||||
|         }); | ||||
|         //fs.promises.copyFile(filename, exportfilename) | ||||
|         const successMessage = { | ||||
|             message: `Chat exported as ${exportfilename}` | ||||
|         } | ||||
|         console.log(`Chat exported as ${exportfilename}`); | ||||
|         return response.status(200).json(successMessage); | ||||
|     } | ||||
|     catch (err) { | ||||
|         console.log("chat export failed.") | ||||
|         console.log(err); | ||||
|         return response.sendStatus(400); | ||||
|     } | ||||
| }) | ||||
|  | ||||
| app.post("/exportcharacter", jsonParser, async function (request, response) { | ||||
|     if (!request.body.format || !request.body.avatar_url) { | ||||
|         return response.sendStatus(400); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user