GPT4Free Page Summarizer (Local Free API)

Generate a summary of any webpage using a local instance of g4f

От 10.04.2025. Виж последната версия.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name         GPT4Free Page Summarizer (Local Free API)
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Generate a summary of any webpage using a local instance of g4f
// @author       SH3LL
// @match        *://*/*
// @grant        GM.xmlHttpRequest
// ==/UserScript==

function getPageText() {
    return document.body.innerText;
}

function summarizePage(pageText, language, maxLines, callback) {
    const apiUrl = 'http://localhost:1337/v1/chat/completions';
    const prompt = `Summarize the page in ${language} in max ${maxLines} lines, in a clear, concise and text organised in paragraphs.
                    Don't add any other sentence like "Here is the summary", write directly the summary itself.
                    Here is the text of the page: ${pageText}`;
    const data = {
        messages: [{
            role: 'user',
            content: prompt
        }],
        model: 'DeepSeek-V3',
        provider: 'Blackbox'
    };

    GM.xmlHttpRequest({
        method: 'POST',
        url: apiUrl,
        headers: {
            'Content-Type': 'application/json'
        },
        data: JSON.stringify(data),
        onload: function(response) {
            if (response.status >= 200 && response.status < 300) {
                try {
                    const jsonResponse = JSON.parse(response.responseText);
                    if (jsonResponse.choices && jsonResponse.choices[0].message && jsonResponse.choices[0].message.content) {
                        callback(null, jsonResponse.choices[0].message.content, response.status);
                    } else {
                        callback('Unexpected format of the API response.', null, response.status);
                    }
                } catch (error) {
                    callback('Error parsing the API response: ' + error, null, response.status);
                }
            } else {
                callback('Error in the API call: ' + response.status + ' ' + response.statusText, null, response.status);
            }
        },
        onerror: function(error) {
            callback('Network error during the API call: ' + error, null, null);
        }
    });
}

