deai prompt generator

with.isとpairs.lvとmarrish.comのユーザーページにコピーボタンを追加し、AI対話プロンプトを生成します。marrish.comのチャットページでメッセージをコピーできます。

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         deai prompt generator
// @namespace    http://tampermonkey.net/
// @version      1.0.8
// @description  with.isとpairs.lvとmarrish.comのユーザーページにコピーボタンを追加し、AI対話プロンプトを生成します。marrish.comのチャットページでメッセージをコピーできます。
// @author       Your Name
// @match        https://with.is/users/*
// @match        https://pairs.lv/*
// @match        https://marrish.com/profile/detail/partner/*
// @match        https://marrish.com/message/index/*
// @grant        GM_setClipboard
// @license      MIT
// @supportURL   https://github.com/thelastfantasy/with-profile-copy/issues
// ==/UserScript==

"use strict";
(function () {
    "use strict";
    let lastUrl = window.location.href;
    let pairsObserver = null;
    let isAddingPairsButton = false;
    const CONFIG = {
        MESSAGE_DISPLAY_TIME: 3000,
        PAIRS_MODAL_TIMEOUT: 10000,
    };
    const COMMON_FOOTER = "以上情報常に忘れず、相手と会話で送るメッセージを提案してみてください。提案するメッセージには非常用の絵文字を使わず、あまり堅苦しくなく、失礼にならない程度のカジュアルな表現でお願いします。\n生成されたメッセージ内容はなるべくAIぽくない、相手のメッセージ内容を重複しない、自然な日本語で、emojiはよく使うやつに限定、「」などの記号を控えるようにお願いします。";
    const TEMPLATES = {
        WITH_IS: {
            header: "with.isで以下ユーザーとマッチしました。相手の情報は以下になります",
            nickname: "ユーザー名",
            age: "年齢",
            location: "居住地",
            introduction: "自己紹介文",
            additional: "俺との共通点",
            basicInfo: "相手の基本情報",
            footer: COMMON_FOOTER,
        },
        PAIRS: {
            header: "pairs.lvで以下ユーザーとマッチしました。相手の情報は以下になります",
            nickname: "ユーザー名",
            age: "年齢",
            location: "居住地",
            introduction: "自己紹介",
            additional: "マイタグ",
            pairsQuestions: "ペアーズクエスチョン",
            basicInfo: "相手の基本情報",
            footer: COMMON_FOOTER,
        },
        MARRISH: {
            header: "marrish.comで以下ユーザーとマッチしました。相手の情報は以下になります",
            nickname: "ユーザー名",
            age: "年齢",
            location: "居住地",
            introduction: "自己PR",
            additional: "参加グループ",
            basicInfo: "相手の基本情報",
            footer: COMMON_FOOTER,
        },
    };
    const CSS_SELECTORS = {
        WITH_IS: {
            NICKNAME: ".profile_main-nickname",
            AGE_ADDRESS: ".profile_main-age-address",
            INTRODUCTION: ".profile-introduction",
            COMMON_POINTS: ".profile-affinities_list.on-user-detail li",
            BASIC_INFO_TABLE: ".profile-detail table",
            BASIC_INFO_ROW: "tr",
            BASIC_INFO_HEADER: "th",
            BASIC_INFO_DATA: "td",
        },
        PAIRS: {
            ROOT: "#dialog-root",
            BUTTON_INSERT: "#dialog-root > div > div > div > div:nth-child(2) > div > div > div:nth-child(3) > div:nth-child(1) > div > div:nth-child(1) > div:nth-child(3) > p",
        },
        MARRISH: {
            BASE_INFO: ".as-profile__baseinfo-pc",
            NAME: ".as-profile__name",
            AGE: ".as-profile__age",
            AREA: ".as-profile__area",
            GROUP_LIST: ".as-prof-group-list",
            GROUP_ITEMS: ".as-prof-group-list__item",
            GROUP_TITLE: ".as-prof-group-list__title",
            GROUP_MEMBER: ".as-prof-group-list__member",
            SELF_PR: ".as-profile-text-contents",
            DETAIL_WRAP: ".as-profile-detail-wrap",
            DETAIL_GROUP: ".as-profile-detail-item-group",
            DETAIL_SUB_TITLE: ".as-profile-detail-sub-title",
            DETAIL_ITEM: ".as-profile-detail-item",
            DETAIL_ITEM_TITLE: ".as-profile-detail-item-title",
            DETAIL_ITEM_DATE: ".as-profile-detail-item-date",
            MOBILE_ONLINE_INFO: ".as-prof-info__online",
            MOBILE_LIKE_COUNT: ".as-prof-like-count",
            MOBILE_BASE_INFO: ".as-prof-info__base",
            MOBILE_NAME: ".as-prof-info__name",
            MOBILE_AGE: ".as-prof-info__age",
            MOBILE_AREA: ".as-prof-info__area",
            MESSAGE_BUBBLE: ".yi-message-form-text-body-bg1, .yi-message-form-text-body-bg1-me",
            MESSAGE_CONTENT: "p",
            SPEAKER_NAME: ".yi-message-form-phone_head_name_textover",
        },
    };
    if (document.readyState === "loading") {
        document.addEventListener("DOMContentLoaded", init);
    }
    else {
        init();
    }
    window.addEventListener("hashchange", handleRouteChange);
    window.addEventListener("popstate", handleRouteChange);
    const originalPushState = history.pushState;
    const originalReplaceState = history.replaceState;
    history.pushState = function (...args) {
        originalPushState.apply(this, args);
        handleRouteChange();
    };
    history.replaceState = function (...args) {
        originalReplaceState.apply(this, args);
        handleRouteChange();
    };
    function isPairsUserPage(url = window.location.href) {
        return url.includes("pairs.lv/message/detail/");
    }
    function handleRouteChange() {
        const currentUrl = window.location.href;
        if (currentUrl !== lastUrl) {
            lastUrl = currentUrl;
            console.log("URL changed, checking for all supported pages...");
            if (currentUrl.includes("with.is/users/")) {
                addCopyButton("WITH_IS");
            }
            else if (isPairsUserPage(currentUrl)) {
                if (pairsObserver) {
                    pairsObserver.disconnect();
                    pairsObserver = null;
                }
                waitForPairsModal();
            }
            else if (currentUrl.includes("marrish.com/profile/detail/partner/")) {
                waitForMarrishBaseInfo();
            }
            else if (currentUrl.includes("marrish.com/message/index/")) {
                waitForMarrishMessages();
            }
        }
    }
    function init() {
        console.log("脚本初始化,当前URL:", window.location.href);
        console.log("isPairsUserPage() 结果:", isPairsUserPage());
        if (window.location.href.includes("with.is/users/")) {
            console.log("检测到with.is页面");
            addCopyButton("WITH_IS");
        }
        else if (isPairsUserPage()) {
            console.log("检测到pairs.lv页面,执行pairs.lv逻辑");
            waitForPairsModal();
        }
        else if (window.location.href.includes("marrish.com/profile/detail/partner/")) {
            console.log("检测到marrish.com页面,执行marrish.com逻辑");
            waitForMarrishBaseInfo();
        }
        else if (window.location.href.includes("marrish.com/message/index/")) {
            console.log("检测到marrish.com聊天页面,执行聊天逻辑");
            waitForMarrishMessages();
        }
        else {
            console.log("未匹配到支持的页面类型");
            return;
        }
    }
    function waitForPairsModal() {
        console.log("等待pairs.lv模态框加载...");
        if (tryAddPairsButton()) {
            return;
        }
        if (pairsObserver) {
            pairsObserver.disconnect();
            pairsObserver = null;
        }
        pairsObserver = new MutationObserver((mutations) => {
            for (const mutation of mutations) {
                if (mutation.type === "childList") {
                    const dialogRoot = document.querySelector(CSS_SELECTORS.PAIRS.ROOT);
                    if (dialogRoot && tryAddPairsButton()) {
                        console.log("pairs.lv模态框已加载,按钮已添加");
                        if (pairsObserver) {
                            pairsObserver.disconnect();
                            pairsObserver = null;
                        }
                        return;
                    }
                }
            }
        });
        pairsObserver.observe(document.body, {
            childList: true,
            subtree: true,
        });
        setTimeout(() => {
            if (pairsObserver) {
                pairsObserver.disconnect();
                pairsObserver = null;
                console.log("pairs.lv模态框加载超时");
            }
        }, CONFIG.PAIRS_MODAL_TIMEOUT);
    }
    function tryAddPairsButton() {
        if (isAddingPairsButton) {
            return false;
        }
        isAddingPairsButton = true;
        try {
            const buttonContainer = document.querySelector(CSS_SELECTORS.PAIRS.BUTTON_INSERT);
            if (buttonContainer) {
                const existingButton = buttonContainer.parentNode?.querySelector('button[style*="background: #007bff"]');
                if (!existingButton) {
                    addCopyButton("PAIRS");
                    return true;
                }
                else {
                    console.log("按钮已存在,跳过重复添加");
                    return true;
                }
            }
            return false;
        }
        finally {
            isAddingPairsButton = false;
        }
    }
    function waitForMarrishBaseInfo() {
        console.log("等待marrish.com基本信息区域加载...");
        if (tryAddMarrishButton()) {
            return;
        }
        const observer = new MutationObserver((mutations) => {
            for (const mutation of mutations) {
                if (mutation.type === "childList") {
                    if (tryAddMarrishButton()) {
                        observer.disconnect();
                        console.log("marrish.com基本信息区域已加载,按钮已添加");
                        return;
                    }
                }
            }
        });
        observer.observe(document.body, {
            childList: true,
            subtree: true,
        });
        setTimeout(() => {
            observer.disconnect();
            console.log("marrish.com基本信息区域加载超时");
        }, CONFIG.PAIRS_MODAL_TIMEOUT);
    }
    function tryAddMarrishButton() {
        const pcButtonContainer = document.querySelector(CSS_SELECTORS.MARRISH.AREA);
        if (pcButtonContainer) {
            console.log("检测到PC版marrish.com,在居住地后面添加按钮");
            addCopyButton("MARRISH");
            return true;
        }
        const mobileLikeCount = document.querySelector(CSS_SELECTORS.MARRISH.MOBILE_LIKE_COUNT);
        if (mobileLikeCount) {
            console.log("检测到手机版marrish.com,在点赞数元素后面添加按钮");
            addCopyButton("MARRISH");
            return true;
        }
        return false;
    }
    function waitForMarrishMessages() {
        console.log("等待marrish.com聊天消息加载...");
        if (tryAddMessageButtons()) {
            addCopyAllChatButton();
            return;
        }
        const observer = new MutationObserver((mutations) => {
            for (const mutation of mutations) {
                if (mutation.type === "childList") {
                    if (tryAddMessageButtons()) {
                        console.log("marrish.com聊天消息已加载,按钮已添加");
                        addCopyAllChatButton();
                    }
                }
            }
        });
        observer.observe(document.body, {
            childList: true,
            subtree: true,
        });
    }
    function tryAddMessageButtons() {
        const messageBubbles = document.querySelectorAll(CSS_SELECTORS.MARRISH.MESSAGE_BUBBLE);
        let addedButtons = false;
        messageBubbles.forEach((bubble) => {
            if (!bubble.querySelector(".message-copy-button")) {
                addMessageCopyButton(bubble);
                addedButtons = true;
            }
        });
        return addedButtons;
    }
    function addMessageCopyButton(bubble) {
        const copyButton = document.createElement("button");
        copyButton.textContent = "📋";
        copyButton.className = "message-copy-button";
        copyButton.style.cssText = `
            position: absolute;
            top: 5px;
            left: 5px;
            padding: 2px 6px;
            background: rgba(0, 123, 255, 0.8);
            color: white;
            border: none;
            border-radius: 3px;
            cursor: pointer;
            font-size: 10px;
            z-index: 10;
            opacity: 0.7;
            transition: opacity 0.2s;
        `;
        copyButton.addEventListener("mouseenter", () => {
            copyButton.style.opacity = "1";
        });
        copyButton.addEventListener("mouseleave", () => {
            copyButton.style.opacity = "0.7";
        });
        copyButton.addEventListener("click", (e) => {
            e.stopPropagation();
            copyMessageContent(bubble);
        });
        if (getComputedStyle(bubble).position === "static") {
            bubble.style.position = "relative";
        }
        bubble.appendChild(copyButton);
    }
    function copyMessageContent(bubble) {
        try {
            const messageContent = bubble.querySelector(CSS_SELECTORS.MARRISH.MESSAGE_CONTENT);
            if (messageContent) {
                const htmlContent = messageContent.innerHTML;
                const textContent = htmlContent
                    .replace(/<br\s*\/?>/gi, "\n")
                    .replace(/<[^>]*>/g, "")
                    .replace(/\n{3,}/g, "\n\n")
                    .trim();
                const speakerNameElement = document.querySelector(CSS_SELECTORS.MARRISH.SPEAKER_NAME);
                let speakerName = "見つかりません";
                if (speakerNameElement) {
                    speakerName =
                        speakerNameElement.textContent?.trim() || "見つかりません";
                }
                const isMyMessage = bubble.classList.contains("yi-message-form-text-body-bg1-me");
                const speakerPrefix = isMyMessage ? "俺" : speakerName;
                const formattedContent = `${speakerPrefix}:\n${textContent}`;
                GM_setClipboard(formattedContent, "text");
                showMessage("✅ メッセージをコピーしました!", "success");
            }
            else {
                showMessage("❌ メッセージ内容が見つかりません", "error");
            }
        }
        catch (error) {
            console.error("メッセージコピーに失敗しました:", error);
            showMessage("❌ コピーに失敗しました", "error");
        }
    }
    function addCopyAllChatButton() {
        const readUnreadButton = document.getElementById("read_unread_func_off");
        if (!readUnreadButton) {
            console.log("既読機能OFF按钮が見つかりません");
            return;
        }
        if (readUnreadButton.parentNode?.querySelector(".copy-all-chat-button")) {
            return;
        }
        const copyAllButton = document.createElement("button");
        copyAllButton.textContent = "📋 チャット履歴をコピー";
        copyAllButton.className = "copy-all-chat-button";
        copyAllButton.style.cssText = `
            margin-right: 10px;
            padding: 6px 12px;
            background: #28a745;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 12px;
        `;
        copyAllButton.addEventListener("click", copyAllChatHistory);
        readUnreadButton.parentNode?.insertBefore(copyAllButton, readUnreadButton);
    }
    function copyAllChatHistory() {
        try {
            const messageBubbles = document.querySelectorAll(CSS_SELECTORS.MARRISH.MESSAGE_BUBBLE);
            if (messageBubbles.length === 0) {
                showMessage("❌ チャット履歴が見つかりません", "error");
                return;
            }
            const speakerNameElement = document.querySelector(CSS_SELECTORS.MARRISH.SPEAKER_NAME);
            const speakerName = speakerNameElement?.textContent?.trim() || "相手";
            const messages = [];
            messages.push("チャット履歴");
            messageBubbles.forEach((bubble) => {
                const messageContent = bubble.querySelector(CSS_SELECTORS.MARRISH.MESSAGE_CONTENT);
                if (messageContent) {
                    const htmlContent = messageContent.innerHTML;
                    const textContent = htmlContent
                        .replace(/<br\s*\/?>/gi, "\n")
                        .replace(/<[^>]*>/g, "")
                        .replace(/\n{3,}/g, "\n\n")
                        .trim();
                    const isMyMessage = bubble.classList.contains("yi-message-form-text-body-bg1-me");
                    const speakerPrefix = isMyMessage ? "俺" : speakerName;
                    messages.push(`${speakerPrefix}:`);
                    messages.push(textContent);
                    messages.push("");
                }
            });
            const fullChatHistory = messages.join("\n").trim();
            GM_setClipboard(fullChatHistory, "text");
            showMessage("✅ チャット履歴をコピーしました!", "success");
        }
        catch (error) {
            console.error("チャット履歴コピーに失敗しました:", error);
            showMessage("❌ チャット履歴のコピーに失敗しました", "error");
        }
    }
    function addCopyButton(site) {
        let buttonContainer = null;
        let buttonText = "📋 ユーザー情報をコピー";
        if (site === "WITH_IS") {
            buttonContainer = document.querySelector(CSS_SELECTORS.WITH_IS.NICKNAME);
        }
        else if (site === "PAIRS") {
            buttonContainer = document.querySelector(CSS_SELECTORS.PAIRS.BUTTON_INSERT);
            buttonText = "📋 プロフィールをコピー";
        }
        else if (site === "MARRISH") {
            buttonContainer = document.querySelector(CSS_SELECTORS.MARRISH.AREA);
            if (!buttonContainer) {
                buttonContainer = document.querySelector(CSS_SELECTORS.MARRISH.MOBILE_LIKE_COUNT);
            }
            buttonText = "📋 プロフィールをコピー";
        }
        if (!buttonContainer) {
            console.log("ボタン追加位置が見つかりません:", site, "selector:", site === "WITH_IS"
                ? CSS_SELECTORS.WITH_IS.NICKNAME
                : site === "PAIRS"
                    ? CSS_SELECTORS.PAIRS.BUTTON_INSERT
                    : CSS_SELECTORS.MARRISH.AREA);
            return;
        }
        createCopyButton(buttonContainer, buttonText);
    }
    function createCopyButton(container, buttonText) {
        const copyButton = document.createElement("button");
        copyButton.textContent = buttonText;
        copyButton.style.cssText = `
            margin-left: 10px;
            padding: 4px 8px;
            background: #007bff;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 12px;
        `;
        copyButton.addEventListener("click", handleCopy);
        container.parentNode?.insertBefore(copyButton, container.nextSibling);
    }
    function handleCopy() {
        try {
            const userData = extractUserData();
            const promptText = generatePrompt(userData);
            GM_setClipboard(promptText, "text");
            showMessage("✅ ユーザー情報をクリップボードにコピーしました!", "success");
        }
        catch (error) {
            console.error("コピーに失敗しました:", error);
            showMessage("❌ コピーに失敗しました。コンソールを確認してください", "error");
        }
    }
    function extractUserData() {
        let selectors;
        let site = "WITH_IS";
        if (window.location.href.includes("with.is/users/")) {
            selectors = CSS_SELECTORS.WITH_IS;
            site = "WITH_IS";
        }
        else if (isPairsUserPage()) {
            selectors = CSS_SELECTORS.PAIRS;
            site = "PAIRS";
        }
        else if (window.location.href.includes("marrish.com/profile/detail/partner/")) {
            selectors = CSS_SELECTORS.MARRISH;
            site = "MARRISH";
            const mobileBaseInfo = document.querySelector(CSS_SELECTORS.MARRISH.MOBILE_BASE_INFO);
            if (mobileBaseInfo) {
                console.log("检测到移动版marrish.com,使用移动版数据提取");
                return extractMarrishMobileData(selectors);
            }
            else {
                console.log("检测到PC版marrish.com,使用PC版数据提取");
                return extractMarrishData(selectors);
            }
        }
        else {
            throw new Error("サポートされていないサイトです");
        }
        if (site === "WITH_IS") {
            return extractWithIsData(selectors);
        }
        else if (site === "PAIRS") {
            return extractPairsData(selectors);
        }
        else {
            return extractMarrishData(selectors);
        }
    }
    function extractWithIsData(selectors) {
        const nickname = document.querySelector(selectors.NICKNAME)?.textContent?.trim() ||
            "見つかりません";
        const ageAddressElement = document.querySelector(selectors.AGE_ADDRESS);
        let age = "見つかりません";
        let location = "見つかりません";
        if (ageAddressElement) {
            const text = ageAddressElement.textContent?.trim() || "";
            const parts = text.split("\n").filter((part) => part.trim());
            if (parts.length >= 1)
                age = parts[0].trim();
            if (parts.length >= 2)
                location = parts[1].trim();
        }
        let introduction = document.querySelector(selectors.INTRODUCTION)?.textContent?.trim() ||
            "見つかりません";
        if (introduction.startsWith("自己紹介文")) {
            introduction = introduction.replace(/^自己紹介文\s*/, "");
        }
        const commonPoints = [];
        const commonPointElements = document.querySelectorAll(selectors.COMMON_POINTS);
        commonPointElements.forEach((el) => {
            const text = el.textContent?.trim();
            if (text)
                commonPoints.push(text);
        });
        const basicInfo = {};
        const basicInfoTable = document.querySelector(selectors.BASIC_INFO_TABLE);
        if (basicInfoTable) {
            const rows = basicInfoTable.querySelectorAll(selectors.BASIC_INFO_ROW);
            rows.forEach((row) => {
                const th = row
                    .querySelector(selectors.BASIC_INFO_HEADER)
                    ?.textContent?.trim();
                const td = row
                    .querySelector(selectors.BASIC_INFO_DATA)
                    ?.textContent?.trim();
                if (th && td) {
                    basicInfo[th] = td;
                }
            });
        }
        return {
            nickname,
            age,
            location,
            introduction,
            commonPoints,
            basicInfo,
            site: "WITH_IS",
        };
    }
    function extractBasicInfoFromProfile(dialogRoot) {
        const basicInfo = {};
        const profileH2 = Array.from(dialogRoot.querySelectorAll("h2")).find((h2) => h2.textContent?.includes("プロフィール"));
        if (profileH2) {
            let profileContainer = profileH2.parentElement;
            if (profileContainer) {
                const allDlElements = profileContainer.querySelectorAll("dl");
                if (allDlElements.length > 0) {
                    allDlElements.forEach((dl) => {
                        const dtElements = dl.querySelectorAll("dt");
                        const ddElements = dl.querySelectorAll("dd");
                        dtElements.forEach((dt, index) => {
                            const key = dt.textContent?.trim();
                            const value = ddElements[index]?.textContent?.trim();
                            if (key && value) {
                                basicInfo[key] = value;
                            }
                        });
                    });
                }
            }
        }
        return basicInfo;
    }
    function extractPairsData(selectors) {
        const dialogRoot = document.querySelector(selectors.ROOT);
        if (!dialogRoot) {
            console.log("未找到#dialog-root容器");
            return {
                nickname: "見つかりません",
                age: "見つかりません",
                location: "見つかりません",
                introduction: "見つかりません",
                myTags: [],
                pairsQuestions: [],
                basicInfo: {},
                site: "PAIRS",
            };
        }
        let nickname = "見つかりません";
        const nameElements = dialogRoot.querySelectorAll("p, span, h1, h2, h3, div");
        for (const element of nameElements) {
            const text = element.textContent?.trim();
            if (text &&
                text.length > 0 &&
                text.length < 30 &&
                !text.includes("歳") &&
                !text.includes("自己紹介") &&
                !text.includes("マイタグ") &&
                !text.includes("プロフィール") &&
                !text.includes("新着のお相手") &&
                !text.includes("お相手詳細") &&
                !text.includes("本人確認済み") &&
                !text.includes("プロフィールをコピー") &&
                !text.includes("前の写真") &&
                !text.includes("次の写真") &&
                !text.includes("いいね!")) {
                nickname = text;
                break;
            }
        }
        if (nickname === "見つかりません") {
            const marinaElements = dialogRoot.querySelectorAll("*");
            for (const element of marinaElements) {
                const text = element.textContent?.trim();
                if (text && text.includes("marina")) {
                    nickname = "marina";
                    break;
                }
            }
        }
        if (nickname === "見つかりません") {
            const profileBasicInfo = extractBasicInfoFromProfile(dialogRoot);
            if (profileBasicInfo["ニックネーム"]) {
                nickname = profileBasicInfo["ニックネーム"];
            }
        }
        let age = "見つかりません";
        let location = "見つかりません";
        const profileBasicInfo = extractBasicInfoFromProfile(dialogRoot);
        if (profileBasicInfo["年齢"])
            age = profileBasicInfo["年齢"];
        if (profileBasicInfo["居住地"])
            location = profileBasicInfo["居住地"];
        if (age === "見つかりません" || location === "見つかりません") {
            const allElements = dialogRoot.querySelectorAll("*");
            for (const element of allElements) {
                const text = element.textContent?.trim();
                if (text && text.includes("歳")) {
                    const cleanText = text
                        .replace(/[\n\r]/g, " ")
                        .replace(/\s+/g, " ")
                        .trim();
                    const parts = cleanText
                        .split(" ")
                        .filter((part) => part.trim());
                    const agePart = parts.find((part) => part.includes("歳"));
                    if (agePart) {
                        age = agePart.trim();
                        const ageIndex = parts.indexOf(agePart);
                        if (ageIndex >= 0 && ageIndex + 1 < parts.length) {
                            location = parts[ageIndex + 1].trim();
                        }
                        break;
                    }
                }
            }
        }
        if (age === "見つかりません") {
            const verifiedElements = dialogRoot.querySelectorAll("*");
            for (const element of verifiedElements) {
                const text = element.textContent?.trim();
                if (text && text.includes("本人確認済み")) {
                    const parentText = element.parentElement?.textContent?.trim();
                    if (parentText && parentText.includes("歳")) {
                        const cleanText = parentText
                            .replace(/[\n\r]/g, " ")
                            .replace(/\s+/g, " ")
                            .trim();
                        const parts = cleanText
                            .split(" ")
                            .filter((part) => part.trim());
                        const agePart = parts.find((part) => part.includes("歳"));
                        if (agePart) {
                            age = agePart.trim();
                            break;
                        }
                    }
                }
            }
        }
        let introduction = "見つかりません";
        const introH2 = Array.from(dialogRoot.querySelectorAll("h2")).find((h2) => h2.textContent?.includes("自己紹介"));
        console.log("自己紹介h2找到:", !!introH2);
        if (introH2) {
            let currentElement = introH2.nextElementSibling;
            while (currentElement) {
                const introP = currentElement.querySelector("p");
                if (introP && introP.textContent?.trim()) {
                    introduction = introP.textContent.trim();
                    console.log("找到自己紹介内容");
                    break;
                }
                const elementText = currentElement.textContent?.trim();
                if (elementText &&
                    elementText.length > 50 &&
                    !elementText.includes("プロフィール")) {
                    introduction = elementText;
                    console.log("通过文本找到自己紹介内容");
                    break;
                }
                currentElement = currentElement.nextElementSibling;
            }
        }
        if (introduction === "見つかりません") {
            const allElements = dialogRoot.querySelectorAll("p, div");
            for (const element of allElements) {
                const text = element.textContent?.trim();
                if (text &&
                    text.length > 100 &&
                    (text.includes("初めまして") ||
                        text.includes("よろしくお願いします") ||
                        text.includes("プロフィールを見ていただき"))) {
                    const cleanText = text
                        .replace(/お相手詳細を閉じるメニュー前の写真次の写真新着のお相手.*?プロフィールをコピー/g, "")
                        .replace(/30歳 大阪.*?本人確認済み/g, "")
                        .replace(/ペアーズクエスチョン.*?マイタグ/g, "")
                        .replace(/自己紹介/g, "")
                        .replace(/プロフィール.*/g, "")
                        .replace(/真面目に真剣に出会いを探してます.*?趣味全般/g, "")
                        .replace(/恋愛・結婚/g, "")
                        .replace(/Netflix観てます/g, "")
                        .replace(/自然のあるところが好き/g, "")
                        .replace(/旅行/g, "")
                        .replace(/Pickup/g, "")
                        .replace(/一緒に夜カフェでまったりしよう/g, "")
                        .replace(/\s+/g, " ")
                        .trim();
                    if (cleanText.length > 50) {
                        introduction = cleanText;
                        console.log("通过关键词找到自己紹介内容");
                        break;
                    }
                }
            }
        }
        const myTags = [];
        const tagsH2 = Array.from(dialogRoot.querySelectorAll("h2")).find((h2) => h2.textContent?.includes("マイタグ"));
        if (tagsH2?.nextElementSibling) {
            const tagLinks = tagsH2.nextElementSibling.querySelectorAll("ul > li > a");
            tagLinks.forEach((a) => {
                const title = a.getAttribute("title");
                if (title)
                    myTags.push(title);
            });
        }
        const pairsQuestions = [];
        const questionsH2 = Array.from(dialogRoot.querySelectorAll("h2")).find((h2) => h2.textContent?.includes("ペアーズクエスチョン"));
        console.log("ペアーズクエスチョンh2找到:", !!questionsH2);
        if (questionsH2) {
            let questionsContainer = questionsH2.nextElementSibling;
            while (questionsContainer) {
                const questionElements = questionsContainer.querySelectorAll("div, p, span");
                console.log("找到的问题元素数量:", questionElements.length);
                for (let i = 0; i < questionElements.length; i++) {
                    const element = questionElements[i];
                    const text = element.textContent?.trim();
                    if (text &&
                        (text.includes("毎日しちゃうルーティンは?") ||
                            text.includes("居心地のいい場所は?") ||
                            text.includes("最高に幸せ!") ||
                            text.includes("デートプランどうやって決める?") ||
                            text.includes("急に1日だけ休みをもらえたら何する?"))) {
                        const question = text;
                        if (i + 1 < questionElements.length) {
                            const answerElement = questionElements[i + 1];
                            const answer = answerElement.textContent?.trim();
                            if (answer && !answer.includes("?") && !answer.includes("!")) {
                                pairsQuestions.push({ question, answer });
                                console.log("找到ペアーズクエスチョン:", question, "=>", answer);
                            }
                        }
                    }
                }
                if (pairsQuestions.length > 0) {
                    console.log("找到ペアーズクエスチョン数量:", pairsQuestions.length);
                    break;
                }
                questionsContainer = questionsContainer.nextElementSibling;
            }
        }
        const basicInfo = extractBasicInfoFromProfile(dialogRoot);
        console.log("提取的基本信息数量:", Object.keys(basicInfo).length);
        console.log("提取的键:", Object.keys(basicInfo));
        return {
            nickname,
            age,
            location,
            introduction,
            myTags,
            pairsQuestions,
            basicInfo,
            site: "PAIRS",
        };
    }
    function extractMarrishData(selectors) {
        const name = document.querySelector(selectors.NAME)?.textContent?.trim() ||
            "見つかりません";
        const age = document.querySelector(selectors.AGE)?.textContent?.trim() ||
            "見つかりません";
        const location = document.querySelector(selectors.AREA)?.textContent?.trim() ||
            "見つかりません";
        const groups = [];
        const groupElements = document.querySelectorAll(selectors.GROUP_ITEMS);
        groupElements.forEach((el) => {
            const title = el
                .querySelector(selectors.GROUP_TITLE)
                ?.textContent?.trim();
            const member = el
                .querySelector(selectors.GROUP_MEMBER)
                ?.textContent?.trim();
            if (title) {
                groups.push({
                    title,
                    member: member || "不明",
                });
            }
        });
        const selfPrElement = document.querySelector(selectors.SELF_PR);
        let selfPr = "見つかりません";
        if (selfPrElement) {
            const htmlContent = selfPrElement.innerHTML;
            selfPr = htmlContent
                .replace(/<br\s*\/?>/gi, "\n")
                .replace(/<[^>]*>/g, "")
                .replace(/\n{3,}/g, "\n\n")
                .trim();
        }
        const basicInfo = {};
        const detailGroups = document.querySelectorAll(selectors.DETAIL_GROUP);
        detailGroups.forEach((group) => {
            const subTitle = group
                .querySelector(selectors.DETAIL_SUB_TITLE)
                ?.textContent?.trim();
            const detailItems = group.querySelectorAll(selectors.DETAIL_ITEM);
            detailItems.forEach((item) => {
                const title = item
                    .querySelector(selectors.DETAIL_ITEM_TITLE)
                    ?.textContent?.trim();
                const dateElement = item.querySelector(selectors.DETAIL_ITEM_DATE);
                if (title && dateElement) {
                    let date = title === "活動エリア"
                        ? dateElement.innerHTML
                            .replace(/<br\s*\/?>/gi, ",")
                            .replace(/<[^>]*>/g, "")
                            .trim()
                            .replace(/,\s*,/g, ",")
                            .replace(/,$/, "")
                        : dateElement.textContent?.trim();
                    if (title && date) {
                        const key = title;
                        basicInfo[key] = {
                            value: date,
                            group: subTitle || "その他",
                        };
                    }
                }
            });
        });
        return {
            nickname: name,
            age,
            location,
            groups,
            selfPr,
            basicInfo,
            site: "MARRISH",
        };
    }
    function extractMarrishMobileData(selectors) {
        const name = document.querySelector(selectors.MOBILE_NAME)?.textContent?.trim() ||
            "見つかりません";
        const age = document.querySelector(selectors.MOBILE_AGE)?.textContent?.trim() ||
            "見つかりません";
        const location = document.querySelector(selectors.MOBILE_AREA)?.textContent?.trim() ||
            "見つかりません";
        const groups = [];
        const groupElements = document.querySelectorAll(selectors.GROUP_ITEMS);
        groupElements.forEach((el) => {
            const title = el
                .querySelector(selectors.GROUP_TITLE)
                ?.textContent?.trim();
            const member = el
                .querySelector(selectors.GROUP_MEMBER)
                ?.textContent?.trim();
            if (title) {
                groups.push({
                    title,
                    member: member || "不明",
                });
            }
        });
        const selfPrElement = document.querySelector(selectors.SELF_PR);
        let selfPr = "見つかりません";
        if (selfPrElement) {
            const htmlContent = selfPrElement.innerHTML;
            selfPr = htmlContent
                .replace(/<br\s*\/?>/gi, "\n")
                .replace(/<[^>]*>/g, "")
                .replace(/\n{3,}/g, "\n\n")
                .trim();
        }
        const basicInfo = {};
        const detailGroups = document.querySelectorAll(selectors.DETAIL_GROUP);
        detailGroups.forEach((group) => {
            const subTitle = group
                .querySelector(selectors.DETAIL_SUB_TITLE)
                ?.textContent?.trim();
            const detailItems = group.querySelectorAll(selectors.DETAIL_ITEM);
            detailItems.forEach((item) => {
                const title = item
                    .querySelector(selectors.DETAIL_ITEM_TITLE)
                    ?.textContent?.trim();
                const dateElement = item.querySelector(selectors.DETAIL_ITEM_DATE);
                if (title && dateElement) {
                    let date = title === "活動エリア"
                        ? dateElement.innerHTML
                            .replace(/<br\s*\/?>/gi, ",")
                            .replace(/<[^>]*>/g, "")
                            .trim()
                            .replace(/,\s*,/g, ",")
                            .replace(/,$/, "")
                        : dateElement.textContent?.trim();
                    if (title && date) {
                        const key = title;
                        basicInfo[key] = {
                            value: date,
                            group: subTitle || "その他",
                        };
                    }
                }
            });
        });
        return {
            nickname: name,
            age,
            location,
            groups,
            selfPr,
            basicInfo,
            site: "MARRISH",
        };
    }
    function generatePrompt(data) {
        const template = TEMPLATES[data.site];
        if (!template) {
            throw new Error(`未知的网站类型: ${data.site}`);
        }
        let basicInfoText;
        if (data.site === "MARRISH") {
            basicInfoText = formatMarrishBasicInfo(data.basicInfo);
        }
        else {
            basicInfoText = formatBasicInfo(data.basicInfo);
        }
        const additionalText = formatAdditionalData(data);
        return buildPrompt(template, data, basicInfoText, additionalText);
    }
    function formatBasicInfo(basicInfo) {
        if (Object.entries(basicInfo).length === 0) {
            return "なし";
        }
        return Object.entries(basicInfo)
            .map(([key, value]) => `${key}: ${value}`)
            .join("\n");
    }
    function formatMarrishBasicInfo(basicInfo) {
        if (Object.entries(basicInfo).length === 0) {
            return "なし";
        }
        const groupedData = {};
        Object.entries(basicInfo).forEach(([key, data]) => {
            const group = data.group;
            if (!groupedData[group]) {
                groupedData[group] = [];
            }
            groupedData[group].push({ key, value: data.value });
        });
        const sections = [];
        Object.entries(groupedData).forEach(([group, items]) => {
            sections.push(group);
            items.forEach((item) => {
                sections.push(`  ${item.key}: ${item.value}`);
            });
            sections.push("");
        });
        return sections.join("\n").trim();
    }
    function formatAdditionalData(data) {
        switch (data.site) {
            case "WITH_IS":
                return data.commonPoints.length > 0
                    ? data.commonPoints.map((point) => `- ${point}`).join("\n")
                    : "なし";
            case "PAIRS":
                const parts = [];
                if (data.myTags.length > 0) {
                    parts.push(...data.myTags.map((tag) => `- ${tag}`));
                }
                if (data.pairsQuestions.length > 0) {
                    if (parts.length > 0)
                        parts.push("");
                    parts.push("ペアーズクエスチョン:");
                    data.pairsQuestions.forEach((q) => {
                        parts.push(`- ${q.question}`);
                        parts.push(`  ${q.answer}`);
                    });
                }
                return parts.length > 0 ? parts.join("\n") : "なし";
            case "MARRISH":
                return data.groups.length > 0
                    ? data.groups
                        .map((group) => `- ${group.title} (${group.member})`)
                        .join("\n")
                    : "なし";
            default:
                return "なし";
        }
    }
    function buildPrompt(template, data, basicInfoText, additionalText) {
        const introductionField = data.site === "MARRISH" ? "selfPr" : "introduction";
        return `${template.header}

${template.nickname}:${data.nickname}
${template.age}:${data.age}
${template.location}:${data.location}

${template.introduction}:
${data[introductionField]}

${template.additional}:
${additionalText}

${template.basicInfo}:
${basicInfoText}

${template.footer}`;
    }
    function showMessage(message, type) {
        const messageDiv = document.createElement("div");
        messageDiv.textContent = message;
        messageDiv.style.cssText = `
            position: fixed;
            top: 20px;
            right: 20px;
            padding: 10px 15px;
            background: ${type === "success" ? "#28a745" : "#dc3545"};
            color: white;
            border-radius: 4px;
            z-index: 10000;
            font-size: 14px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.2);
        `;
        document.body.appendChild(messageDiv);
        setTimeout(() => {
            if (messageDiv.parentNode) {
                messageDiv.parentNode.removeChild(messageDiv);
            }
        }, CONFIG.MESSAGE_DISPLAY_TIME);
    }
})();