SullyTavern Auto Resend on Empty AI

Automatically clicks the send button in Sully Tavern when "Google AI Studio Candidate text empty" error occurs.

  1. // ==UserScript==
  2. // @name SullyTavern Auto Resend on Empty AI
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.0
  5. // @description Automatically clicks the send button in Sully Tavern when "Google AI Studio Candidate text empty" error occurs.
  6. // @author Your Helper
  7. // @match http://127.0.0.1:8000/*
  8. // @match http://localhost:8000/*
  9. // @match http://127.0.0.1:8000
  10. // @match http://localhost:8000
  11. // @grant none
  12. // @run-at document-start
  13. // ==/UserScript==
  14.  
  15. (function() {
  16. 'use strict';
  17.  
  18. const TARGET_ERROR_SUBSTRING = "Google AI Studio Candidate text empty";
  19. const BUTTON_ID = "send_but";
  20. const SCRIPT_PREFIX = "[SullyTavern AutoResend] ";
  21.  
  22. let errorHandlingInitialized = false;
  23.  
  24. function handleError(errorSource, errorDetails) {
  25. let errorMessage = "";
  26.  
  27. if (typeof errorDetails === 'string') {
  28. errorMessage = errorDetails;
  29. } else if (errorDetails instanceof Error) {
  30. errorMessage = errorDetails.message || "";
  31. } else if (errorDetails && typeof errorDetails.reason !== 'undefined') { // For unhandledrejection event
  32. if (errorDetails.reason instanceof Error) {
  33. errorMessage = errorDetails.reason.message || "";
  34. } else if (typeof errorDetails.reason === 'string') {
  35. errorMessage = errorDetails.reason;
  36. }
  37. }
  38.  
  39. if (typeof errorMessage === 'string' && errorMessage.includes(TARGET_ERROR_SUBSTRING)) {
  40. console.log(SCRIPT_PREFIX + `Target error detected via ${errorSource}: "${errorMessage}". Clicking send button.`);
  41. clickSendButton();
  42. }
  43. }
  44.  
  45. function initializeErrorHandlers() {
  46. if (errorHandlingInitialized) {
  47. return;
  48. }
  49.  
  50. // 1. Hook console.error (as a fallback, unhandledrejection is primary for this error)
  51. if (typeof console !== 'undefined' && typeof console.error !== 'undefined') {
  52. const originalConsoleError = console.error;
  53. console.error = function(...args) {
  54. originalConsoleError.apply(console, args);
  55. if (args.length > 0) {
  56. handleError("console.error", args[0]);
  57. }
  58. };
  59. }
  60.  
  61. // 2. Hook unhandled promise rejections (primary method for this error)
  62. if (typeof window !== 'undefined') {
  63. window.addEventListener('unhandledrejection', function(event) {
  64. // We don't need to log the full event object in the final version
  65. // console.log(SCRIPT_PREFIX + "Unhandled rejection EVENT caught.");
  66. handleError("unhandledrejection", event);
  67. });
  68. }
  69. errorHandlingInitialized = true;
  70. console.log(SCRIPT_PREFIX + "Script loaded and error listeners active.");
  71. }
  72.  
  73. function clickSendButton() {
  74. setTimeout(() => {
  75. const sendButton = document.getElementById(BUTTON_ID);
  76. if (sendButton) {
  77. if (sendButton.offsetParent !== null && !sendButton.disabled) {
  78. sendButton.click();
  79. // console.log(SCRIPT_PREFIX + "Send button clicked."); // Можно раскомментировать, если хотите видеть подтверждение клика
  80. } else {
  81. console.warn(SCRIPT_PREFIX + `Send button found but is not clickable (Visible: ${sendButton.offsetParent !== null}, Disabled: ${sendButton.disabled}).`);
  82. }
  83. } else {
  84. console.warn(SCRIPT_PREFIX + `Send button with ID "${BUTTON_ID}" NOT FOUND.`);
  85. }
  86. }, 100); // 100 мс задержка
  87. }
  88.  
  89. // Initialize handlers
  90. if (document.readyState === 'loading') {
  91. document.addEventListener('DOMContentLoaded', initializeErrorHandlers);
  92. } else {
  93. initializeErrorHandlers();
  94. }
  95. window.addEventListener('load', () => {
  96. if (!errorHandlingInitialized) {
  97. initializeErrorHandlers();
  98. }
  99. });
  100.  
  101. })();

QingJ © 2025

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