logo NodeSeekbeta

分享一个测GPT是否降智的油猴脚本

由这个 https://www.nodeseek.com/post-908122-1 帖子的代码扔给claude魔改为油猴插件
该插件只能检测是否降低模型,降低思考强度是无法检测的
直接复制粘贴以下代码导入到油猴插件里:

// ==UserScript==
// @name         ChatGPT Route Checker v4
// @name:zh-CN   ChatGPT 模型路由检测器 v4
// @namespace    local.chatgpt.route-checker
// @version      4.1.0
// @description  Display the requested model and model-routing metadata exposed by ChatGPT Web.
// @description:zh-CN 显示 ChatGPT 网页请求的模型及服务端暴露的模型路由标注。
// @match        https://chatgpt.com/*
// @match        https://chat.openai.com/*
// @run-at       document-start
// @sandbox      raw
// @grant        none
// @noframes
// ==/UserScript==
(() => {
  "use strict";
  if (window.__CHATGPT_ROUTE_CHECKER_V4__) {
    console.log("Route Checker v4 已在运行");
    return;
  }
  window.__CHATGPT_ROUTE_CHECKER_V4__ = true;

  const nativeFetch = window.fetch.bind(window);
  const nativeBeacon = navigator.sendBeacon
    ? navigator.sendBeacon.bind(navigator)
    : null;

  const state = {
    active: false,
    finished: false,
    requestModel: null,
    thinkingEffort: null,
    serverModel: null,
    assistantModel: null,
    resolvedModel: null,
    requestedExperience: null,
    domModel: null
  };

  // 供 scanObject 使用:本次扫描内“字段是否真的变化 / 是否命中 server_ste_metadata”
  let dirty = false;
  let sawServerMeta = false;
  function setField(key, value) {
    if (state[key] !== value) {
      state[key] = value;
      dirty = true;
    }
  }

  let finishTimer = null;

  // ---------------- UI ----------------
  const panel = document.createElement("div");
  Object.assign(panel.style, {
    position: "fixed",
    right: "16px",
    bottom: "16px",
    zIndex: "2147483647",
    width: "410px",
    maxWidth: "calc(100vw - 32px)",
    padding: "14px 16px",
    border: "1px solid #444",
    borderRadius: "12px",
    background: "#111",
    color: "#eee",
    font: "13px/1.7 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace",
    boxShadow: "0 8px 30px rgba(0,0,0,.4)",
    // 整个显示框缩小为原来的 70%
    transform: "scale(0.7)",
    transformOrigin: "right bottom"
  });

  function mountPanel() {
    if (!panel.isConnected && document.documentElement) {
      document.documentElement.appendChild(panel);
    }
  }
  mountPanel();

  const esc = value =>
    String(value).replace(/[&<>"']/g, c => ({
      "&": "&amp;",
      "<": "&lt;",
      ">": "&gt;",
      '"': "&quot;",
      "'": "&#39;"
    })[c]);

  function display(value) {
    return value ? esc(value) : state.finished ? "本次未返回" : "搜索中…";
  }

  function modelFamily(slug) {
    const m = String(slug || "").match(/^gpt-(\d+)-(\d+)/i);
    return m ? `gpt-${m[1]}-${m[2]}` : null;
  }

  function verdict() {
    if (!state.active) return "⏳ 等待发送一条新消息";
    if (!state.serverModel) return "🔎 检测中,等待服务端模型标注…";
    if (!state.requestModel) return "✅ 已取得服务端模型标注";
    if (state.requestModel === state.serverModel) {
      return "✅ 请求模型与服务端模型标注一致";
    }
    const reqFamily = modelFamily(state.requestModel);
    const srvFamily = modelFamily(state.serverModel);
    if (reqFamily && reqFamily === srvFamily) {
      return "✅ 同一模型系列(内部 slug 不同)";
    }
    return "🚨 请求模型与服务端模型标注不一致";
  }

  function refreshDomModel() {
    const els = document.querySelectorAll('[data-message-author-role="assistant"]');
    if (!els.length) return;
    const value = els[els.length - 1].getAttribute("data-message-model-slug");
    if (value) state.domModel = value;
  }

  function render() {
    mountPanel();
    refreshDomModel();
    panel.innerHTML = `
      <div style="font-weight:700;font-size:14px;margin-bottom:8px">
        ChatGPT Route Checker v4
      </div>
      <div style="margin-bottom:10px">${verdict()}</div>
      <div style="border-top:1px solid #333;border-bottom:1px solid #333;padding:10px 0;margin-bottom:10px">
        <div style="color:#aaa">实际回复模型标注</div>
        <div style="font-size:18px;font-weight:700;margin-top:2px">
          ${display(state.serverModel)}
        </div>
        <div style="color:#777;font-size:11px;margin-top:2px">
          server_ste_metadata.model_slug
        </div>
      </div>
      <div>
        请求的模型:<b>${display(state.requestModel)}</b><br>
        请求的思考强度:<b>${display(state.thinkingEffort)}</b><br><br>
        server_ste_metadata.model_slug:<b>${display(state.serverModel)}</b><br>
        assistant metadata.model_slug:<b>${display(state.assistantModel)}</b><br>
        resolved_model_slug:<b>${display(state.resolvedModel)}</b><br>
        requested_model_experience:<b>${display(state.requestedExperience)}</b><br>
        DOM data-message-model-slug:<b>${display(state.domModel)}</b>
      </div>
      <div style="border-top:1px solid #333;margin-top:10px;padding-top:7px;color:#777;font-size:11px">
        主判断:server_ste_metadata.model_slug<br>
        其余字段仅用于交叉验证
      </div>
    `;
  }

  // ---------------- 单轮状态管理 ----------------
  function beginTurn(req) {
    clearTimeout(finishTimer);
    state.active = true;
    state.finished = false;
    state.requestModel = typeof req?.model === "string" ? req.model : null;
    state.thinkingEffort =
      typeof req?.thinking_effort === "string" ? req.thinking_effort : null;
    state.serverModel = null;
    state.assistantModel = null;
    state.resolvedModel = null;
    state.requestedExperience = null;
    state.domModel = null;
    render();
  }

  function scheduleFinish(delay = 2000) {
    clearTimeout(finishTimer);
    finishTimer = setTimeout(() => {
      state.finished = true;
      refreshDomModel();
      render();
    }, delay);
  }

  // ---------------- 扫描 JSON ----------------
  function scanObject(obj, depth = 0, seen = new WeakSet()) {
    if (obj == null || depth > 15) return;

    if (typeof obj === "string") {
      const s = obj.trim();
      if (
        (s.startsWith("{") || s.startsWith("[")) &&
        (s.includes("model_slug") ||
          s.includes("server_ste_metadata") ||
          s.includes("resolved_model_slug"))
      ) {
        try {
          scanObject(JSON.parse(s), depth + 1, seen);
        } catch {}
      }
      return;
    }

    if (typeof obj !== "object" || seen.has(obj)) return;
    seen.add(obj);

    // server_ste_metadata 可能出现在三种位置:{type, metadata}、直属字段、turn_analytics 内
    const serverMeta =
      (obj.type === "server_ste_metadata" && obj.metadata) ||
      obj.server_ste_metadata ||
      obj.turn_analytics?.server_ste_metadata;
    if (serverMeta && typeof serverMeta === "object") {
      if (typeof serverMeta.model_slug === "string") {
        setField("serverModel", serverMeta.model_slug);
      }
      if (typeof serverMeta.requested_model_experience === "string") {
        setField("requestedExperience", serverMeta.requested_model_experience);
      }
      sawServerMeta = true;
    }

    // assistant 消息的 metadata.model_slug:可能是本对象,也可能包在 .message 里
    const assistantNode =
      obj.author?.role === "assistant"
        ? obj
        : obj.message?.author?.role === "assistant"
        ? obj.message
        : null;
    if (typeof assistantNode?.metadata?.model_slug === "string") {
      setField("assistantModel", assistantNode.metadata.model_slug);
    }

    if (typeof obj.resolved_model_slug === "string") {
      setField("resolvedModel", obj.resolved_model_slug);
    }

    for (const value of Object.values(obj)) {
      scanObject(value, depth + 1, seen);
    }
  }

  function parseData(raw) {
    if (!raw) return;
    const text = raw.trim();
    if (!text || text === "[DONE]") return;
    let obj;
    try {
      obj = JSON.parse(text);
    } catch {
      return;
    }
    dirty = false;
    sawServerMeta = false;
    scanObject(obj);
    if (dirty) render();
    if (sawServerMeta) scheduleFinish(1500);
  }

  function scanWholeText(text) {
    if (!text) return;
    parseData(text); // 整体可能就是一个 JSON
    for (let line of text.split(/\r?\n/)) {
      line = line.trim();
      if (!line) continue;
      if (line.startsWith("data:")) line = line.slice(5).trim();
      parseData(line);
    }
  }

  // ---------------- 实时 SSE 读取 ----------------
  async function watchStream(response) {
    if (!response.body) {
      try {
        scanWholeText(await response.text());
      } catch {}
      scheduleFinish();
      return;
    }

    const reader = response.body.getReader();
    const decoder = new TextDecoder();
    let buffer = "";
    let eventLines = [];
    const flushEvent = () => {
      if (eventLines.length) {
        parseData(eventLines.join("\n"));
        eventLines = [];
      }
    };

    try {
      while (true) {
        const { value, done } = await reader.read();
        if (done) break;
        buffer += decoder.decode(value, { stream: true });

        let nl;
        while ((nl = buffer.indexOf("\n")) !== -1) {
          let line = buffer.slice(0, nl);
          buffer = buffer.slice(nl + 1);
          if (line.endsWith("\r")) line = line.slice(0, -1);

          if (line === "") {
            flushEvent();
          } else if (line.startsWith("data:")) {
            eventLines.push(line.slice(5).trimStart());
          } else {
            const t = line.trim();
            if (t.startsWith("{") || t.startsWith("[")) parseData(t);
          }
        }
      }
      const rest = buffer.trim();
      if (rest.startsWith("data:")) {
        eventLines.push(rest.slice(5).trimStart());
      } else if (rest) {
        parseData(rest);
      }
      flushEvent();
    } catch (err) {
      console.debug("[Route Checker] stream reader:", err);
    }
    scheduleFinish(3000);
  }

  // ---------------- Request body ----------------
  async function bodyText(body) {
    try {
      if (body == null) return "";
      if (typeof body === "string") return body;
      if (body instanceof Blob) return await body.text();
      if (body instanceof URLSearchParams) return body.toString();
      if (body instanceof ArrayBuffer) return new TextDecoder().decode(body);
      if (ArrayBuffer.isView(body)) return new TextDecoder().decode(body);
    } catch {}
    return "";
  }

  async function getRequestText(input, init) {
    if (init?.body != null) return await bodyText(init.body);
    if (input instanceof Request) {
      try {
        return await input.clone().text();
      } catch {}
    }
    return "";
  }

  const isConversation = (url, method) =>
    method === "POST" && /\/backend-api\/f\/conversation(?:\?|$)/.test(url);
  const isTelemetry = (url, method) =>
    method === "POST" && /\/ces\/v1\/telemetry\/intake(?:\?|$)/.test(url);

  // ---------------- fetch hook ----------------
  window.fetch = async function (input, init = {}) {
    const url = typeof input === "string" ? input : input?.url || "";
    const method = String(init.method || input?.method || "GET").toUpperCase();

    if (isConversation(url, method)) {
      const reqText = await getRequestText(input, init);
      try {
        beginTurn(JSON.parse(reqText));
      } catch {
        beginTurn({});
      }
    } else if (isTelemetry(url, method)) {
      scanWholeText(await getRequestText(input, init));
    }

    const response = await nativeFetch(input, init);

    if (isConversation(url, method)) {
      try {
        void watchStream(response.clone());
      } catch {}
    }
    return response;
  };

  // ---------------- sendBeacon telemetry ----------------
  if (nativeBeacon) {
    try {
      navigator.sendBeacon = function (url, data) {
        if (/\/ces\/v1\/telemetry\/intake(?:\?|$)/.test(String(url || ""))) {
          void bodyText(data).then(scanWholeText);
        }
        return nativeBeacon(url, data);
      };
    } catch {}
  }

  // ---------------- DOM observer(用 rAF 合并高频 DOM 变动) ----------------
  let domCheckQueued = false;
  const observer = new MutationObserver(() => {
    if (domCheckQueued) return;
    domCheckQueued = true;
    requestAnimationFrame(() => {
      domCheckQueued = false;
      mountPanel();
      const before = state.domModel;
      refreshDomModel();
      if (state.domModel !== before) render();
    });
  });
  observer.observe(document, {
    subtree: true,
    childList: true,
    attributes: true,
    attributeFilter: ["data-message-model-slug"]
  });

  render();
  console.log("ChatGPT Route Checker v4 已启动,发送一条新消息即可。");
})();
12
12

你好啊,陌生人!

我的朋友,看起来你是新来的,如果想参与到讨论中,点击下面的按钮!

📈用户数目📈

目前论坛共有71747位seeker

🎉欢迎新用户🎉