DeepSeek 繁忙自动重试,用DeepSeek编脚本

1. 笨AI

DeepSeek好固然好,但是他常摆出一脸臭脸,令人不爽。

你转“好久”,就告诉我这?繁忙,想了0秒?

既然可以稍后再试,为什么不能自动替我试一下呢?

2. 写脚本

2.1 决定写脚本

我决定写个 tampermonkey 脚本,见到繁忙就重新提交。

2.2 决定由AI写

为什么要我来写呢,不是有AI吗,应该AI干活啊。

2.3 与 Kimi 相看两厌

因为讨厌 DeepSeek繁忙的消息,我找到了 Kimi,和他聊了一会儿。

接下来,我希望他能自动发现这些网页元素的特征,他希望这事由我来做。如果特征要我自己去找特征,不如我自己把脚本写了呢。

2.4 决定由 DeepSeek写

还是找 DeepSeek,繁忙我就先忍着。提交了同样的要求。DeepSeek特意提醒我,别提交页面的截图,应该用F12。提交页面的过程中,范围越扩越大,我把整个div交上去了。

DeepSeek超限了。

C:\Users\young\Documents\WeChat Files\wxid_mkn03idldug522\FileStorage\Temp\2edff25bd5f2520448896241d912624.png

2.5 考虑下要求,如何精确而省力地描述

对话框c,看着它的id就像唯一的稳定的标识

要求变化不大,用按回车代替点击发送按钮。我以为这样可以少讨论一个网页元素。

繁忙a,是DeepSeek说的那段“我忙”;
要求b,是我的最后一条消息;
对话框c,是下面那个文本框,输入消息的。

2.5.1 繁忙a

我没看到示例,但是英雄所见略同,我贴了HTML代码。

后面还有很长,截图略。后来我发现这路数不好,稍后会提到。

2.5.2 jquery,以及在 console 测试

因为DeepSeek并没有加载jquery,因此jquery相关的函数都未定义。我放弃了在 console中测试,准备冒险直接在 tampermonkey 中测。如果一再错,改不出来,那就放弃。

我读 DeepSeek的消息 读得急躁,跳过了重要信息。

所以我看他还一再希望我按最初的计划测试,再次要求。

他不理我(他经常高度自信,甚至过于自信,跟传说中的雪地犬一样,认为自己更专业,按你说的做只是你刚好说得对),继续要求我测。我有次脑抽忘了不打算测,测了,居然好使了,发现他已经去除了对jquery的依赖,全用js代码写的。

2.5.3 繁忙a 和 要求b

“繁忙”字样可能出现多次,只有之后有个 New chat,之后有个文本框……的才是繁忙a。

如何描述这些,我纠结了几个来回。后来突然想到,他不是AI么,他应该挺聪明啊。

我用人类语言描述了繁忙a和要求b的特征:交替对话,deepseek的最后一条消息,以及我的最后一条消息。

在同一条消息中,我给出了“我发送的消息”的示例。

在同一条消息中,我给出了“deepseek发送的消息”的示例。

这样,tokens的数量比贴整个div(父一级的)要小很多。

2.5.4 消息发送

脚本找到了繁忙a(并且当繁忙字样不在最后一条,是历史消息时,并未误判),复制了正确的命令b文字,粘贴到了正确的对话框c里。但是,并不发送。

他问我,按钮状态是不是禁用的,这样 ,还是这样

代码里某个属性,具体地说,aria-disabled的值在按钮禁用时是什么?

于是,这样来回测了几次。

在这个具体的步骤中,我是他的眼睛和手指,他是我的大脑。

2.5.5 测试环境

你想提问时,DeepSeek繁忙;你希望他繁忙时,他不忙了。很快我就把历史上留下来的最后一条消息是“繁忙”的会话消耗光了。

我让DeepSeek自己说“繁忙”。我不知道他是真忙,还是按我要求才忙的。但是他表现出了忙的样子,很好。

2.5.6 成功了

不一刻,在某个版本(v5,不知道为什么还叫作 @version 1.4),成功了。

我此前没有提到,DeepSeek还考虑到可能频繁提交类似DoS效果/抖动,所以他要求脚本的观察时隔为2秒,提交次数上限5次。并且在开发过程中,他屡次提醒,我一直不吱声。直到最后才夸了他。他说除了2秒检测间隔,还有3秒初始延迟。

3. 体会

我全程一行代码也没写。

对我的要求如下。

(1)在浏览器里F12,会在Console里贴代码、跑、复制出错信息,用眼睛观察结果,用文字描述。

(2) 在浏览器里F12,会用 Inspector复制一段html代码。

