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/User Avatars/ | ||||||
| public/backgrounds/ | public/backgrounds/ | ||||||
| public/groups/ | public/groups/ | ||||||
|  | public/group chats/ | ||||||
| public/worlds/ | public/worlds/ | ||||||
| public/css/bg_load.css | public/css/bg_load.css | ||||||
| public/themes/ | public/themes/ | ||||||
|   | |||||||
| @@ -2363,6 +2363,7 @@ | |||||||
|             </div> |             </div> | ||||||
|             <div class="flex-container height100pSpaceEvenly"> |             <div class="flex-container height100pSpaceEvenly"> | ||||||
|                 <div class="renameChatButton fa-solid fa-pen"></div> |                 <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 file_name="" class="PastChat_cross fa-solid fa-circle-xmark"></div> | ||||||
|             </div> |             </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 () { |     $("#talkativeness_slider").on("input", function () { | ||||||
|         if (menu_type == "create") { |         if (menu_type == "create") { | ||||||
|             create_save_talkativeness = $("#talkativeness_slider").val(); |             create_save_talkativeness = $("#talkativeness_slider").val(); | ||||||
|   | |||||||
| @@ -2618,7 +2618,8 @@ h5 { | |||||||
|     flex: 1 |     flex: 1 | ||||||
| } | } | ||||||
|  |  | ||||||
| .renameChatButton { | .renameChatButton, | ||||||
|  | .exportChatButton { | ||||||
|     cursor: pointer; |     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) { | app.post("/exportcharacter", jsonParser, async function (request, response) { | ||||||
|     if (!request.body.format || !request.body.avatar_url) { |     if (!request.body.format || !request.body.avatar_url) { | ||||||
|         return response.sendStatus(400); |         return response.sendStatus(400); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user