Mistral AI - Delete All Chats

Adds a native-looking "Delete All Chats" button to Mistral AI interface with multi-language support

  1. // ==UserScript==
  2. // @name Mistral AI - Delete All Chats
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.03
  5. // @description Adds a native-looking "Delete All Chats" button to Mistral AI interface with multi-language support
  6. // @author Ognisty321
  7. // @match https://chat.mistral.ai/*
  8. // @license MIT
  9. // @grant none
  10. // @run-at document-end
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15.  
  16. const translations = {
  17. en: {
  18. deleteAllChats: "Delete All Chats",
  19. confirmDeleteAll: "Are you sure you want to delete ALL chats? This action cannot be undone!",
  20. modalTitle: "Deleting Chats",
  21. modalClose: "Close",
  22. startingDeletion: "Starting deletion process...",
  23. fetchingChats: "Fetching chats...",
  24. foundChats: "Found {0} chats to delete.",
  25. noMoreChats: "No more chats to delete!",
  26. deletionComplete: "✅ Deletion complete! Successfully deleted {0} chats in total.",
  27. startingBatch: "Starting batch #{0}...",
  28. completedBatch: "Completed batch #{0}: Deleted {1} chats",
  29. deletedChat: "Deleted chat: {0} ({1}...)",
  30. failedChat: "Failed to delete chat {0}: {1}",
  31. errorFetchingChats: "Error fetching chats: {0}",
  32. buttonAdded: "\"Delete All Chats\" button added successfully",
  33. confirmButtonLog: "Attempting to add native delete button..."
  34. },
  35. fr: {
  36. deleteAllChats: "Supprimer tous les chats",
  37. confirmDeleteAll: "Êtes-vous sûr de vouloir supprimer TOUS les chats ? Cette action est irréversible !",
  38. modalTitle: "Suppression des chats",
  39. modalClose: "Fermer",
  40. startingDeletion: "Début du processus de suppression...",
  41. fetchingChats: "Récupération des chats...",
  42. foundChats: "{0} chats trouvés à supprimer.",
  43. noMoreChats: "Aucun autre chat à supprimer !",
  44. deletionComplete: "✅ Suppression terminée ! {0} chats supprimés au total.",
  45. startingBatch: "Lancement du lot #{0}...",
  46. completedBatch: "Lot #{0} terminé : {1} chats supprimés",
  47. deletedChat: "Chat supprimé : {0} ({1}...)",
  48. failedChat: "Échec de la suppression du chat {0} : {1}",
  49. errorFetchingChats: "Erreur lors de la récupération des chats : {0}",
  50. buttonAdded: "Bouton « Supprimer tous les chats » ajouté avec succès",
  51. confirmButtonLog: "Tentative d’ajout du bouton natif de suppression..."
  52. },
  53. de: {
  54. deleteAllChats: "Alle Chats löschen",
  55. confirmDeleteAll: "Sind Sie sicher, dass Sie ALLE Chats löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden!",
  56. modalTitle: "Chats löschen",
  57. modalClose: "Schließen",
  58. startingDeletion: "Löschvorgang wird gestartet...",
  59. fetchingChats: "Chats werden geladen...",
  60. foundChats: "{0} Chats zum Löschen gefunden.",
  61. noMoreChats: "Keine weiteren Chats zum Löschen!",
  62. deletionComplete: "✅ Löschvorgang abgeschlossen! Insgesamt wurden {0} Chats erfolgreich gelöscht.",
  63. startingBatch: "Batch #{0} wird gestartet...",
  64. completedBatch: "Batch #{0} abgeschlossen: {1} Chats gelöscht",
  65. deletedChat: "Chat gelöscht: {0} ({1}...)",
  66. failedChat: "Chat {0} konnte nicht gelöscht werden: {1}",
  67. errorFetchingChats: "Fehler beim Laden der Chats: {0}",
  68. buttonAdded: "Button „Alle Chats löschen“ erfolgreich hinzugefügt",
  69. confirmButtonLog: "Versuche, nativen Lösch-Button hinzuzufügen..."
  70. },
  71. es: {
  72. deleteAllChats: "Eliminar todos los chats",
  73. confirmDeleteAll: "¿Seguro que quieres eliminar TODOS los chats? ¡Esta acción no se puede deshacer!",
  74. modalTitle: "Eliminando chats",
  75. modalClose: "Cerrar",
  76. startingDeletion: "Iniciando el proceso de eliminación...",
  77. fetchingChats: "Obteniendo los chats...",
  78. foundChats: "{0} chats encontrados para eliminar.",
  79. noMoreChats: "¡No quedan más chats para eliminar!",
  80. deletionComplete: "✅ ¡Eliminación completada! Se eliminaron correctamente {0} chats en total.",
  81. startingBatch: "Iniciando lote #{0}...",
  82. completedBatch: "Lote #{0} completado: {1} chats eliminados",
  83. deletedChat: "Chat eliminado: {0} ({1}...)",
  84. failedChat: "No se pudo eliminar el chat {0}: {1}",
  85. errorFetchingChats: "Error al obtener los chats: {0}",
  86. buttonAdded: "Botón «Eliminar todos los chats» agregado correctamente",
  87. confirmButtonLog: "Intentando añadir botón nativo de eliminación..."
  88. },
  89. pl: {
  90. deleteAllChats: "Usuń wszystkie czaty",
  91. confirmDeleteAll: "Czy na pewno chcesz usunąć WSZYSTKIE czaty? Tej operacji nie można cofnąć!",
  92. modalTitle: "Usuwanie czatów",
  93. modalClose: "Zamknij",
  94. startingDeletion: "Rozpoczynanie procesu usuwania...",
  95. fetchingChats: "Pobieranie czatów...",
  96. foundChats: "Znaleziono {0} czatów do usunięcia.",
  97. noMoreChats: "Brak kolejnych czatów do usunięcia!",
  98. deletionComplete: "✅ Usuwanie zakończone! Łącznie usunięto {0} czatów.",
  99. startingBatch: "Rozpoczynanie partii nr {0}...",
  100. completedBatch: "Zakończono partię nr {0}: usunięto {1} czatów",
  101. deletedChat: "Usunięto czat: {0} ({1}...)",
  102. failedChat: "Nie udało się usunąć czatu {0}: {1}",
  103. errorFetchingChats: "Błąd podczas pobierania czatów: {0}",
  104. buttonAdded: "Przycisk „Usuń wszystkie czaty” został dodany pomyślnie",
  105. confirmButtonLog: "Próba dodania natywnego przycisku usuwania..."
  106. },
  107. it: {
  108. deleteAllChats: "Elimina tutte le chat",
  109. confirmDeleteAll: "Sei sicuro di voler eliminare TUTTE le chat? Questa azione non può essere annullata!",
  110. modalTitle: "Eliminazione chat",
  111. modalClose: "Chiudi",
  112. startingDeletion: "Avvio del processo di eliminazione...",
  113. fetchingChats: "Recupero delle chat...",
  114. foundChats: "Trovate {0} chat da eliminare.",
  115. noMoreChats: "Non ci sono più chat da eliminare!",
  116. deletionComplete: "✅ Eliminazione completata! {0} chat eliminate con successo.",
  117. startingBatch: "Avvio batch #{0}...",
  118. completedBatch: "Batch #{0} completato: {1} chat eliminate",
  119. deletedChat: "Chat eliminata: {0} ({1}...)",
  120. failedChat: "Impossibile eliminare la chat {0}: {1}",
  121. errorFetchingChats: "Errore nel recupero delle chat: {0}",
  122. buttonAdded: "Pulsante «Elimina tutte le chat» aggiunto con successo",
  123. confirmButtonLog: "Tentativo di aggiungere il pulsante nativo di eliminazione..."
  124. },
  125. pt: {
  126. deleteAllChats: "Excluir todas as conversas",
  127. confirmDeleteAll: "Tem certeza de que deseja excluir TODAS as conversas? Esta ação não pode ser desfeita!",
  128. modalTitle: "Excluindo conversas",
  129. modalClose: "Fechar",
  130. startingDeletion: "Iniciando o processo de exclusão...",
  131. fetchingChats: "Obtendo conversas...",
  132. foundChats: "{0} conversas encontradas para exclusão.",
  133. noMoreChats: "Não há mais conversas para excluir!",
  134. deletionComplete: "✅ Exclusão concluída! {0} conversas excluídas com sucesso.",
  135. startingBatch: "Iniciando lote #{0}...",
  136. completedBatch: "Lote #{0} concluído: {1} conversas excluídas",
  137. deletedChat: "Conversa excluída: {0} ({1}...)",
  138. failedChat: "Falha ao excluir a conversa {0}: {1}",
  139. errorFetchingChats: "Erro ao obter conversas: {0}",
  140. buttonAdded: "Botão «Excluir todas as conversas» adicionado com sucesso",
  141. confirmButtonLog: "Tentando adicionar botão nativo de exclusão..."
  142. },
  143. ar: {
  144. deleteAllChats: "حذف كل المحادثات",
  145. confirmDeleteAll: "هل أنت متأكد أنك تريد حذف كل المحادثات؟ لا يمكن التراجع عن هذا الإجراء!",
  146. modalTitle: "جارٍ حذف المحادثات",
  147. modalClose: "إغلاق",
  148. startingDeletion: "بدء عملية الحذف...",
  149. fetchingChats: "جارٍ جلب المحادثات...",
  150. foundChats: "تم العثور على {0} محادثة للحذف.",
  151. noMoreChats: "لا توجد محادثات أخرى للحذف!",
  152. deletionComplete: "✅ اكتملت عملية الحذف! تم حذف {0} محادثة بنجاح.",
  153. startingBatch: "بدء الدفعة رقم {0}...",
  154. completedBatch: "اكتملت الدفعة رقم {0}: تم حذف {1} محادثة",
  155. deletedChat: "تم حذف المحادثة: {0} ({1}...)",
  156. failedChat: "فشل حذف المحادثة {0}: {1}",
  157. errorFetchingChats: "حدث خطأ أثناء جلب المحادثات: {0}",
  158. buttonAdded: "تمت إضافة زر «حذف كل المحادثات» بنجاح",
  159. confirmButtonLog: "جارٍ محاولة إضافة زر الحذف الأصلي..."
  160. }
  161. };
  162.  
  163. function formatString(template, ...args) {
  164. return template.replace(/\{(\d+)\}/g, (match, index) => {
  165. return typeof args[index] !== 'undefined' ? args[index] : match;
  166. });
  167. }
  168.  
  169. // Function to get cookie value by name
  170. function getCookie(name) {
  171. const value = `; ${document.cookie}`;
  172. const parts = value.split(`; ${name}=`);
  173. if (parts.length === 2) return parts.pop().split(';').shift();
  174. return undefined;
  175. }
  176.  
  177. // Get language from cookie first, then fall back to browser language if no cookie found
  178. const cookieLang = getCookie('lang');
  179. const userLang = (cookieLang || navigator.language || navigator.userLanguage || 'en').slice(0, 2);
  180. const i18n = translations[userLang] || translations.en;
  181.  
  182. function addNativeDeleteButton() {
  183. console.log(i18n.confirmButtonLog);
  184. const sidebarMenu = document.querySelector('ul[data-sidebar="menu"]');
  185. if (!sidebarMenu) {
  186. console.log('Sidebar menu not found, retrying in 1 second...');
  187. setTimeout(addNativeDeleteButton, 1000);
  188. return;
  189. }
  190. if (document.getElementById('delete-all-chats-button')) {
  191. console.log('Delete button already exists');
  192. return;
  193. }
  194. const menuItem = document.createElement('li');
  195. menuItem.setAttribute('data-sidebar', 'menu-item');
  196. menuItem.className = 'group/menu-item relative';
  197. const button = document.createElement('button');
  198. button.id = 'delete-all-chats-button';
  199. button.setAttribute('data-sidebar', 'menu-button');
  200. button.setAttribute('data-size', 'default');
  201. button.setAttribute('data-active', 'false');
  202. button.className = 'peer/menu-button ring-default active:bg-muted active:text-default data-[active=true]:bg-muted data-[active=true]:text-default data-[state=open]:hover:bg-muted data-[state=open]:hover:text-default outline-hidden group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left transition-colors focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:font-medium [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 hover:bg-muted hover:text-default h-8 text-sm text-red-600';
  203. button.type = 'button';
  204. button.innerHTML = `
  205. <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  206. <path d="M3 6h18"></path>
  207. <path d="M8 6V4c0-1.1.9-2 2-2h4c1.1 0 2 .9 2 2v2"></path>
  208. <path d="M19 6l-1 14c-.1 1-1 2-2 2H8c-1 0-1.9-1-2-2L5 6"></path>
  209. <line x1="10" y1="11" x2="10" y2="17"></line>
  210. <line x1="14" y1="11" x2="14" y2="17"></line>
  211. </svg>
  212. <span>${i18n.deleteAllChats}</span>
  213. `;
  214. button.addEventListener('click', () => {
  215. confirmAndDeleteAllChats();
  216. });
  217. menuItem.appendChild(button);
  218. sidebarMenu.appendChild(menuItem);
  219. console.log(i18n.buttonAdded);
  220. createStatusModal();
  221. }
  222.  
  223. function createStatusModal() {
  224. if (document.getElementById('delete-status-modal')) {
  225. return;
  226. }
  227. const modal = document.createElement('div');
  228. modal.id = 'delete-status-modal';
  229. modal.style.position = 'fixed';
  230. modal.style.top = '0';
  231. modal.style.left = '0';
  232. modal.style.right = '0';
  233. modal.style.bottom = '0';
  234. modal.style.backgroundColor = 'rgba(0, 0, 0, 0.75)';
  235. modal.style.zIndex = '9999';
  236. modal.style.display = 'none';
  237. modal.style.overflow = 'auto';
  238. modal.style.alignItems = 'flex-start';
  239. modal.style.justifyContent = 'center';
  240. modal.style.paddingTop = '50px';
  241. modal.style.paddingBottom = '50px';
  242. const modalContent = document.createElement('div');
  243. modalContent.className = 'relative w-full max-w-md rounded-lg bg-gray-900 shadow-lg text-gray-100';
  244. modalContent.style.margin = '0 auto';
  245. modalContent.style.boxShadow = '0 10px 25px -5px rgba(0, 0, 0, 0.3)';
  246. modalContent.style.display = 'flex';
  247. modalContent.style.flexDirection = 'column';
  248. modalContent.style.maxHeight = '80vh';
  249. const modalHeader = document.createElement('div');
  250. modalHeader.className = 'flex items-center justify-between border-b border-gray-700 pb-3 px-4 pt-4';
  251. modalHeader.style.position = 'sticky';
  252. modalHeader.style.top = '0';
  253. modalHeader.style.backgroundColor = 'rgb(17,24,39)';
  254. modalHeader.style.zIndex = '1';
  255. modalHeader.style.borderTopLeftRadius = '0.5rem';
  256. modalHeader.style.borderTopRightRadius = '0.5rem';
  257. modalHeader.innerHTML = `
  258. <div class="flex items-center">
  259. <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#ef4444" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 8px;">
  260. <circle cx="12" cy="12" r="10"></circle>
  261. <path d="M15 9l-6 6"></path>
  262. <path d="M9 9l6 6"></path>
  263. </svg>
  264. <h3 class="text-lg font-semibold">${i18n.modalTitle}</h3>
  265. </div>
  266. <button id="close-status-modal" class="rounded-full p-1.5 hover:bg-gray-100 transition-colors">
  267. <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  268. <path d="M18 6 6 18"></path>
  269. <path d="m6 6 12 12"></path>
  270. </svg>
  271. </button>
  272. `;
  273. const statusContainer = document.createElement('div');
  274. statusContainer.id = 'delete-status';
  275. statusContainer.className = 'overflow-y-auto px-4 py-3 space-y-2.5';
  276. statusContainer.style.flex = '1';
  277. statusContainer.style.overflowY = 'auto';
  278. statusContainer.style.minHeight = '100px';
  279. statusContainer.style.maxHeight = 'calc(80vh - 120px)';
  280. const modalFooter = document.createElement('div');
  281. modalFooter.className = 'border-t border-gray-700 px-4 py-3';
  282. modalFooter.style.position = 'sticky';
  283. modalFooter.style.bottom = '0';
  284. modalFooter.style.backgroundColor = 'rgb(17,24,39)';
  285. modalFooter.style.borderBottomLeftRadius = '0.5rem';
  286. modalFooter.style.borderBottomRightRadius = '0.5rem';
  287. const closeButton = document.createElement('button');
  288. closeButton.id = 'close-status-button';
  289. closeButton.className = 'px-4 py-2 bg-gray-800 hover:bg-gray-700 rounded-md text-sm font-medium transition-colors text-gray-100';
  290. closeButton.textContent = i18n.modalClose;
  291. modalFooter.appendChild(closeButton);
  292. modalContent.appendChild(modalHeader);
  293. modalContent.appendChild(statusContainer);
  294. modalContent.appendChild(modalFooter);
  295. modal.appendChild(modalContent);
  296. document.body.appendChild(modal);
  297. document.getElementById('close-status-modal').addEventListener('click', hideModal);
  298. document.getElementById('close-status-button').addEventListener('click', hideModal);
  299. modal.addEventListener('click', (e) => {
  300. if (e.target === modal) {
  301. hideModal();
  302. }
  303. });
  304. function hideModal() {
  305. document.getElementById('delete-status-modal').style.display = 'none';
  306. document.body.style.overflow = '';
  307. }
  308. }
  309.  
  310. function addStatus(message, type = 'info') {
  311. const statusContainer = document.getElementById('delete-status');
  312. if (!statusContainer) return;
  313. const statusItem = document.createElement('div');
  314. statusItem.className = `mb-2 p-3 rounded-md text-sm border`;
  315. if (type === 'success') {
  316. statusItem.innerHTML = `<div class="flex items-center">
  317. <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-2">
  318. <path d="M20 6L9 17l-5-5"></path>
  319. </svg>
  320. ${message}
  321. </div>`;
  322. } else if (type === 'error') {
  323. statusItem.innerHTML = `<div class="flex items-center">
  324. <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#ef4444" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-2">
  325. <circle cx="12" cy="12" r="10"></circle>
  326. <line x1="12" y1="8" x2="12" y2="12"></line>
  327. <line x1="12" y1="16" x2="12.01" y2="16"></line>
  328. </svg>
  329. ${message}
  330. </div>`;
  331. } else {
  332. statusItem.innerHTML = `<div class="flex items-center">
  333. <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#3b82f6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-2">
  334. <circle cx="12" cy="12" r="10"></circle>
  335. <line x1="12" y1="16" x2="12" y2="12"></line>
  336. <line x1="12" y1="8" x2="12.01" y2="8"></line>
  337. </svg>
  338. ${message}
  339. </div>`;
  340. }
  341. statusContainer.appendChild(statusItem);
  342. statusContainer.scrollTop = statusContainer.scrollHeight;
  343. }
  344.  
  345. function showStatusModal() {
  346. const modal = document.getElementById('delete-status-modal');
  347. if (modal) {
  348. modal.style.display = 'flex';
  349. document.body.style.overflow = 'hidden';
  350. }
  351. }
  352.  
  353. function confirmAndDeleteAllChats() {
  354. if (confirm(i18n.confirmDeleteAll)) {
  355. const statusContainer = document.getElementById('delete-status');
  356. if (statusContainer) {
  357. statusContainer.innerHTML = '';
  358. }
  359. showStatusModal();
  360. addStatus(i18n.startingDeletion, 'info');
  361. deleteAllChats();
  362. }
  363. }
  364.  
  365. async function fetchChats() {
  366. try {
  367. addStatus(i18n.fetchingChats, 'info');
  368. const url = "https://chat.mistral.ai/api/trpc/chat.last";
  369. const params = {
  370. "batch": "1",
  371. "input": JSON.stringify({
  372. "0": {
  373. "json": {
  374. "chatVisibility": "private",
  375. "chatPermission": "write",
  376. "direction": "forward",
  377. "limit": 20
  378. }
  379. }
  380. })
  381. };
  382. const response = await fetch(`${url}?${new URLSearchParams(params)}`, {
  383. method: 'GET',
  384. headers: {
  385. 'accept': '*/*',
  386. 'content-type': 'application/json',
  387. 'trpc-accept': 'application/jsonl',
  388. 'x-trpc-source': 'nextjs-react'
  389. },
  390. credentials: 'include'
  391. });
  392. if (!response.ok) {
  393. throw new Error(`Failed to fetch chats: ${response.status}`);
  394. }
  395. const text = await response.text();
  396. const chatIds = [];
  397. const lines = text.trim().split('\n');
  398. for (const line of lines) {
  399. try {
  400. const data = JSON.parse(line);
  401. if (data.json && Array.isArray(data.json)) {
  402. if (data.json[2]?.[0]?.[0]?.items) {
  403. for (const chat of data.json[2][0][0].items) {
  404. if (chat.id) {
  405. chatIds.push({
  406. id: chat.id,
  407. title: chat.title || 'No title'
  408. });
  409. }
  410. }
  411. }
  412. }
  413. } catch (e) {
  414. console.error('Error parsing JSON line:', e);
  415. }
  416. }
  417. addStatus(formatString(i18n.foundChats, chatIds.length), 'info');
  418. return chatIds;
  419. } catch (error) {
  420. addStatus(formatString(i18n.errorFetchingChats, error.message), 'error');
  421. console.error('Error fetching chats:', error);
  422. return [];
  423. }
  424. }
  425.  
  426. async function deleteChat(chatId, title) {
  427. try {
  428. const url = "https://chat.mistral.ai/api/trpc/chat.delete";
  429. const params = {"batch": "1"};
  430. const payload = {"0": {"json": {"id": chatId}}};
  431. const response = await fetch(`${url}?${new URLSearchParams(params)}`, {
  432. method: 'POST',
  433. headers: {
  434. 'accept': '*/*',
  435. 'content-type': 'application/json',
  436. 'trpc-accept': 'application/jsonl',
  437. 'x-trpc-source': 'nextjs-react'
  438. },
  439. credentials: 'include',
  440. body: JSON.stringify(payload)
  441. });
  442. if (!response.ok) {
  443. throw new Error(`Failed to delete chat: ${response.status}`);
  444. }
  445. addStatus(formatString(i18n.deletedChat, title, chatId.substring(0, 8)), 'success');
  446. return true;
  447. } catch (error) {
  448. addStatus(formatString(i18n.failedChat, chatId, error.message), 'error');
  449. console.error('Error deleting chat:', error);
  450. return false;
  451. }
  452. }
  453.  
  454. async function deleteAllChats() {
  455. let batchNumber = 1;
  456. let totalDeleted = 0;
  457. while (true) {
  458. addStatus(formatString(i18n.startingBatch, batchNumber), 'info');
  459. const chats = await fetchChats();
  460. if (chats.length === 0) {
  461. addStatus(i18n.noMoreChats, 'success');
  462. break;
  463. }
  464. let batchDeleted = 0;
  465. for (const chat of chats) {
  466. await deleteChat(chat.id, chat.title);
  467. batchDeleted++;
  468. totalDeleted++;
  469. await new Promise(resolve => setTimeout(resolve, 500));
  470. }
  471. addStatus(formatString(i18n.completedBatch, batchNumber, batchDeleted), 'info');
  472. batchNumber++;
  473. await new Promise(resolve => setTimeout(resolve, 2000));
  474. }
  475. addStatus(formatString(i18n.deletionComplete, totalDeleted), 'success');
  476. }
  477.  
  478. setTimeout(addNativeDeleteButton, 2000);
  479. let lastUrl = location.href;
  480. const observer = new MutationObserver(() => {
  481. if (lastUrl !== location.href) {
  482. lastUrl = location.href;
  483. setTimeout(addNativeDeleteButton, 2000);
  484. }
  485. if (!document.getElementById('delete-all-chats-button')) {
  486. addNativeDeleteButton();
  487. }
  488. });
  489. observer.observe(document, {subtree: true, childList: true});
  490. setTimeout(addNativeDeleteButton, 5000);
  491. console.log('Mistral AI - Delete All Chats script (multi-language) loaded!');
  492. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址