ChatGPT IP 风险检测:使用油猴脚本检测 PoW 难度与 IP 质量
本文介绍如何通过简单的油猴脚本检测你的 IP 是否被 ChatGPT 判定为高风险。在一定程度上,这可以帮助你判断 IP 是否遭到服务降级(降智),或者为何模型不进行思考直接回答。
原理说明
ChatGPT 会根据用户 IP 的风险等级下发不同难度的 PoW (Proof of Work) 计算任务。如果 PoW 难度值很低,通常代表你的 IP 被判定为高风险或受到限制。
使用教程
1. 安装 Tampermonkey
首先需要安装 Tampermonkey(油猴)插件:
2. 添加脚本
创建一个新脚本,将下方的完整代码复制进去并保存。
3. 查看结果
脚本安装完成后,打开 ChatGPT。 你会看到屏幕右侧出现一个绿色圆形图标。将鼠标悬停在图标上,会显示详细信息:
- PoW 难度:显示的数值代表十六进制长度,数值越小风险越高。
- IP 质量:根据难度自动评级(高风险、中等、良好、优秀)。
- 用户类型:显示当前账号被识别的类型。
完整代码
// ==UserScript==
// @name ChatGPT PoW检测
// @namespace https://github.com/KoriIku/chatgpt-degrade-checker
// @homepage https://github.com/KoriIku/chatgpt-degrade-checker
// @author cangwei
// @version 2.1
// @description 检测 ChatGPT 数据库中的风险等级
// @match *://chatgpt.com/*
// @grant none
// @run-at document-start
// @license AGPLv3
// ==/UserScript==
(function () {
'use strict';
// 存储数据
let powData = null;
// 立即拦截 fetch
const originalFetch = window.fetch;
console.log('[ChatGPT降级检测] 脚本已加载,开始监听请求');
window.fetch = async function (resource, options) {
const url = typeof resource === 'string' ? resource : resource.url;
// console.log('[ChatGPT降级检测] fetch请求:', url); // 减少日志输出
const response = await originalFetch(resource, options);
if (url.includes('/backend-api/sentinel/chat-requirements/prepare')) {
console.log('[ChatGPT降级检测] 匹配到目标API:', url);
const clonedResponse = response.clone();
clonedResponse.json().then(data => {
console.log('[ChatGPT降级检测] 响应数据:', data);
const difficulty = data.proofofwork ? data.proofofwork.difficulty : 'N/A';
const persona = data.persona || 'N/A';
console.log('[ChatGPT降级检测] PoW难度:', difficulty);
console.log('[ChatGPT降级检测] 用户类型:', persona);
// 保存数据
powData = { difficulty, persona };
// 更新UI(如果已创建)
updateUI(difficulty, persona);
}).catch(e => console.error('[ChatGPT降级检测] 解析响应时出错:', e));
}
return response;
};
// 更新UI函数
function updateUI(difficulty, persona) {
const difficultyEl = document.getElementById('difficulty');
if (!difficultyEl) return; // UI未创建
// 计算并显示长度而不是十六进制值
if (difficulty === 'N/A') {
difficultyEl.innerText = 'N/A';
} else {
const cleanDifficulty = difficulty.replace('0x', '').replace(/^0+/, '');
const hexLength = cleanDifficulty.length;
difficultyEl.innerText = hexLength;
}
const personaContainer = document.getElementById('persona-container');
// 免费用户也展示
if (persona && persona !== 'N/A') {
personaContainer.style.display = 'block';
document.getElementById('persona').innerText = persona;
} else {
personaContainer.style.display = 'none';
}
updateDifficultyIndicator(difficulty);
}
// 等待DOM加载后创建UI
function initUI() {
// 创建显示框
const displayBox = document.createElement('div');
displayBox.style.position = 'fixed';
displayBox.style.top = '20%';
displayBox.style.right = '15px';
displayBox.style.transform = 'translateY(-50%)';
displayBox.style.width = '220px';
displayBox.style.padding = '10px';
displayBox.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
displayBox.style.color = '#fff';
displayBox.style.fontSize = '14px';
displayBox.style.borderRadius = '8px';
displayBox.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.3)';
displayBox.style.zIndex = '10000';
displayBox.style.transition = 'all 0.3s ease';
displayBox.style.display = 'none';
displayBox.innerHTML = `
<div style="margin-bottom: 10px;">
<strong>PoW 信息</strong>
</div>
<div id="content">
PoW难度: <span id="difficulty">N/A</span><span id="difficulty-level" style="margin-left: 3px"></span>
<span id="difficulty-tooltip" style="
cursor: pointer;
color: #fff;
font-size: 12px;
display: inline-block;
width: 14px;
height: 14px;
line-height: 14px;
text-align: center;
border-radius: 50%;
border: 1px solid #fff;
margin-left: 3px;
">?</span><br>
IP质量: <span id="ip-quality">N/A</span><br>
<span id="persona-container" style="display: none">用户类型: <span id="persona">N/A</span></span>
</div>
<div style="
margin-top: 12px;
padding-top: 8px;
border-top: 0.5px solid rgba(255, 255, 255, 0.15);
font-size: 10px;
color: rgba(255, 255, 255, 0.5);
text-align: center;
letter-spacing: 0.3px;
cursor: pointer;
" onclick="window.open('https://github.com/KoriIku/chatgpt-degrade-checker', '_blank')">
ChatGPT Degrade Checker
</div>`;
document.body.appendChild(displayBox);
// 创建收缩状态的指示器
const collapsedIndicator = document.createElement('div');
collapsedIndicator.style.position = 'fixed';
collapsedIndicator.style.top = '8%';
collapsedIndicator.style.right = '10px';
collapsedIndicator.style.transform = 'translateY(-50%)';
collapsedIndicator.style.width = '32px';
collapsedIndicator.style.height = '32px';
collapsedIndicator.style.backgroundColor = 'transparent';
collapsedIndicator.style.borderRadius = '50%';
collapsedIndicator.style.cursor = 'pointer';
collapsedIndicator.style.zIndex = '10000';
collapsedIndicator.style.padding = '4px';
collapsedIndicator.style.display = 'flex';
collapsedIndicator.style.alignItems = 'center';
collapsedIndicator.style.justifyContent = 'center';
collapsedIndicator.style.transition = 'all 0.3s ease';
// 使用SVG作为指示器
collapsedIndicator.innerHTML = `
<svg id="status-icon" width="32" height="32" viewBox="0 0 64 64" style="transition: all 0.3s ease;">
<defs>
<linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#3498db;stop-opacity:1" />
<stop offset="100%" style="stop-color:#2ecc71;stop-opacity:1" />
</linearGradient>
<filter id="glow">
<feGaussianBlur stdDeviation="2" result="coloredBlur"/>
<feMerge>
<feMergeNode in="coloredBlur"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<g id="icon-group" filter="url(#glow)">
<circle cx="32" cy="32" r="28" fill="url(#gradient)" stroke="#fff" stroke-width="2"/>
<circle cx="32" cy="32" r="20" fill="none" stroke="#fff" stroke-width="2" stroke-dasharray="100">
<animateTransform
attributeName="transform"
attributeType="XML"
type="rotate"
from="0 32 32"
to="360 32 32"
dur="8s"
repeatCount="indefinite"/>
</circle>
<circle cx="32" cy="32" r="12" fill="none" stroke="#fff" stroke-width="2">
<animate
attributeName="r"
values="12;14;12"
dur="2s"
repeatCount="indefinite"/>
</circle>
<circle id="center-dot" cx="32" cy="32" r="4" fill="#fff">
<animate
attributeName="r"
values="4;6;4"
dur="2s"
repeatCount="indefinite"/>
</circle>
</g>
</svg>`;
document.body.appendChild(collapsedIndicator);
// 鼠标悬停事件
collapsedIndicator.addEventListener('mouseenter', function () {
displayBox.style.display = 'block';
collapsedIndicator.style.opacity = '0';
});
displayBox.addEventListener('mouseleave', function () {
displayBox.style.display = 'none';
collapsedIndicator.style.opacity = '1';
});
// 创建提示框
const tooltip = document.createElement('div');
tooltip.id = 'tooltip';
tooltip.innerText = '这个值越小,代表PoW难度越高,ChatGPT认为你的IP风险越高。';
tooltip.style.position = 'fixed';
tooltip.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
tooltip.style.color = '#fff';
tooltip.style.padding = '8px 12px';
tooltip.style.borderRadius = '5px';
tooltip.style.fontSize = '12px';
tooltip.style.visibility = 'hidden';
tooltip.style.zIndex = '10001';
tooltip.style.width = '240px';
tooltip.style.lineHeight = '1.4';
tooltip.style.pointerEvents = 'none';
document.body.appendChild(tooltip);
// 显示提示
document.getElementById('difficulty-tooltip').addEventListener('mouseenter', function (event) {
tooltip.style.visibility = 'visible';
const tooltipWidth = 240;
const mouseX = event.clientX;
const mouseY = event.clientY;
let leftPosition = mouseX - tooltipWidth - 10;
if (leftPosition < 10) {
leftPosition = mouseX + 20;
}
let topPosition = mouseY - 40;
tooltip.style.left = `${leftPosition}px`;
tooltip.style.top = `${topPosition}px`;
});
// 隐藏提示
document.getElementById('difficulty-tooltip').addEventListener('mouseleave', function () {
tooltip.style.visibility = 'hidden';
});
// 如果已有数据,立即更新
if (powData) {
updateUI(powData.difficulty, powData.persona);
}
}
// 更新difficulty指示器
function updateDifficultyIndicator(difficulty) {
const difficultyLevel = document.getElementById('difficulty-level');
const ipQuality = document.getElementById('ip-quality');
if (difficulty === 'N/A') {
setIconColors('#888', '#666');
difficultyLevel.innerText = '';
ipQuality.innerHTML = 'N/A';
return;
}
const cleanDifficulty = difficulty.replace('0x', '').replace(/^0+/, '');
const hexLength = cleanDifficulty.length;
let color, secondaryColor, textColor, level, qualityText;
if (hexLength <= 2) {
color = '#F44336';
secondaryColor = '#d32f2f';
textColor = '#ff6b6b';
level = '(困难)';
qualityText = '高风险';
} else if (hexLength === 3) {
color = '#FFC107';
secondaryColor = '#ffa000';
textColor = '#ffd700';
level = '(中等)';
qualityText = '中等';
} else if (hexLength === 4) {
color = '#8BC34A';
secondaryColor = '#689f38';
textColor = '#9acd32';
level = '(简单)';
qualityText = '良好';
} else {
color = '#4CAF50';
secondaryColor = '#388e3c';
textColor = '#98fb98';
level = '(极易)';
qualityText = '优秀';
}
setIconColors(color, secondaryColor);
difficultyLevel.innerHTML = `<span style="color: ${textColor}">${level}</span>`;
ipQuality.innerHTML = `<span style="color: ${textColor}">${qualityText}</span>`;
}
function setIconColors(primaryColor, secondaryColor) {
const gradient = document.querySelector('#gradient');
if(gradient) {
gradient.innerHTML = `
<stop offset="0%" style="stop-color:${primaryColor};stop-opacity:1" />
<stop offset="100%" style="stop-color:${secondaryColor};stop-opacity:1" />
`;
}
}
// DOM加载完成后初始化UI
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initUI);
} else {
initUI();
}
})();