然后让GEMINI也写,然后再交叉验证然后再把两个人的融合。基于现有的别人的一个插件,出来了这个,你们试试
// ==UserScript==// @name ChatGPT 智商检测器 · 始终展开版(右下角)// @namespace http://tampermonkey.net/// @version 1.2.2// @description 右下角固定展开:显示是否降级 + 启发式质量评分(TTR/重复/套话/关键词重叠/结构),含设置与性能优化;模型名多来源提取(SSE/请求体/DOM)。// @author You + NBAI// @license GPL-3.0// @match https://chatgpt.com/*// @match https://*.chatgpt.com/*// @match https://chat.openai.com/*// @match https://*.openai.com/*// @grant none// @run-at document-start// ==/UserScript==(function () { 'use strict'; // 仅在 ChatGPT/OpenAI 页面运行 const HOST_OK = /(^|\.)chatgpt\.com$|(^|\.)openai\.com$/i.test(location.hostname); if (!HOST_OK) return; /* ---------------- 配置(持久化) ---------------- */ const DEFAULT_CFG = { enableTTR: true, enableNgram: true, enableFillers: true, enableOverlap: true, preset: 'qa', scoreWarn: 60, tokenSampleEachSide: 1200, longTokenThreshold: 2400 }; function loadCfg(){ try{return {...DEFAULT_CFG, ...JSON.parse(localStorage.getItem('iq_cfg')||'{}')}}catch{return {...DEFAULT_CFG}}} function saveCfg(cfg){ localStorage.setItem('iq_cfg', JSON.stringify(cfg)); } let CFG = loadCfg(); function tuneThresholdsByPreset(){ const p=CFG.preset; if(p==='writing') return { ttrMin:.40, repTrigger:.16, fillerMin:.012, overlapMin:.04 }; if(p==='code') return { ttrMin:.25, repTrigger:.30, fillerMin:.020, overlapMin:.02 }; return { ttrMin:.35, repTrigger:.18, fillerMin:.015, overlapMin:.06 }; } /* ---------------- 多语言 ---------------- */ const languages = { 'zh-CN': { title:'ChatGPT 检测器', normal:'智商正常', downgraded:'检测到降智(模型或能力降级)', model:'模型', author:'made by NBAI + enhanced', score:'质量分', tokens:'词数', sentences:'句子', ttr:'TTR', ngram:'n-gram重复率(2/3取max)', filler:'套话/填充密度', overlap:'与问题关键词重叠', status_good:'良好', status_warn:'注意', status_bad:'警示', settings:'设置', save:'保存', preset:'预设', preset_qa:'问答', preset_writing:'写作', preset_code:'代码', guard:'分数警戒' }, 'en': { title:'ChatGPT Detector', normal:'IQ Normal', downgraded:'IQ Downgraded (model/capability)', model:'Model', author:'made by NBAI + enhanced', score:'Quality', tokens:'Tokens', sentences:'Sentences', ttr:'TTR', ngram:'n-gram repetition (max of 2/3)', filler:'Filler density', overlap:'Keyword overlap', status_good:'Good', status_warn:'Caution', status_bad:'Alert', settings:'Settings', save:'Save', preset:'Preset', preset_qa:'Q&A', preset_writing:'Writing', preset_code:'Code', guard:'Warn threshold' } }; let currentLanguage = (document.documentElement.lang||'').toLowerCase().startsWith('zh')?'zh-CN':'en'; const getText = k => (languages[currentLanguage] && languages[currentLanguage][k]) || languages['en'][k]; function detectLanguageFromHeaders(headers){ try{ let v=''; if(headers && headers.get) v = headers.get('oai-language')||''; else if(headers && typeof headers==='object') v = headers['oai-language']||headers['Oai-Language']||headers['OAI-Language']||''; if(String(v).toLowerCase()==='zh-cn') currentLanguage='zh-CN'; else if(v) currentLanguage='en'; }catch{} } /* ---------------- 样式(始终展开:取消缩放动画/小圆点状态) ---------------- */ function injectStyles(){ const style=document.createElement('style'); style.textContent=` .iq-notification{ position:fixed!important; bottom:20px!important; right:20px!important; z-index:999999!important; width:340px!important; height:auto!important; border-radius:16px!important; color:#fff; font-size:14px; display:flex; align-items:flex-start; justify-content:stretch; overflow:hidden; cursor:default; box-sizing:border-box!important; transform:none; transition:none; font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Inter',sans-serif; backdrop-filter:blur(18px); box-shadow:0 8px 32px rgba(0,0,0,.12),0 4px 16px rgba(0,0,0,.08),inset 0 1px 0 rgba(255,255,255,.08); border:1px solid rgba(255,255,255,.1); padding:14px 16px; } .iq-notification::before{content:'';position:absolute;inset:0;border-radius:inherit; background:linear-gradient(135deg,rgba(255,255,255,.12),rgba(255,255,255,.06));pointer-events:none} .iq-notification.normal{background:linear-gradient(135deg,rgba(16,185,129,.9),rgba(5,150,105,.9),rgba(6,182,212,.8))} .iq-notification.downgraded{background:linear-gradient(135deg,rgba(239,68,68,.9),rgba(220,38,38,.9),rgba(251,113,133,.8))} /* 始终展开:去掉小圆点/展开态差异 */ .iq-notification .circle-icon{display:none} .iq-notification .expanded-content{display:block;width:100%} .iq-notification .close-btn{ position:absolute; top:8px; right:8px; width:24px; height:24px; border-radius:50%; background:rgba(255,255,255,.1); border:1px solid rgba(255,255,255,.2); color:#fff; font-size:14px; display:flex; align-items:center; justify-content:center; cursor:pointer; opacity:.75; transition:all .2s ease; backdrop-filter:blur(10px) } .iq-notification .close-btn:hover{ opacity:1; transform:scale(1.05) } .iq-title{font-size:12px;letter-spacing:.5px;text-transform:uppercase;margin:0 0 8px 0; background:linear-gradient(90deg,rgba(255,255,255,.9),rgba(255,255,255,.7));-webkit-background-clip:text;-webkit-text-fill-color:transparent;font-weight:700} .iq-row{display:flex;align-items:center;gap:10px;margin:6px 0;flex-wrap:wrap} .iq-badge{display:inline-flex;align-items:center;gap:6px;padding:2px 8px;border-radius:999px;background:rgba(255,255,255,.16);font-weight:700;font-size:12px} .iq-badge.good{background:#d1fae5;color:#065f46} .iq-badge.warn{background:#fef3c7;color:#92400e} .iq-badge.bad{background:#fee2e2;color:#991b1b} .iq-kv{display:flex;justify-content:space-between;gap:10px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,"Liberation Mono",monospace} .iq-kv + .iq-kv{margin-top:4px} .iq-k{opacity:.75} .iq-v{font-weight:700} .iq-reasons{margin-top:8px;padding:8px;border-radius:8px;background:rgba(0,0,0,.08);border:1px solid rgba(255,255,255,.12);font-family:ui-monospace,Menlo,Consolas,monospace;font-size:12px;line-height:1.5;white-space:pre-wrap;display:block} .iq-author{font-size:10px;opacity:.6;margin-top:6px;text-align:center;font-style:italic} .iq-settings-btn{margin-top:8px;padding:6px 10px;border-radius:10px;border:1px solid rgba(255,255,255,.2);background:rgba(255,255,255,.12);color:#fff;cursor:pointer;font-size:12px} .iq-settings{margin-top:8px;padding:8px;border-radius:8px;background:rgba(0,0,0,.06);border:1px dashed rgba(255,255,255,.2);display:none} .iq-settings label{margin-right:10px;display:inline-flex;align-items:center;gap:4px} .iq-settings select,.iq-settings input[type="number"]{padding:2px 6px;border-radius:6px;border:1px solid rgba(0,0,0,.15)} .iq-settings .row{margin:6px 0;display:flex;align-items:center;gap:8px;flex-wrap:wrap} .iq-save-btn{margin-left:8px;padding:4px 10px;border-radius:8px;border:1px solid rgba(0,0,0,.15);background:#fff;color:#333;cursor:pointer;font-size:12px} `; document.head.appendChild(style); } /* ---------------- 质量分析 ---------------- */ function tokenizeMixed(t){const out=[];const re=/[\p{Script=Han}]{1}|[A-Za-z0-9]+(?:'[A-Za-z0-9]+)?/gu;let m;while((m=re.exec(t))!==null)out.push(m[0].toLowerCase());return out;} function sentenceSplit(t){return t.split(/[.!?。!?;;]\s*/).map(s=>s.trim()).filter(s=>s.length>=4);} function ngramRepeatRatio(tokens,n=2){if(tokens.length<n*3)return 0;const grams=[];for(let i=0;i+n<=tokens.length;i++)grams.push(tokens.slice(i,i+n).join(' '));const total=grams.length;const uniq=new Set(grams).size;return total?(1-uniq/total):0;} const FILLERS=[/as an ai/gi,/it is important to/gi,/in general/gi,/however/gi,/please note/gi,/i cannot/gi,/i am not able/gi,/on the other hand/gi,/it's possible that/gi,/作为一个ai/gi,/作为一名ai/gi,/作为语言模型/gi,/需要注意的是/gi,/通常来说/gi,/总体而言/gi,/我无法访问互联网/gi,/无法提供实时/gi,/从某种程度上/gi]; function lexicalDiversity(tokens){if(!tokens.length)return 0;const uniq=new Set(tokens).size;return uniq/tokens.length;} function fillerDensity(text){let c=0;for(const re of FILLERS)c+=(text.match(re)||[]).length;const tokens=tokenizeMixed(text);return tokens.length?c/tokens.length:0;} function keywordOverlap(u,a){const stop=new Set(['the','is','are','and','or','to','of','in','on','for','a','an','with','that','this','it','be','as','at','by','from','than','then','等','的','了','和','是','在','与','及','对','或','把','被','而','并','就','也','及其','以及','通过']);const tu=tokenizeMixed(u).filter(w=>!stop.has(w));const ta=tokenizeMixed(a).filter(w=>!stop.has(w));if(!tu.length||!ta.length)return 0;const su=new Set(tu);let inter=0;for(const w of new Set(ta))if(su.has(w))inter++;const union=new Set([...tu,...ta]).size;return union?inter/union:0;} function analyzeQuality(answer,user=''){ const thr=tuneThresholdsByPreset(); const baseTokens=tokenizeMixed(answer); const needSample=baseTokens.length>(CFG.longTokenThreshold||2400); const tokens=needSample?baseTokens.slice(0,CFG.tokenSampleEachSide).concat(baseTokens.slice(-CFG.tokenSampleEachSide)):baseTokens; const ttr=lexicalDiversity(tokens); const rep2=ngramRepeatRatio(tokens,2), rep3=ngramRepeatRatio(tokens,3), rep=Math.max(rep2,rep3); const fill=fillerDensity(answer); const sent=sentenceSplit(answer).length; const ovlp=user?keywordOverlap(user,answer):null; let score=100, reasons=[]; if(CFG.enableTTR && ttr<thr.ttrMin && tokens.length>80){const p=Math.min((thr.ttrMin-ttr)*120,25);score-=p;reasons.push(`TTR=${ttr.toFixed(3)} (<${thr.ttrMin}) (-${p.toFixed(0)})${needSample?' · sample':''}`);} if(CFG.enableNgram && rep>thr.repTrigger){const p=Math.min((rep-thr.repTrigger)*220,30);score-=p;reasons.push(`n-gram≈${(rep*100).toFixed(1)}% (>${(thr.repTrigger*100).toFixed(0)}%) (-${p.toFixed(0)})${needSample?' · sample':''}`);} if(CFG.enableFillers && fill>thr.fillerMin){const p=Math.min((fill-thr.fillerMin)*3000,25);score-=p;reasons.push(`fill=${fill.toFixed(3)} (>${thr.fillerMin}) (-${p.toFixed(0)})`);} if(CFG.enableOverlap && ovlp!==null && ovlp<thr.overlapMin){score-=20;reasons.push(`overlap=${(ovlp*100).toFixed(1)}% (<${(thr.overlapMin*100).toFixed(0)}%) (-20)`);} if(sent<=1 && tokens.length>60){score-=10;reasons.push('1 段落过长 (-10)');} score=Math.max(0,Math.min(100,Math.round(score))); return {score,reasons,ttr,rep,fill,ovlp,tokens:baseTokens.length,sentences:sent}; } /* ---------------- DOM/气泡 ---------------- */ function escapeHtml(s){return String(s).replaceAll('&','&').replaceAll('<','<').replaceAll('>','>').replaceAll('"','"').replaceAll("'","'");} function getLastUserText(){const users=[...document.querySelectorAll('[data-message-author-role="user"]')];const u=users[users.length-1];return u?((u.innerText||u.textContent||'').trim()):'';} function getAssistantNodes(){return [...document.querySelectorAll('[data-message-author-role="assistant"]')];} let modelSlugMemo=''; let downgradedMemo=null; let lastScorePayload=null; let notif=null; function ensureNotification(){ if(notif && document.body.contains(notif)) return notif; notif=document.createElement('div'); // 始终展开:类名直接使用“expanded”效果样式(但我们 CSS 已让 expanded/非expanded一致) notif.className=`iq-notification normal expanded`; notif.innerHTML=` <div class="expanded-content"> <button class="close-btn" title="close">×</button> <div class="iq-title">${getText('title')}</div> <div class="iq-row"> <span class="iq-badge" id="iq-badge-score">--</span> <span class="iq-badge" id="iq-badge-model">${getText('model')}: --</span> <button class="iq-settings-btn" id="iq-settings-btn">⚙️ ${getText('settings')}</button> </div> <div id="iq-kvs"></div> <div class="iq-reasons" id="iq-reasons"></div> <div class="iq-settings" id="iq-settings"></div> <div class="iq-author">${getText('author')}</div> </div>`; document.body.appendChild(notif); // 始终展开:禁止折叠/展开切换 notif.addEventListener('click',(e)=>{ /* no-op,保持展开 */ }); const closeBtn=notif.querySelector('.close-btn'); if(closeBtn){ closeBtn.addEventListener('click',(e)=>{ e.stopPropagation(); // 保持可手动关闭 if (notif && notif.parentNode) notif.remove(); }); } const settingsBtn=notif.querySelector('#iq-settings-btn'); const settingsPanel=notif.querySelector('#iq-settings'); if(settingsBtn && settingsPanel){ settingsBtn.addEventListener('click',(e)=>{ e.stopPropagation(); settingsPanel.style.display = settingsPanel.style.display==='none'?'block':'none'; if(settingsPanel.style.display==='block') renderSettingsPanel(settingsPanel); }); } return notif; } function renderSettingsPanel(container){ container.innerHTML=` <div class="row"> <label><input type="checkbox" id="cfg-ttr" ${CFG.enableTTR?'checked':''}> TTR</label> <label><input type="checkbox" id="cfg-ng" ${CFG.enableNgram?'checked':''}> n-gram</label> <label><input type="checkbox" id="cfg-fi" ${CFG.enableFillers?'checked':''}> ${getText('filler')}</label> <label><input type="checkbox" id="cfg-ov" ${CFG.enableOverlap?'checked':''}> ${getText('overlap')}</label> </div> <div class="row"> ${getText('preset')}: <select id="cfg-preset"> <option value="qa" ${CFG.preset==='qa'?'selected':''}>${getText('preset_qa')}</option> <option value="writing" ${CFG.preset==='writing'?'selected':''}>${getText('preset_writing')}</option> <option value="code" ${CFG.preset==='code'?'selected':''}>${getText('preset_code')}</option> </select> ${getText('guard')}: <input id="cfg-warn" type="number" min="0" max="100" value="${CFG.scoreWarn}" style="width:72px"> <button class="iq-save-btn" id="cfg-save">${getText('save')}</button> </div>`; container.querySelector('#cfg-save').onclick=()=>{ CFG.enableTTR=container.querySelector('#cfg-ttr').checked; CFG.enableNgram=container.querySelector('#cfg-ng').checked; CFG.enableFillers=container.querySelector('#cfg-fi').checked; CFG.enableOverlap=container.querySelector('#cfg-ov').checked; CFG.preset=container.querySelector('#cfg-preset').value; CFG.scoreWarn=Math.max(0,Math.min(100,+container.querySelector('#cfg-warn').value||60)); saveCfg(CFG); scanLatestAssistant(true); }; } function updateNotification(){ const el=ensureNotification(); const downgraded=!!(typeof downgradedMemo==='boolean'?downgradedMemo:false); el.classList.remove('normal','downgraded'); el.classList.add(downgraded?'downgraded':'normal'); const scoreBadge=el.querySelector('#iq-badge-score'); if(scoreBadge){ if(lastScorePayload){ const s=lastScorePayload.score; const status= s>=80 ? {t:getText('status_good'),c:'good'} : s>=CFG.scoreWarn ? {t:getText('status_warn'),c:'warn'} : {t:getText('status_bad'),c:'bad'}; scoreBadge.textContent = `${getText('score')} ${s}/100 · ${status.t}`; scoreBadge.className = `iq-badge ${status.c}`; }else{ scoreBadge.textContent = `${getText('score')} --`; scoreBadge.className = `iq-badge`; } } const modelBadge=el.querySelector('#iq-badge-model'); if(modelBadge){ const ms = modelSlugMemo || tryReadModelFromDOM() || '--'; modelBadge.textContent = `${getText('model')}: ${ms}`; } const kvs=el.querySelector('#iq-kvs'); if(kvs && lastScorePayload){ const m=lastScorePayload; kvs.innerHTML=` <div class="iq-kv"><span class="iq-k">📦 ${getText('tokens')}</span><span class="iq-v">${m.tokens}</span></div> <div class="iq-kv"><span class="iq-k">✂️ ${getText('sentences')}</span><span class="iq-v">${m.sentences}</span></div> <div class="iq-kv"><span class="iq-k">🔤 ${getText('ttr')}</span><span class="iq-v">${m.ttr.toFixed(3)}</span></div> <div class="iq-kv"><span class="iq-k">🔁 ${getText('ngram')}</span><span class="iq-v">${m.rep.toFixed(3)}</span></div> <div class="iq-kv"><span class="iq-k">🧩 ${getText('filler')}</span><span class="iq-v">${m.fill.toFixed(3)}</span></div> ${typeof m.ovlp==='number'?`<div class="iq-kv"><span class="iq-k">🔗 ${getText('overlap')}</span><span class="iq-v">${(m.ovlp*100).toFixed(1)}%</span></div>`:''} `; } const reasonsBox=el.querySelector('#iq-reasons'); if(reasonsBox){ if(lastScorePayload && lastScorePayload.reasons.length){ reasonsBox.innerHTML = escapeHtml(lastScorePayload.reasons.map(r=>`• ${r}`).join('\n')); }else{ reasonsBox.textContent=''; } } } /* ---------------- 模型提取:SSE / 请求体 / DOM ---------------- */ function safeGet(obj, pathArr){ try{ return pathArr.reduce((o,k)=> (o && (k in o)) ? o[k] : undefined, obj); }catch{return undefined;} } function extractModelFromJson(obj){ const paths = [ ['metadata','model_slug'], ['model'], ['response','model'], ['message','model'], ['payload','model'], ['conversation','model'], ['meta','model'], ]; for(const p of paths){ const v = safeGet(obj, p); if(typeof v==='string' && v.trim()) return v.trim(); } try{ const q=[obj]; const seen=new Set(); while(q.length){ const cur=q.shift(); if(!cur || typeof cur!=='object' || seen.has(cur)) continue; seen.add(cur); for(const [k,v] of Object.entries(cur)){ if(k==='model' && typeof v==='string' && v.trim()) return v.trim(); if(v && typeof v==='object') q.push(v); } } }catch{} return ''; } function parseStreamData(text){ const lines=text.split('\n'); let model=''; for(const line of lines){ if(!line.startsWith('data: ') || line.includes('[DONE]')) continue; const jsonStr=line.slice(6).trim(); if(!jsonStr) continue; try{ const obj=JSON.parse(jsonStr); const m=extractModelFromJson(obj); if(m){ model=m; break; } }catch{} } if(model){ return { modelSlug: model, isDowngraded: /^i-/i.test(model) }; } return { modelSlug:'', isDowngraded:null }; } function tryReadModelFromDOM(){ const candidates = [ '[data-testid="model-switcher"]', '[aria-label*="Model"]', '[aria-label*="模型"]', 'header button[role="combobox"]', ]; for(const sel of candidates){ const el=document.querySelector(sel); if(el){ const txt=(el.innerText||el.textContent||'').trim(); if(/gpt|o\d|4o|mini|sonnet|haiku|4\.1|o3|o4|turbo/i.test(txt)) return txt.replace(/\s+/g,' '); } } return ''; } /* ---- 劫持 fetch/XHR:读 SSE;并从请求体捕获 model ---- */ function interceptFetch(){ if(window.__iq_fetch_patched__) return; window.__iq_fetch_patched__=true; const orig=window.fetch; window.fetch=function(...args){ let [url, options]=args; const urlStr = typeof url==='string' ? url : (url&&url.url)||''; const target = /\/backend-api\/(f\/)?conversation/.test(urlStr); // 从请求体抓 model try{ if(target && options && options.body){ const bodyText = typeof options.body==='string' ? options.body : (options.body?.toString?.()||''); if(bodyText && bodyText[0]==='{'){ const obj=JSON.parse(bodyText); const m=extractModelFromJson(obj); if(m){ modelSlugMemo=m; downgradedMemo=/^i-/i.test(m); updateNotification(); } } } }catch{} if(target && options && options.headers) detectLanguageFromHeaders(options.headers); const p=orig.apply(this,args); if(!target) return p; return p.then(response=>{ try{ if(response.ok && response.body){ const cloned=response.clone(); const reader=cloned.body.getReader(); let fullText=''; (function pump(){ return reader.read().then(({done,value})=>{ if(done){ const res=parseStreamData(fullText); if(res.modelSlug){ modelSlugMemo=res.modelSlug; downgradedMemo=!!res.isDowngraded; updateNotification(); } return; } try{ fullText += new TextDecoder().decode(value); }catch{} return pump(); }); })().catch(()=>{}); } }catch{} return response; }); }; } function interceptXHR(){ if(window.__iq_xhr_patched__) return; window.__iq_xhr_patched__=true; const open=XMLHttpRequest.prototype.open; const send=XMLHttpRequest.prototype.send; const setHeader=XMLHttpRequest.prototype.setRequestHeader; XMLHttpRequest.prototype.open=function(method,url,...rest){ this.__iq_url=url; this.__iq_headers={}; return open.call(this,method,url,...rest); }; XMLHttpRequest.prototype.setRequestHeader=function(k,v){ try{ (this.__iq_headers||(this.__iq_headers={}))[k]=v; }catch{} return setHeader.call(this,k,v); }; XMLHttpRequest.prototype.send=function(body){ const url=this.__iq_url||''; const target=/\/backend-api\/(f\/)?conversation/.test(url); // 从请求体抓 model try{ if(target && typeof body==='string' && body[0]==='{'){ const obj=JSON.parse(body); const m=extractModelFromJson(obj); if(m){ modelSlugMemo=m; downgradedMemo=/^i-/i.test(m); updateNotification(); } } }catch{} if(target && this.__iq_headers) detectLanguageFromHeaders(this.__iq_headers); if(target){ this.addEventListener('readystatechange',function(){ if(this.readyState===4 && this.status===200 && typeof this.responseText==='string'){ try{ const res=parseStreamData(this.responseText); if(res.modelSlug){ modelSlugMemo=res.modelSlug; downgradedMemo=!!res.isDowngraded; updateNotification(); } }catch{} } }); } return send.call(this, body); }; } /* ---------------- 观察与评分 ---------------- */ let observer=null, debounceTimer=null; function ensureObserver(){ if(observer) return observer; observer = new MutationObserver(()=>{ clearTimeout(debounceTimer); debounceTimer=setTimeout(()=>scanLatestAssistant(false),300); }); return observer; } function connectObserver(){ ensureObserver().observe(document.documentElement,{subtree:true,childList:true,characterData:true}); } function disconnectObserver(){ if(observer) observer.disconnect(); } document.addEventListener('visibilitychange',()=>{ if(document.hidden) disconnectObserver(); else { connectObserver(); setTimeout(()=>scanLatestAssistant(false),200); }}); function scanLatestAssistant(forceRefreshUI){ const nodes=getAssistantNodes(); if(!nodes.length){ if(forceRefreshUI) updateNotification(); return; } const last=nodes[nodes.length-1]; const text=((last.innerText||last.textContent||'')+'').trim(); if(!text || text.length<30){ if(forceRefreshUI) updateNotification(); return; } const prevLen=last.__iq_last_len||0; if(!forceRefreshUI && prevLen!==text.length){ last.__iq_last_len=text.length; return; } last.__iq_last_len=text.length; try{ const userText=getLastUserText(); lastScorePayload=analyzeQuality(text,userText); if(!modelSlugMemo){ const domModel=tryReadModelFromDOM(); if(domModel){ modelSlugMemo=domModel; downgradedMemo=/^i-/i.test(domModel); } } updateNotification(); }catch(e){ console.error('[IQ Detector] analyze error:',e); } } /* ---------------- 路由/初始化 ---------------- */ function setupRouteListener(){ let href=location.href; const reinit=()=>{ setTimeout(()=>{ interceptFetch(); interceptXHR(); updateNotification(); },120); }; window.addEventListener('popstate',()=>{ if(location.href!==href){ href=location.href; reinit(); }}); const push=history.pushState, replace=history.replaceState; history.pushState=function(...a){ const r=push.apply(this,a); if(location.href!==href){ href=location.href; reinit(); } return r; }; history.replaceState=function(...a){ const r=replace.apply(this,a); if(location.href!==href){ href=location.href; reinit(); } return r; }; } function start(){ injectStyles(); interceptFetch(); interceptXHR(); connectObserver(); setTimeout(()=>scanLatestAssistant(false),1500); updateNotification(); } if(document.readyState==='loading'){ document.addEventListener('DOMContentLoaded',()=>{ start(); setupRouteListener(); }); }else{ start(); setupRouteListener(); }})();
评论 (0)