Greasy Fork

来自缓存

Greasy Fork is available in English.

妖火帖子AI总结(太长不看)

调用OpenAI或其他支持completions功能API对妖火论坛帖子内容及评论进行摘要总结,并提供回帖建议

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         妖火帖子AI总结(太长不看)
// @namespace    https://www.yaohuo.me/bbs/userinfo.aspx?touserid=20740
// @version      1.9.99
// @description  调用OpenAI或其他支持completions功能API对妖火论坛帖子内容及评论进行摘要总结,并提供回帖建议
// @author       SiXi
// @match        https://www.yaohuo.me/bbs*
// @match        https://yaohuo.me/bbs*
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @icon         https://www.yaohuo.me/css/favicon.ico
// @license      Apache 2
// @require      https://code.jquery.com/jquery-3.6.0.min.js
// ==/UserScript==

(function() {
    'use strict';

    // 用户配置参数
    const OPENAI_BASE_URL = 'https://api.gptgod.online/v1/chat/completions';  //模型的base_url,需要使用支持completions功能的url
    const OPENAI_API_KEY = 'sk-XXXXXXXXXXXX';  //密钥
    const OPENAI_MODEL = 'glm-4-flash';  //模型名称,火山方舟申请的模型是填'推理接入点'名称,ep开头那个

    // 创建按钮并插入页面
    $(document).ready(function() {
        $('.Postinfo .Postime').each(function() {
            const postInfo = $(this).closest('.Postinfo');
            const button = $('<button class="ai-summary-btn">AI总结</button>')
                .css({
                    'padding': '5px 10px',
                    'background-color': '#4CAF50',
                    'color': 'white',
                    'border': 'none',
                    'border-radius': '5px',
                    'cursor': 'pointer'
                })
                .insertAfter(postInfo.find('.Postime'))
                .on('click', function() {
                    handleButtonClick($(this), postInfo);
                });
        });
    });

    // 获取评论内容
    function getComments() {
        const comments = [];
        $('.recontent .retext').each(function() {
            const commentText = $(this).text().trim();
            if (commentText && !$(this).closest('.quoted-content').length) {
                comments.push(commentText);
            }
        });
        return comments;
    }

    // 处理按钮点击事件
    function handleButtonClick(button, postInfo) {
        button.prop('disabled', true).text('AI阅读中...');

        const title = postInfo.find('.biaotiwenzi').text().trim();
        if (!title) {
            alert("未找到帖子标题!");
            button.prop('disabled', false).text('AI总结');
            return;
        }

        const content = postInfo.closest('.content').find('.bbscontent').text().trim();
        if (!content) {
            alert("未找到帖子内容!");
            button.prop('disabled', false).text('AI总结');
            return;
        }

        const comments = getComments();

        const fullContent = `帖子标题:${title}\n\n原帖内容:\n${content}\n\n评论区内容:\n\n${comments.map((comment, index) => `${index + 1}. ${comment}`).join('\n')}`;

        fetchSummaryAndReplies(fullContent, button);
    }

    function fetchSummaryAndReplies(content, button) {
        GM_xmlhttpRequest({
            method: 'POST',
            url: `${OPENAI_BASE_URL}`,
            headers: {
                'Authorization': `Bearer ${OPENAI_API_KEY}`,
                'Content-Type': 'application/json'
            },
            data: JSON.stringify({
                model: OPENAI_MODEL,
                messages: [
                    {
                        role: "system",
                        content: "你是妖火网论坛的用户。请分别总结原帖内容和评论区的主要观点。原帖内容用1-3句话总结,评论区的观点用1-2句话总结。总结内容用'原帖内容'和'妖友观点'前缀进行回复。同时,请根据原帖内容和评论区的讨论,生成5条适合的回帖内容,尽可能贴近评论区的观点,模仿他们的语气,使用口语化,用'回帖内容'前缀进行回复。"
                    },
                    {
                        role: "user",
                        content: `请总结:\n\n${content}`
                    }
                ],
                stream: false
            }),
            onload: function(response) {
                try {
                    const result = JSON.parse(response.responseText);
                    let summary = result.choices[0].message.content.trim();
                    summary = summary.replace("妖友观点:", "<hr>妖友观点:");

                    // 回帖内容解析
                    let replies = [];

                    const pattern1 = /回帖内容:\s*((?:\d+\.\s*[^\n]+\n*)+)/;
                    const match1 = summary.match(pattern1);

                    if (match1) {
                        replies = match1[1].split(/\d+\./).filter(reply => reply.trim());
                    } else {
                        replies = summary.match(/回帖内容\d+:[^\n]+/g);
                        if (replies) {
                            replies = replies.map(reply => reply.replace(/回帖内容\d+:/, '').trim());
                        }
                    }

                    const summaryParts = summary.split(/回帖内容[:\d]/)[0].trim();
                    const subtitleElement = $('<div class="subtitle content welcome"></div>');
                    subtitleElement.html(summaryParts);
                    $('.Postinfo').after(subtitleElement);

                    // 显示回帖建议
                    if (replies && replies.length > 0) {
                        showReplySuggestions(replies);
                    }

                    button.prop('disabled', false).text('AI总结');
                } catch (error) {
                    console.error("解析AI响应失败:", error);
                    showErrorPopup("请求失败,请稍后再试。");
                    button.prop('disabled', false).text('AI总结');
                }
            },
            onerror: function(error) {
                console.error("请求失败:", error);
                showErrorPopup("网络请求失败,请检查您的网络连接。");
                button.prop('disabled', false).text('AI总结');
            }
        });
    }

    // 显示回帖建议
    function showReplySuggestions(replies) {
        // 首先移除旧的建议(如果存在)
        $('.reply-suggestions-container').remove();

        const replyContainer = $('<div class="content"></div>')
            .insertAfter('.kuaisuhuifu');

        replies.forEach(reply => {
            const replySpan = $('<div class="reply-suggestion"></div>')
                .css({
                    'padding': '1px 1px 1px 7px',
                    'margin': '5px 0',
                    'background-color': '#f5f5f5',
                    'border-radius': '4px',
                    'cursor': 'pointer',
                    'transition': 'background-color 0.2s'
                })
                .hover(
                    function() { $(this).css('background-color', '#e0e0e0'); },
                    function() { $(this).css('background-color', '#f5f5f5'); }
                )
                .text(reply.trim())
                .on('click', function() {
                    $('.retextarea').val($(this).text());
                })
                .appendTo(replyContainer);
        });
    }

    // 显示错误提示浮窗
    function showErrorPopup(message) {
        const popup = $('<div class="ai-error-popup"></div>')
            .css({
                'position': 'fixed',
                'top': '50%',
                'left': '50%',
                'transform': 'translate(-50%, -50%)',
                'background-color': 'rgba(255,0,0,0.7)',
                'color': 'white',
                'padding': '20px',
                'border-radius': '10px',
                'z-index': '10000'
            })
            .html(`<p>${message}</p><button class="ai-error-close-btn">X</button>`)
            .appendTo('body');

        popup.find('.ai-error-close-btn').on('click', function() {
            popup.remove();
        });
    }
})();