Bing Search with Gemini

Bing 검색 결과 우측에 Gemini 결과를 마크다운 스타일로 표시

2025-02-27 يوللانغان نەشرى. ئەڭ يېڭى نەشرىنى كۆرۈش.

// ==UserScript==
// @name         Bing Search with Gemini
// @version      1.0
// @description  Bing 검색 결과 우측에 Gemini 결과를 마크다운 스타일로 표시
// @author       lanpod
// @match        https://www.bing.com/search*
// @grant        GM_addStyle
// @grant        GM_xmlhttpRequest
// @license      MIT
// @namespace http://tampermonkey.net/
// ==/UserScript==

(function() {
    'use strict';

    console.log('스크립트 실행 시작');

    function isMobile() {
        const ua = navigator.userAgent;
        return /Mobi|Android|iPhone|iPad/i.test(ua);
    }

    GM_addStyle(`
        #gemini-box {
            width: 100%;
            background: #fff;
            border: 1px solid #e0e0e0;
            box-shadow: 0 1px 3px rgba(0,0,0,0.1);
            overflow: auto;
            padding: 16px;
            margin-bottom: 20px;
            font-family: Arial, sans-serif;
            position: relative;
            z-index: 1000;
            display: block !important;
            min-height: 100px;
        }
        #gemini-header { display: flex; align-items: center; margin-bottom: 8px; }
        #gemini-logo { width: 24px; height: 24px; margin-right: 8px; }
        #gemini-box h3 { margin: 0; font-size: 18px; color: #202124; }
        #gemini-divider { border: 0; height: 1px; background: #e0e0e0; margin: 8px 0; }
        #gemini-content { font-size: 14px; line-height: 1.6; color: #333; }
        #gemini-content h1, #gemini-content h2, #gemini-content h3 { margin: 16px 0 8px; color: #202124; }
        #gemini-content h1 { font-size: 24px; }
        #gemini-content h2 { font-size: 20px; }
        #gemini-content h3 { font-size: 16px; }
        #gemini-content p { margin: 0 0 12px; }
        #gemini-content ul, #gemini-content ol { margin: 0 0 12px 20px; padding-left: 0; }
        #gemini-content li { margin: 4px 0; }
        #gemini-content code { background: #f1f3f4; padding: 2px 6px; border-radius: 4px; font-family: 'Courier New', monospace; }
        #gemini-content pre { background: #f1f3f4; padding: 12px; border-radius: 4px; overflow-x: auto; }
        #gemini-content strong { font-weight: bold; }
        #gemini-content em { font-style: italic; }
        #b_results > li a { font-weight: normal !important; color: #1a0dab !important; }
        #b_results > li a:visited { color: #660099 !important; }
        #b_results .b_ad a, .b_ad a { color: #008000 !important; }
    `);

    if (!isMobile()) {
        console.log('PC 환경 감지: Gemini 기능 활성화');

        const marked = (function() {
            function parse(text) {
                text = text
                    .replace(/^### (.*$)/gm, '<h3>$1</h3>')
                    .replace(/^## (.*$)/gm, '<h2>$1</h2>')
                    .replace(/^# (.*$)/gm, '<h1>$1</h1>')
                    .replace(/^\* (.*$)/gm, '<li>$1</li>')
                    .replace(/^- (.*$)/gm, '<li>$1</li>')
                    .replace(/```(.*?)```/gs, '<pre><code>$1</code></pre>')
                    .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
                    .replace(/(?<!\*)\*(?!\*)(.*?)(?<!\*)\*(?!\*)/g, '<em>$1</em>')
                    .replace(/\n/g, '<br>');
                return '<p>' + text + '</p>';
            }
            return { parse: parse };
        })();

        let apiKey = localStorage.getItem('geminiApiKey');
        if (!apiKey) {
            apiKey = prompt('Gemini API 키를 입력하세요 (Google AI Studio에서 발급):');
            if (apiKey) localStorage.setItem('geminiApiKey', apiKey);
        }
        console.log('API 키 확인:', apiKey ? '설정됨' : '없음');

        function createGeminiBox() {
            const box = document.createElement('div');
            box.id = 'gemini-box';
            box.innerHTML = `
                <div id="gemini-header">
                    <img id="gemini-logo" src="https://i.namu.wiki/i/sJQlY6ZVq4au-2hUjZC7z89rPkepG8bSMWdGSYgVoDxwoGc4ovzEU26Wk7E8wptmwAxmMZdUV00mLqVR-nqsYw.svg" alt="Gemini Logo">
                    <h3>Gemini 검색 결과</h3>
                </div>
                <hr id="gemini-divider">
                <div id="gemini-content">검색 쿼리를 기다리는 중...</div>
            `;
            return box;
        }

        let currentQuery = null;
        function fetchGeminiResult(query) {
            const requestQuery = query; // 요청 시점의 쿼리 저장
            document.getElementById('gemini-content').innerText = '로딩 중...'; // 즉시 초기화
            const url = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=' + apiKey;
            GM_xmlhttpRequest({
                method: 'POST',
                url: url,
                headers: { 'Content-Type': 'application/json' },
                data: JSON.stringify({
                    contents: [{ parts: [{ text: `다음 검색 쿼리에 대해 최대한 자세한 정보를 찾아줘: "${query}" (마크다운 형식으로 작성해줘)` }] }]
                }),
                onload: function(response) {
                    if (requestQuery !== currentQuery) {
                        console.log(`[${requestQuery}] 응답 무시: 현재 쿼리 [${currentQuery}]와 다름`);
                        return; // 현재 쿼리와 다르면 무시
                    }
                    console.log('Gemini API 원시 응답:', response.responseText);
                    try {
                        const result = JSON.parse(response.responseText);
                        const content = result.candidates?.[0]?.content?.parts?.[0]?.text;
                        if (content) {
                            console.log('마크다운 텍스트:', content);
                            document.getElementById('gemini-content').innerHTML = marked.parse(content);
                            console.log('마크다운 렌더링 완료');
                        } else {
                            document.getElementById('gemini-content').innerText = 'Gemini 응답이 유효하지 않음';
                        }
                    } catch (e) {
                        console.error('API 응답 파싱 오류:', e);
                        document.getElementById('gemini-content').innerText = '응답 처리 오류';
                    }
                },
                onerror: function(error) {
                    console.error('API 요청 오류:', error);
                    if (requestQuery === currentQuery) {
                        document.getElementById('gemini-content').innerText = 'API 호출 실패';
                    }
                }
            });
        }

        function ensureGeminiBox() {
            const query = new URLSearchParams(window.location.search).get('q') || 'No query found';
            if (query === currentQuery) return; // 동일 쿼리면 중복 실행 방지
            currentQuery = query;
            console.log('검색 쿼리:', query);

            let box = document.getElementById('gemini-box');
            const contextArea = document.getElementById('b_context');
            if (!contextArea) {
                console.warn('#b_context 없음, 대기 중');
                return;
            }
            if (!box || !contextArea.contains(box)) {
                if (box) box.remove(); // 기존 박스 제거
                box = createGeminiBox();
                contextArea.insertBefore(box, contextArea.firstChild);
                console.log('Gemini 박스가 #b_context에 추가됨');
            } else {
                console.log('Gemini 박스 이미 존재, 재사용');
                document.getElementById('gemini-content').innerText = '검색 쿼리를 기다리는 중...'; // 재사용 시 초기화
            }

            if (apiKey) fetchGeminiResult(query);
            else document.getElementById('gemini-content').innerText = 'API 키 없음';
        }

        const observer = new MutationObserver(() => {
            ensureGeminiBox();
            const box = document.getElementById('gemini-box');
            if (box && box.style.display === 'none') {
                box.style.display = 'block';
                console.log('Gemini 박스 강제로 표시');
            }
        });
        observer.observe(document.body, { childList: true, subtree: true });
        ensureGeminiBox(); // 초기 실행
    } else {
        console.log('모바일 환경 감지: Gemini 기능 비활성화');
    }
})();
长期地址
遇到问题?请前往 GitHub 提 Issues,或加Q群1031348184

赞助商

Fishcpy

广告

Rainyun

注册一下就行

Rainyun

一年攒够 12 元