(function() {
    'use strict';

    const languageNames = new Intl.DisplayNames(['it'], { type: 'language' });
    const browserLanguage = navigator.language;
    const selectedLanguage = languageNames.of(browserLanguage);

    // Create the sidebar container
    const sidebar = document.createElement('div');
    sidebar.style.position = 'fixed';
    sidebar.style.right = '-300px';
    sidebar.style.top = '0';
    sidebar.style.width = '300px';
    sidebar.style.height = '100vh';
    sidebar.style.backgroundColor = '#000000';
    sidebar.style.color = '#ffffff';
    sidebar.style.padding = '20px';
    sidebar.style.zIndex = '9999';
    sidebar.style.fontFamily = 'Arial, sans-serif';
    sidebar.style.boxSizing = 'border-box';
    sidebar.style.display = 'flex';
    sidebar.style.flexDirection = 'column';
    sidebar.style.gap = '10px';
    sidebar.style.transition = 'right 0.3s ease';
    document.body.appendChild(sidebar);

    // Create the button to show/hide the sidebar
    const toggleButton = document.createElement('button');
    toggleButton.textContent = '>';
    toggleButton.style.position = 'fixed';
    toggleButton.style.right = '0';
    toggleButton.style.top = '20px';
    toggleButton.style.backgroundColor = '#000000';
    toggleButton.style.color = '#ffffff';
    toggleButton.style.border = 'none';
    toggleButton.style.padding = '10px';
    toggleButton.style.cursor = 'pointer';
    toggleButton.style.zIndex = '10000';
    toggleButton.style.fontSize = '14px';
    toggleButton.style.transition = 'right 0.3s ease';
    document.body.appendChild(toggleButton);

    // Create the container for the button and selector
    const buttonContainer = document.createElement('div');
    buttonContainer.style.display = 'flex';
    buttonContainer.style.gap = '10px';
    buttonContainer.style.alignItems = 'center';
    sidebar.appendChild(buttonContainer);

    // Create the summarize button
    const summarizeButton = document.createElement('button');
    summarizeButton.textContent = 'Summarize';
    summarizeButton.style.backgroundColor = '#ffffff';
    summarizeButton.style.color = '#000000';
    summarizeButton.style.border = 'none';
    summarizeButton.style.padding = '10px 20px';
    summarizeButton.style.cursor = 'pointer';
    summarizeButton.style.fontSize = '14px';
    summarizeButton.style.flex = '1';
    summarizeButton.style.transition = 'background-color 0.3s';
    summarizeButton.onmouseover = () => summarizeButton.style.backgroundColor = '#e0e0e0';
    summarizeButton.onmouseout = () => summarizeButton.style.backgroundColor = '#ffffff';
    buttonContainer.appendChild(summarizeButton);

    // Create the selector for the number of lines
    const linesSelector = document.createElement('select');
    linesSelector.style.backgroundColor = '#ffffff';
    linesSelector.style.color = '#000000';
    linesSelector.style.border = 'none';
    linesSelector.style.padding = '10px';
    linesSelector.style.fontSize = '14px';
    linesSelector.style.cursor = 'pointer';
    const lineOptions = [10, 15, 20, 25, 30, 50, 100];
    lineOptions.forEach(lines => {
        const option = document.createElement('option');
        option.value = lines;
        option.textContent = `${lines} lines`;
        if (lines === 10) option.selected = true; // Default to 10 lines
        linesSelector.appendChild(option);
    });
    buttonContainer.appendChild(linesSelector);

    // Create the API status display with detected language
    const statusDisplay = document.createElement('div');
    statusDisplay.style.fontSize = '12px';
    statusDisplay.style.color = '#888888';
    statusDisplay.textContent = `Status: Idle | Lang: ${selectedLanguage}`;
    sidebar.appendChild(statusDisplay);

    // Create the summary container
    const summaryContainer = document.createElement('div');
    summaryContainer.style.fontSize = '14px';
    summaryContainer.style.lineHeight = '1.5';
    summaryContainer.style.display = 'none';
    summaryContainer.style.overflowY = 'auto';
    summaryContainer.style.maxHeight = 'calc(100vh - 130px)'; // Adjusted space for the selector
    sidebar.appendChild(summaryContainer);

    // Handle sidebar visibility
    let isSidebarVisible = false;
    toggleButton.addEventListener('click', function() {
        if (isSidebarVisible) {
            sidebar.style.right = '-300px';
            toggleButton.style.right = '0';
            toggleButton.textContent = '>';
        } else {
            sidebar.style.right = '0';
            toggleButton.style.right = '300px';
            toggleButton.textContent = '<';
        }
        isSidebarVisible = !isSidebarVisible;
    });

    // Event listener for the summarize button
    summarizeButton.addEventListener('click', function() {
        summarizeButton.disabled = true;
        summarizeButton.textContent = 'Loading...';
        statusDisplay.textContent = `Status: Requesting... | Lang: ${selectedLanguage}`;
        summaryContainer.style.display = 'none';

        const pageText = getPageText();
        const maxLines = parseInt(linesSelector.value, 10); // Get the value from the selector
        summarizePage(pageText, selectedLanguage, maxLines, function(error, summary, statusCode) {
            summarizeButton.disabled = false;
            summarizeButton.textContent = 'Summarize Page';
            if (error) {
                summaryContainer.textContent = 'Error: ' + error;
                summaryContainer.style.color = '#ff4444';
                statusDisplay.textContent = `Status: Failed${statusCode ? ` (${statusCode})` : ''} | Lang: ${selectedLanguage}`;
                statusDisplay.style.color = '#ff4444';
            } else {
                summaryContainer.textContent = summary;
                summaryContainer.style.color = '#ffffff';
                statusDisplay.textContent = `Status: Success (${statusCode}) | Lang: ${selectedLanguage}`;
                statusDisplay.style.color = '#00ff00';
            }
            summaryContainer.style.display = 'block';
        });
    });
})();