b站硬核会员答题辅助(Gemini ver.)

b站硬核会员答题辅助

// ==UserScript==
// @name         b站硬核会员答题辅助(Gemini ver.)
// @namespace    https://github.com/Masetti0927
// @version      2025-10-09
// @description  b站硬核会员答题辅助
// @author       masetti
// @match        https://www.bilibili.com/h5/senior-newbie/qa
// @license      GPL-3.0-only
// @icon         https://www.google.com/s2/favicons?sz=64&domain=bilibili.com
// @grant        none
// ==/UserScript==
(function () {
    'use strict';
    // ⭐⭐⭐ 1. 请输入你的 Google AI Studio API Key ⭐⭐⭐
    // 你也可以直接在这里把 Key 写死,例如: const API_KEY = "AIzaSy...你的Key";
    const API_KEY = prompt("请输入你的 Google AI Studio API Key:");

    // ⭐⭐⭐ 2. 需要别的模型这里改 ⭐⭐⭐
    // 推荐使用性能较好的模型,如 gemini-2.5-flash 或 gemini-2.5-pro
    const MODEL = "gemini-2.5-flash"; // 或 "gemini-2.5-pro"

    // ⭐⭐⭐ 3. Google Gemini API 的 ENDPOINT ⭐⭐⭐
    // API URL 包含模型名称,Key 作为查询参数
    const GEMINI_CHAT_ENDPOINT = `https://generativelanguage.googleapis.com/v1beta/models/${MODEL}:generateContent?key=${API_KEY}`;

    // Prompt模板,想改可以改。
    const getPrompt = (questionText, answersText) => {
        return `你是一个资深的 B 站答题专家。你只能告诉我最有可能正确的选项。不要提供任何解释或其他文本。问题: ${questionText};选项:${answersText}`
    }

    // 后面不用改了

    let lastQuestionText = ""; // 存储上一次的文本
    let isThrottled = false; // 节流标志


    // 防抖函数
    function debounce(func, delay) {
        let timeout;
        return function (...args) {
            clearTimeout(timeout);
            timeout = setTimeout(() => func.apply(this, args), delay);
        };
    }

    // 节流函数
    function throttle(func, limit) {
        return function (...args) {
            if (!isThrottled) {
                func.apply(this, args);
                isThrottled = true;
                setTimeout(() => {
                    isThrottled = false;
                }, limit);
            }
        };
    }

    // 创建一个观察者实例
    const observer = new MutationObserver((mutations) => {
        mutations.forEach(mutation => {
            if (mutation.type === 'childList') {
                // 重新获取所有带有 fade-out 类的 senior-question 元素
                const fadeOutQuestions = document.querySelectorAll('.senior-question.fade-out');

                fadeOutQuestions.forEach(question => {
                    // 获取问题文本
                    const questionText = question.querySelector('.senior-question__qs').innerText;

                    // 获取所有答案文本
                    const answerElements = question.querySelectorAll('.senior-question__answer .senior-question__answer--item');
                    const answersText = Array.from(answerElements).map(answer => answer.innerText);

                    // 防抖处理,创建或更新内容
                    // 使用 getPrompt() 生成最终发送给 API 的文本
                    createOrUpdateContent(getPrompt(questionText, answersText));
                });
            }
        });
    });

    // 创建或更新内容的函数
    const createOrUpdateContent = throttle(debounce((promptText) => {
        // 如果新的文本和上一次的文本相同,则不发送请求
        if (promptText === lastQuestionText) {
            return;
        }

        lastQuestionText = promptText; // 更新上一次的文本

        // 使用彩色输出问题文本
        console.log('%cPrompt: ' + promptText, 'font-weight: bold;');

        // 4. 发起 fetch 请求 (请求头和请求体已适配 Gemini API)
        fetch(GEMINI_CHAT_ENDPOINT, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
                // 注意:Google API Key 是通过 URL 参数传递,不需要 Authorization 头部
            },
            body: JSON.stringify({
                contents: [ // 使用 contents 替代 messages
                    {
                        role: 'user',
                        parts: [ // 使用 parts 替代 content
                            {
                                text: promptText
                            }
                        ]
                    }
                ]
            })
        })
            .then(response => {
                if (!response.ok) {
                    // 如果 API 返回错误,尝试解析错误信息
                    return response.json().then(err => {
                        console.error('API 错误详情:', err.error);
                        throw new Error(`网络响应错误,状态码: ${response.status}`);
                    });
                }
                return response.json();
            })
            .then(data => {
                // 5. 获取并处理响应中的内容 (适配 Gemini 响应结构)
                const content = data?.candidates?.[0]?.content?.parts?.[0]?.text || "未找到答案";

                // 使用彩色输出响应内容
                console.log('%c【Gemini 推荐选项】: ' + content, 'color: #34A853; font-weight: bold; font-size: 1.2em;');
            })
            .catch(error => {
                console.error('Fetch error:', error);
                console.log('%c请检查:1. 您的 API Key 是否正确;2. 您是否已启用该模型的 API 权限;3. 您的 API 是否被限流。', 'color: red;');
            });
    }, 1000), 2000); // 防抖延迟为 1000 毫秒,节流间隔为 2000 毫秒

    // 观察目标节点,配置观察选项
    const targetNode = document.body; // 你可以根据需要选择特定的父元素
    const config = { childList: true, subtree: true };

    // 开始观察
    observer.observe(targetNode, config);
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址