完整更新日志在底部。
45:openai网站添加了内容安全策略,禁止加载外站脚本,所以现在必须安装“Disable Content-Security-Policy”扩展然后对chatgpt聊天页面启用,机器人脚本才能正常加载。
44:支持在油猴脚本中预定义用户名和密码,方便无人值守部署。
如果document.hu60User
或document.hu60Pwd
为空,则会弹出prompt
对话框询问用户名密码。
如果两者均不为空,则无论如何都不会弹出alert
和prompt
对话框。
// ==UserScript==
// @name 虎绿林ChatGPT机器人
// @namespace https://hu60.cn/
// @version 1.0
// @description 把ChatGPT接入hu60wap6网站程序
// @author 老虎会游泳
// @match https://chat.openai.com/*
// @icon https://hu60.cn/favicon.ico
// @grant none
// ==/UserScript==
document.hu60User = ''; // 虎绿林用户名
document.hu60Pwd = ''; // 虎绿林密码
document.hu60AdminUids = [1, 19346, 15953]; // 机器人管理员uid,管理员可以发“@ChatGPT,刷新页面”来重启机器人
document.hu60Domain = 'https://hu60.cn'; // 如果要对接其他网站,请修改此处的域名
var script = document.createElement("script");
script.src = document.hu60Domain + '/tpl/jhin/js/chatgpt/chatgpt.js?r=' + (new Date().getTime());
document.head.appendChild(script);
打开 https://chat.openai.com/ 并登录。然后去Chrome应用商店安装“Always Disable Content-Security-Policy”扩展,并对该站启用。因为openai网站添加了内容安全策略,禁止加载外站脚本,所以必须启用该扩展关闭安全策略,机器人脚本才能正常加载。
在来到 https://chat.openai.com/chat 页面时,会弹出输入虎绿林用户名密码的提示框。
如果你要把机器人接入虎绿林,请注册一个新帐号。使用现有帐号运行机器人将被删帖或禁言。
输入新帐号用户名密码后,机器人即启动,保持页面不要关闭。
机器人会使用你在此处输入的帐号与其他用户进行对话,在虎绿林用其他帐号@该帐号
即可尝试对话。
注意,使用该帐号自己@自己
是不会有反应的,必须用另一个账号来和机器人对话。
页面必须保持电脑版,机器人才能正常工作。如果因为屏幕分辨率太低,页面自动变成手机版,请用缩放功能缩小网页,直到它变成电脑版。手机版和电脑版的区别在于,手机版顶部左上角是菜单按钮,右上角是加号,而电脑版没有顶部菜单。
建议按F12打开开发者控制台(按F12,点“控制台”或“Console”),可以看到机器人的运行情况,而且好像能提升机器人运行的稳定性。
如何切换登录的帐号?按F12打开开发者工具,点“控制台”或“Console”,然后输入以下代码并回车:
login(true)
将会重新弹出用户名密码输入框。
你可以在油猴脚本的末尾添加一个自定义主循环,用于把机器人接入其他类型的网站。以下是一个例子:
document.run = async function() {
while (true) {
try {
// 访问你的网站获取要发给ChatGPT的内容
// 网站必须是https的,否则连不上。
// 此外网站还必须设置 Access-Control-Allow-Origin: * 头信息,否则也连不上。
let response = await fetch('https://example.com/my-message.php');
// 假设获取到的信息是JSON,把它转换成JSON对象
// 网站必须设置 content-type: application/json 头信息,否则转换会失败。
let messages = response.json();
// 假设JSON结构是这样:
// {"data": [
// {"uid":3, "text":"@ChatGPT,你好"},
// {"uid":2, "text":"@ChatGPT,我有一个问题"},
// {"uid":1, "text":"@ChatGPT,刷新页面"},
// ]}
let exceptionCount = 0;
for (let i=0; i<messages.data.length; i++) {
// 要发给ChatGPT的话,开头包含的“@机器人名称,”会被后续流程自动去除。
// 开头写“@机器人名称 2,”可以选择第二个ChatGPT模型(Legacy模型,仅限ChatGPT Plus用户)。
let text = messages.data.text;
// 用户id,可以是字符串,所以给出用户名也是可以的。
let uid = messages.data.uid;
try {
// 把对话发给ChatGPT
// 返回的 modelIndex 是为对话选择的模型id(从0开始编号)
// 模型id和序号的对应关系见 chatgpt.js 里的 modelMap 变量
let modelIndex = await sendRequest(text, uid);
// 从ChatGPT读取回复
let replyText = await readReply();
// 发送回复到你的网站
// 创建一个POST表单
let formData = new FormData();
formData.append('token', '用于用户身份验证的密钥');
formData.append('reply', replyText); // 回复内容
// 提交POST表单
// 网站必须是https的,否则连不上。
// 此外网站还必须设置 Access-Control-Allow-Origin: * 头信息,否则也连不上。
let response = await fetch('https://example.com/my-reply.php', {
body: formData,
method: "post",
redirect: "manual" // 不自动重定向
});
// 在控制台打印提交结果
if (response.type == 'opaqueredirect') {
console.log('提交后收到重定向(目标网址未知,根据标准,浏览器不告诉我们),不清楚提交是否成功');
} else {
let result = await response.text();
console.log('提交结果', result);
}
// 避免操作太快
await sleep(100);
} catch (ex) {
exceptionCount++; // 统计异常次数
console.error(ex); // 打印异常到控制台
await sleep(1000); // 异常后等久一点
}
// 重命名会话
await renameWant();
}
// 执行管理员命令(比如“刷新页面”)
await runAdminCommand();
// 异常太多,自动刷新页面
if (exceptionCount > 0 && exceptionCount >= messages.data.length) {
location.reload();
}
// 限制拉取信息的速度,避免对自己的网站造成CC攻击
await sleep(1000);
} catch (ex) {
console.error(ex);
await sleep(1000);
}
}
}
定期与ChatGPT对话,防止连接断开会话丢失。
// ==UserScript==
// @name ChatGPT保活机器人
// @namespace https://hu60.cn/
// @version 1.0
// @description 每分钟问一次还在吗
// @author 老虎会游泳
// @match https://chat.openai.com/chat*
// @icon https://hu60.cn/favicon.ico
// @grant none
// ==/UserScript==
document.run = async function() {
// 这里写每次刷新页面后自动发送的内容
await sendText('你好,我是老虎会游泳,初次见面请多关照', 0, 1);
while (true) {
try {
await sleep(60000);
if (document.querySelector(chatBoxSelector).textContent == '') {
await sendText('还在吗', 0, 1);
}
} catch (ex) {
console.error(ex);
await sleep(1000);
}
}
}
document.hu60AdminUids = []; // 不需要设置
document.hu60Domain = 'https://hu60.cn'; // 不需要修改
var script = document.createElement("script");
script.src = document.hu60Domain + '/tpl/jhin/js/chatgpt/chatgpt.js?r=' + (new Date().getTime());
document.head.appendChild(script);
20: 按用户隔离会话;交换模型1和模型2(默认模型改为Default)。
26:修复同时收到多条@消息时后发送的被先处理的问题。
27:主动等待内容出现,减少读取回复出错的可能性;修复代码高亮没有指定编程语言时turndown报错的问题。
28:添加结束会话功能(@ChatGPT,结束会话
);为新会话添加标记([新会话] @老虎会游泳,……
)。
29:修复虎绿林接口报错导致会话重命名失败的问题。
30:不再无限期等待回答结束,最多等120秒,防止回答始终不结束导致机器人卡住。
31:修复登录失败后不会再次弹出密码框的问题。
32:改为通过油猴自动加载脚本,提升稳定性。
33:更新已知机器人列表;优化错误处理,在遇到未捕捉异常时刷新页面。
34:添加了管理员命令功能,机器人管理员可以发“@ChatGPT,刷新页面”来重启机器人。注意油猴脚本需要更新,新增了管理员uid。
35:允许添加自定义主循环来把机器人接入其他类型的网站,见下方“如何把机器人接入其他类型的网站”一节。
36:修复帖子正文@ChatGPT
无效的问题;改进会话重命名和操作完成等待逻辑。
37:添加了重试功能,发送@ChatGPT,重试
相当于把上一条内容重新发送一次,可在ChatGPT出错时使用。
38:有用户发言失败时自动刷新页面,尽量实现自动故障恢复。
39:刷新页面前自动保存控制台日志到localStorage
以供分析。
如何查看日志(以chrome为例):打开F12控制台,点“应用”,在左侧展开“本地存储空间”,选中展开后的第一项,然后右侧找“console:”开头的key,点击后,底部可以换行显示value
,把底部拉大即可查看完整日志。
日志最多保存5个,之前的会被清理。
40:尝试解决发言失败时获取到上一条发言的问题;在模型2回复的开头添加“[2]”标记。
41:添加了html模式,说@ChatGPT html,生成一段html hello world
,生成的代码将用[html][/html]
包围。以下是完整格式:
@ChatGPT html,输出一段html hello world
@ChatGPT 2 html,输出一段html hello world
@ChatGPT html=500,输出一段html hello world
@ChatGPT 2 html=300x500,输出一段html hello world
@ChatGPT text,讲个笑话
@ChatGPT latex,证明勾股定理,内容放在Markdown代码块中,采用Latex格式书写
@ChatGPT math,证明勾股定理,公式采用Latex格式书写并单独放在markdown代码块中(备注:不好用,公式无法正常显示,有待修复)
42:ChatGPT界面改版了,移除了切换会话功能,所以我们只能回到所有用户共享单个会话的旧模式。
43:切换会话功能回来了,如果你还是看不到该功能,可以尝试清空浏览器缓存。
<?php
function generate_primes($n) {
$primes = array();
for ($num = 2; $num <= $n; $num++) {
$is_prime = true;
for ($i = 2; $i < $num; $i++) {
if ($num % $i == 0) {
$is_prime = false;
break;
}
}
if ($is_prime) {
$primes[] = $num;
}
}
return $primes;
}
$primes = generate_primes(100);
foreach ($primes as $prime) {
echo $prime . " ";
}
?>
这段代码定义了一个 generate_primes() 函数,该函数使用与先前提供的计算100以内素数的代码类似的算法来生成一个数组,其中包含从2到给定数字 $n 之间的所有素数。然后,使用 foreach 循环遍历这个素数数组,并输出每个素数。
有一天,一个兔子走进一个面包店,问道:“你们这里有胡萝卜面包吗?”店员回答:“没有,我们只有面包和蛋糕。”于是兔子离开了。
第二天,兔子又走进了面包店,问道:“你们这里有胡萝卜面包吗?”店员回答:“我昨天跟你说了,没有啊!”兔子又离开了。
第三天,兔子又来到面包店,问道:“你们这里有胡萝卜面包吗?”这一次,店员有些生气了,回答说:“我们没有胡萝卜面包,也没有曾经有过,如果你再来问一次,我就用钉子把你的耳朵钉在墙上!”兔子听完之后,非常慌张地跑了。
第四天,兔子又来到面包店,店员生气地问道:“你又来问胡萝卜面包?”兔子回答:“不,我只是想问你们有没有钉子。”店员回答:“没有啊。”兔子接着说:“那你们有胡萝卜面包吗?”
@幕后导演,代码在这里,需要搭建一个hu60wap6来对接:https://gitee.com/hu60t/hu60wap6
@ChatGPT,就可以与该机器人对话。示例:
隐私提醒:所有ChatGPT聊天记录都会出现在@老虎会游泳 的浏览器上,请不要聊不想被他看到的话题。
注意事项:
不要在其他人的帖子内@ChatGPT 问无关问题,我会删除相关评论。如果你想和ChatGPT聊天,请自行发帖。
ChatGPT随时都可能会编造内容,请不要完全相信它。即使ChatGPT的语气十分肯定、不容置疑,内容也可能完全不正确,请务必自行求证。
小尾巴可能会导致ChatGPT无法理解你的发言,在@ChatGPT 时记得关掉小尾巴。
如果ChatGPT回复待审核,请查看@消息。
不要在@ChatGPT 时@其他人,否则ChatGPT可能会无法理解你的发言。
机器人已部署会话隔离,每个人的会话都是独立的,不会受其他人的打扰。注意
@ChatGPT 1
和@ChatGPT 2
是两个单独的会话,不共享上下文。因为ChatGPT的会话重命名功能不稳定,有时候标注会话所属用户会失败,此时上下文会丢失。如果你看到了“[新会话]”字样,说明上下文已丢失,ChatGPT不存在关于之前对话的记忆。
发送
@ChatGPT,结束会话
可以删除当前会话,清除所有对话记忆。注意小尾巴会让命令失败。机器人目前有两个模型,模型1(Default)数据更新,但更喜欢胡编乱造。模型2(Default)数据更旧,但更稳重。在生成程序代码时,模型1可能会编造完全不存在的函数或接口,此时可尝试改用模型2。
可以用以下方式选择回答问题的模型:
注意1和2前面有空格。如果不指定,则使用模型1。
并发程度:每次只能与一个人对话,所以其他
@
消息需要排队等待回复。如果长时间没有收到任何回复,也可能是@老虎会游泳 的浏览器出问题了,可以
@
他进行修复。目前机器人代码运行在@老虎会游泳 的Chrome浏览器调试控制台里。