(3) 在浏览器里F12,DeepSeek认为存在可能需要看Network,但是这次没有用到。

(4) 描述需求。

(5) 在 tampermonkey中建立新脚本,向里面贴代码。并非必要的,为了退出运行,如果会禁用tampermonkey或tampermonkey插件,更好。

4. 代码,enjoy

// ==UserScript==

// @name DeepSeek 繁忙自动重试(v5)

// @namespace http://tampermonkey.net/

// @version 1.4

// @description 修复输入框聚焦和内容保持问题

// @author You

// @match https://chat.deepseek.com/*

// @grant none

// ==/UserScript==

(function() {

'use strict';

const config = {

checkInterval: 2000,

busyText: "服务器繁忙,请稍后再试。",

inputSelector: 'textarea[placeholder="Message DeepSeek"]',

sendButtonSelector: 'div[role="button"][aria-disabled="false"].f6d670'

};

// 增强输入处理

const safeInput = (inputElement, text) => {

return new Promise(resolve => {

// 确保输入框聚焦

inputElement.focus();

inputElement.select();

// 清除现有内容

inputElement.value = '';

['input', 'change'].forEach(eventType => {

inputElement.dispatchEvent(new Event(eventType, {

bubbles: true,

cancelable: true

}));

});

// 使用document.execCommand实现更真实的输入

const pasteText = () => {

const success = document.execCommand('insertText', false, text);

if (success) {

// 触发必要事件

['input', 'change'].forEach(eventType => {

inputElement.dispatchEvent(new Event(eventType, {

bubbles: true,

cancelable: true

}));

});

resolve(true);

} else {

resolve(false);

}

};

// 如果execCommand不可用,使用备用方案

if (!document.execCommand) {

inputElement.value = text;

['input', 'change'].forEach(eventType => {

inputElement.dispatchEvent(new Event(eventType, {

bubbles: true,

cancelable: true

}));

});

resolve(true);

} else {

setTimeout(pasteText, 100);

}

});

};

const safeClickButton = () => {

const button = document.querySelector(config.sendButtonSelector);

if (!button || button.getAttribute('aria-disabled') !== 'false') return false;

// 创建更真实的点击事件

const mouseEvents = ['mousedown', 'mouseup', 'click'];

mouseEvents.forEach(eventType => {

button.dispatchEvent(new MouseEvent(eventType, {

bubbles: true,

cancelable: true,

view: window

}));

});

return button.getAttribute('aria-disabled') === 'true';

};

const getLastUserMessage = () => {

const userMessages = document.querySelectorAll('div.fa81');

return userMessages.length > 0

? userMessages[userMessages.length -1].querySelector('div.fbb737a4')?.textContent?.trim()

: null;

};

const checkBusyState = () => {

const botMessages = document.querySelectorAll('div.f9bf7997.d7dc56a8');

return botMessages.length > 0

&& botMessages[botMessages.length -1].querySelector('.ds-markdown p')?.textContent === config.busyText;

};

const resendMessage = async () => {

const message = getLastUserMessage();

if (!message) return;

const input = document.querySelector(config.inputSelector);

if (!input) return;

// 等待输入完成

const inputSuccess = await safeInput(input, message);

if (!inputSuccess) {

console.error('[AutoRetry] 输入失败');

return;

}

// 等待按钮状态更新

await new Promise(resolve => setTimeout(resolve, 500));

// 点击按钮

const clickSuccess = safeClickButton();

if (!clickSuccess) {

console.error('[AutoRetry] 点击失败');

return;

}

console.log('[AutoRetry] 消息重发成功');

};

let lastState = false;

const detectionLoop = () => {

const currentState = checkBusyState();

if (currentState && !lastState) {

console.log('[AutoRetry] 触发重试机制');

resendMessage();

}

lastState = currentState;

setTimeout(detectionLoop, config.checkInterval);

};

window.addEventListener('load', () => {

setTimeout(detectionLoop, 3000);

});

})();

此文也发布在以下站点。
----
知乎 https://www.zhihu.com/people/yang-gui-fu-52

独立博客 https://younggift.net/

微信公众号 杨贵福
----
以下是我曾经发布博客的站点,有些旧文。
----
豆瓣 - 因为审核"我的日记",不再更新。
https://www.douban.com/people/younggift/?_i=0098558fqLUL9h

CSDN – 因为要求我登记手机号码的原因是“为了您的安全”,不再更新。
https://blog.csdn.net/younggift?type=blog

blogsopt – 因为从我的机器不可达,无法更新

Leave a Reply

Your email address will not be published. Required fields are marked *