V2EX 成分分析器

自动提取V2EX用户的所有回复,支持导出CSV和Markdown格式,10维度量化评分+AI分析用户画像

目前為 2025-10-31 提交的版本,檢視 最新版本

// ==UserScript==
// @name         V2EX 成分分析器
// @namespace    http://tampermonkey.net/
// @version      1.3.1
// @description  自动提取V2EX用户的所有回复,支持导出CSV和Markdown格式,10维度量化评分+AI分析用户画像
// @author       su3sl3h06
// @license      MIT
// @match        https://www.v2ex.com/member/*
// @match        https://v2ex.com/member/*
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    // 存储提取的数据
    let allReplies = [];
    let allTopics = [];
    let isRunning = false;
    let shouldStop = false;

    // 创建控制面板
    function createControlPanel() {
        const panel = document.createElement('div');
        panel.id = 'reply-extractor-panel';
        panel.innerHTML = `
            <div style="
                position: fixed;
                top: 100px;
                right: 20px;
                width: 320px;
                background: white;
                border: 2px solid #ccc;
                border-radius: 8px;
                padding: 20px;
                box-shadow: 0 4px 12px rgba(0,0,0,0.15);
                z-index: 10000;
                font-family: Arial, sans-serif;
            ">
                <h3 style="margin: 0 0 15px 0; font-size: 16px; color: #333;">
                    V2EX 回复提取器
                </h3>
                
                <div style="margin-bottom: 15px;">
                    <label style="display: block; margin-bottom: 5px; font-size: 14px; color: #666;">
                        提取模式:
                    </label>
                    <select id="extract-mode" style="
                        width: 100%;
                        padding: 8px;
                        border: 1px solid #ddd;
                        border-radius: 4px;
                        font-size: 14px;
                    ">
                        <option value="all">提取所有页面(上限500条)</option>
                        <option value="custom">自定义页数</option>
                    </select>
                </div>

                <div id="custom-pages-container" style="margin-bottom: 15px; display: none;">
                    <label style="display: block; margin-bottom: 5px; font-size: 14px; color: #666;">
                        提取页数:
                    </label>
                    <input 
                        type="number" 
                        id="pages-to-extract" 
                        min="1" 
                        value="5"
                        style="
                            width: 100%;
                            padding: 8px;
                            border: 1px solid #ddd;
                            border-radius: 4px;
                            font-size: 14px;
                        "
                    />
                </div>

                <div style="margin-bottom: 15px;">
                    <label style="display: block; margin-bottom: 5px; font-size: 14px; color: #666;">
                        延迟时间(毫秒):
                    </label>
                    <input 
                        type="number" 
                        id="delay-time" 
                        min="500" 
                        value="1500"
                        style="
                            width: 100%;
                            padding: 8px;
                            border: 1px solid #ddd;
                            border-radius: 4px;
                            font-size: 14px;
                        "
                    />
                </div>

                <div style="margin-bottom: 15px;">
                    <div style="
                        background: #f5f5f5;
                        padding: 10px;
                        border-radius: 4px;
                        font-size: 13px;
                    ">
                        <div>当前页: <span id="current-page">-</span></div>
                        <div>总页数: <span id="total-pages">-</span></div>
                        <div>已提取: <span id="extracted-count">0</span> 条</div>
                        <div>状态: <span id="status">等待中</span></div>
                    </div>
                </div>

                <div style="margin-bottom: 15px;">
                    <div style="
                        width: 100%;
                        height: 20px;
                        background: #f0f0f0;
                        border-radius: 10px;
                        overflow: hidden;
                    ">
                        <div id="progress-bar" style="
                            width: 0%;
                            height: 100%;
                            background: linear-gradient(90deg, #4CAF50, #8BC34A);
                            transition: width 0.3s ease;
                        "></div>
                    </div>
                    <div style="text-align: center; font-size: 12px; color: #666; margin-top: 5px;">
                        <span id="progress-text">0%</span>
                    </div>
                </div>

                <button id="start-extract-btn" style="
                    width: 100%;
                    padding: 10px;
                    background: #4CAF50;
                    color: white;
                    border: none;
                    border-radius: 4px;
                    font-size: 14px;
                    cursor: pointer;
                    margin-bottom: 10px;
                ">
                    开始提取
                </button>

                <button id="stop-extract-btn" style="
                    width: 100%;
                    padding: 10px;
                    background: #f44336;
                    color: white;
                    border: none;
                    border-radius: 4px;
                    font-size: 14px;
                    cursor: pointer;
                    margin-bottom: 10px;
                    display: none;
                ">
                    停止提取
                </button>

                <button id="export-csv-btn" style="
                    width: 100%;
                    padding: 10px;
                    background: #2196F3;
                    color: white;
                    border: none;
                    border-radius: 4px;
                    font-size: 14px;
                    cursor: pointer;
                    margin-bottom: 10px;
                " disabled>
                    导出 CSV
                </button>

                <button id="export-md-btn" style="
                    width: 100%;
                    padding: 10px;
                    background: #FF9800;
                    color: white;
                    border: none;
                    border-radius: 4px;
                    font-size: 14px;
                    cursor: pointer;
                    margin-bottom: 10px;
                " disabled>
                    📥 导出 MD 文件
                </button>

                <button id="copy-md-btn" style="
                    width: 100%;
                    padding: 10px;
                    background: #9C27B0;
                    color: white;
                    border: none;
                    border-radius: 4px;
                    font-size: 14px;
                    cursor: pointer;
                    margin-bottom: 10px;
                " disabled>
                    📋 复制 MD 内容
                </button>

                <button id="close-panel-btn" style="
                    width: 100%;
                    padding: 8px;
                    background: #fff;
                    color: #666;
                    border: 1px solid #ddd;
                    border-radius: 4px;
                    font-size: 13px;
                    cursor: pointer;
                ">
                    关闭面板
                </button>
            </div>
        `;
        document.body.appendChild(panel);
        bindEvents();
    }

    // 收集该用户自己创建的主题URL(从已提取回复中筛选)
    function collectUserAuthoredTopicUrls(username) {
        const set = new Set();
        if (!username) return set;
        allReplies.forEach(r => {
            if ((r.主题作者 || '').trim() === username && r.主题链接) {
                set.add(r.主题链接.split('#')[0]);
            }
        });
        return set;
    }

    // 抓取主题正文(标题/节点/正文),limit用于限制最多抓取数量
    async function fetchTopicsContent(urls, delayMs = 1200, limit = 30, onProgress) {
        const topics = [];
        const slice = urls.slice(0, Math.max(0, limit));
        for (let i = 0; i < slice.length; i++) {
            const url = slice[i];
            try {
                // 节流
                if (i > 0) {
                    await new Promise(r => setTimeout(r, delayMs));
                }
                const html = await fetch(url, { credentials: 'include' }).then(res => res.text());
                const parser = new DOMParser();
                const doc = parser.parseFromString(html, 'text/html');

                const title = doc.querySelector('.post-wrapper .header h1')?.textContent?.trim() ||
                               doc.querySelector('h1')?.textContent?.trim() || '';
                const node = doc.querySelector('.post-wrapper .header a[href^="/go/"]')?.textContent?.trim() || '';
                const bodyEl = doc.querySelector('.topic_content .markdown_body') || doc.querySelector('.topic_content');
                let body = bodyEl ? bodyEl.textContent.trim() : '';
                // 压缩多余空白
                body = body.replace(/\u00a0/g, ' ').replace(/\s{3,}/g, ' ').replace(/[\r\t]+/g, '').trim();

                topics.push({ 标题: title, 节点: node, 正文: body });
                if (typeof onProgress === 'function') {
                    onProgress(i + 1, slice.length);
                }
            } catch (e) {
                console.error('抓取主题失败:', url, e);
                if (typeof onProgress === 'function') {
                    onProgress(i + 1, slice.length);
                }
            }
        }
        return topics;
    }

    // 统一Toast
    function showToast(message, durationMs = 10000) {
        try {
            const toast = document.createElement('div');
            toast.style.cssText = `
                position: fixed;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                color: white;
                padding: 20px 28px;
                border-radius: 12px;
                box-shadow: 0 8px 32px rgba(102, 126, 234, 0.4);
                z-index: 10001;
                font-size: 15px;
                font-weight: bold;
                text-align: center;
                line-height: 1.6;
                animation: fadeInOut ${Math.max(200, durationMs)}ms ease-in-out;
                white-space: pre-line;
            `;
            toast.innerHTML = `✅\n${message}`;

            if (!document.getElementById('toast-animation-style')) {
                const style = document.createElement('style');
                style.id = 'toast-animation-style';
                style.textContent = `
                    @keyframes fadeInOut {
                        0% { opacity: 0; transform: translate(-50%, -50%) scale(0.92); }
                        10% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
                        90% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
                        100% { opacity: 0; transform: translate(-50%, -50%) scale(0.96); }
                    }
                `;
                document.head.appendChild(style);
            }

            document.body.appendChild(toast);
            setTimeout(() => { toast.remove(); }, durationMs);
        } catch (e) {
            // 兜底
            console.log('Toast:', message);
        }
    }

    // 绑定事件
    function bindEvents() {
        // 模式切换
        document.getElementById('extract-mode').addEventListener('change', function(e) {
            const customContainer = document.getElementById('custom-pages-container');
            customContainer.style.display = e.target.value === 'custom' ? 'block' : 'none';
        });

        // 开始提取
        document.getElementById('start-extract-btn').addEventListener('click', startExtraction);

        // 停止提取
        document.getElementById('stop-extract-btn').addEventListener('click', stopExtraction);

        // 导出CSV
        document.getElementById('export-csv-btn').addEventListener('click', exportToCSV);

        // 导出MD
        document.getElementById('export-md-btn').addEventListener('click', exportToMarkdown);

        // 复制MD到剪贴板
        document.getElementById('copy-md-btn').addEventListener('click', copyMarkdownToClipboard);

        // 关闭面板
        document.getElementById('close-panel-btn').addEventListener('click', function() {
            document.getElementById('reply-extractor-panel').style.display = 'none';
        });
    }

    // 获取当前页面信息
    function getPageInfo() {
        const headerText = document.querySelector('.box .header')?.textContent || '';
        const match = headerText.match(/第\s*(\d+)\s*页\s*\/\s*共\s*(\d+)\s*页/);
        
        if (match) {
            return {
                currentPage: parseInt(match[1]),
                totalPages: parseInt(match[2])
            };
        }
        
        // 如果没有分页信息,说明只有一页
        return {
            currentPage: 1,
            totalPages: 1
        };
    }

    // 提取当前页面的回复
    function extractCurrentPage() {
        const replies = [];
        const dockAreas = document.querySelectorAll('.dock_area');
        
        dockAreas.forEach((dockArea, index) => {
            try {
                // 获取时间
                const timeElement = dockArea.querySelector('.fr .fade');
                const time = timeElement ? timeElement.textContent.trim() : '';

                // 获取回复信息
                const graySpan = dockArea.querySelector('.gray');
                if (!graySpan) return;

                // 获取主题作者
                const authorLink = graySpan.querySelector('a[href^="/member/"]');
                const author = authorLink ? authorLink.textContent.trim() : '';

                // 获取板块
                const boardLink = graySpan.querySelector('a[href^="/go/"]');
                const board = boardLink ? boardLink.textContent.trim() : '';

                // 获取主题标题和链接
                const topicLink = graySpan.querySelector('a[href^="/t/"]');
                const topicTitle = topicLink ? topicLink.textContent.trim() : '';
                const topicUrl = topicLink ? 'https://www.v2ex.com' + topicLink.getAttribute('href') : '';

                // 获取回复内容
                let replyContent = '';
                const nextInner = dockArea.nextElementSibling;
                if (nextInner && (nextInner.classList.contains('inner') || nextInner.classList.contains('cell'))) {
                    const contentDiv = nextInner.querySelector('.reply_content');
                    if (contentDiv) {
                        replyContent = contentDiv.textContent.trim();
                    }
                }

                if (replyContent) {
                    replies.push({
                        时间: time,
                        主题作者: author,
                        板块: board,
                        主题标题: topicTitle,
                        主题链接: topicUrl,
                        回复内容: replyContent
                    });
                }
            } catch (error) {
                console.error('提取回复时出错:', error);
            }
        });

        return replies;
    }

    // 更新UI
    function updateUI(currentPage, totalPages, extractedCount, status, progress) {
        document.getElementById('current-page').textContent = currentPage;
        document.getElementById('total-pages').textContent = totalPages;
        document.getElementById('extracted-count').textContent = extractedCount;
        document.getElementById('status').textContent = status;
        document.getElementById('progress-bar').style.width = progress + '%';
        document.getElementById('progress-text').textContent = Math.round(progress) + '%';
    }

    // 开始提取
    async function startExtraction() {
        if (isRunning) return;

        isRunning = true;
        shouldStop = false;
        allReplies = [];
        allTopics = [];

        // 更新按钮状态
        document.getElementById('start-extract-btn').style.display = 'none';
        document.getElementById('stop-extract-btn').style.display = 'block';
        document.getElementById('export-csv-btn').disabled = true;
        document.getElementById('export-md-btn').disabled = true;
        document.getElementById('copy-md-btn').disabled = true;

        // 获取配置
        const mode = document.getElementById('extract-mode').value;
        const customPages = parseInt(document.getElementById('pages-to-extract').value) || 5;
        const delay = parseInt(document.getElementById('delay-time').value) || 1500;

        // 获取页面信息
        const pageInfo = getPageInfo();
        const totalPages = mode === 'all' ? pageInfo.totalPages : Math.min(customPages, pageInfo.totalPages);
        
        updateUI(pageInfo.currentPage, totalPages, 0, '正在提取...', 0);

        try {
            // 提取当前页
            const currentReplies = extractCurrentPage();
            allReplies.push(...currentReplies);
            if (allReplies.length >= 500) {
                allReplies = allReplies.slice(0, 500);
                updateUI(pageInfo.currentPage, totalPages, allReplies.length, '已达到500条上限,停止提取', (pageInfo.currentPage / totalPages) * 100);
                shouldStop = true;
            }
            updateUI(pageInfo.currentPage, totalPages, allReplies.length, '正在提取...', 
                    (pageInfo.currentPage / totalPages) * 100);

            // 如果需要提取更多页
            if (totalPages > pageInfo.currentPage && !shouldStop) {
                for (let page = pageInfo.currentPage + 1; page <= totalPages; page++) {
                    if (allReplies.length >= 500) break;
                    if (shouldStop) break;

                    updateUI(page, totalPages, allReplies.length, `正在加载第 ${page} 页...`, 
                            ((page - 1) / totalPages) * 100);

                    // 等待延迟
                    await new Promise(resolve => setTimeout(resolve, delay));

                    // 跳转到下一页
                    const nextPageUrl = window.location.pathname + '?p=' + page;
                    await loadPage(nextPageUrl);

                    // 提取新页面的回复
                    const newReplies = extractCurrentPage();
                    allReplies.push(...newReplies);
                    if (allReplies.length >= 500) {
                        allReplies = allReplies.slice(0, 500);
                        shouldStop = true;
                    }
                    
                    updateUI(page, totalPages, allReplies.length, '正在提取...', 
                            (page / totalPages) * 100);
                }
            }

            // 无论是否达到上限/主动停止,均尝试抓取该用户创建的主题内容
            const username = window.location.pathname.match(/\/member\/([^\/]+)/)?.[1] || '';
            try {
                const topicUrls = collectUserAuthoredTopicUrls(username);
                if (topicUrls.size > 0) {
                    updateUI(totalPages, totalPages, allReplies.length, `提取完成,正在抓取主题正文(${topicUrls.size})...`, 95);
                    const delayMs = parseInt(document.getElementById('delay-time').value) || 1500;
                    allTopics = await fetchTopicsContent(
                        Array.from(topicUrls),
                        delayMs,
                        30,
                        (done, total) => {
                            const pct = 95 + Math.min(5, (done / Math.max(1, total)) * 5);
                            updateUI(totalPages, totalPages, allReplies.length, `抓取主题正文 ${done}/${total} ...`, pct);
                        }
                    );
                    showToast(`提取完成\n抓取到用户创建的主题:${allTopics.length} 篇`);
                }
            } catch (e) {
                console.error('抓取主题正文失败:', e);
            }
            updateUI(totalPages, totalPages, allReplies.length, '提取完成!', 100);

        } catch (error) {
            console.error('提取过程出错:', error);
            updateUI('-', '-', allReplies.length, '提取出错', 0);
        }

        // 恢复按钮状态
        document.getElementById('start-extract-btn').style.display = 'block';
        document.getElementById('stop-extract-btn').style.display = 'none';
        document.getElementById('export-csv-btn').disabled = false;
        document.getElementById('export-md-btn').disabled = false;
        document.getElementById('copy-md-btn').disabled = false;
        isRunning = false;
    }

    // 停止提取
    function stopExtraction() {
        shouldStop = true;
        updateUI('-', '-', allReplies.length, '正在停止...', 0);
    }

    // 加载页面
    function loadPage(url) {
        return new Promise((resolve, reject) => {
            fetch(url)
                .then(response => response.text())
                .then(html => {
                    const parser = new DOMParser();
                    const doc = parser.parseFromString(html, 'text/html');
                    
                    // 替换主内容区域
                    const newMain = doc.querySelector('#Main');
                    const oldMain = document.querySelector('#Main');
                    if (newMain && oldMain) {
                        oldMain.innerHTML = newMain.innerHTML;
                    }
                    
                    // 更新URL
                    window.history.pushState({}, '', url);
                    
                    resolve();
                })
                .catch(error => {
                    console.error('加载页面失败:', error);
                    reject(error);
                });
        });
    }

    // 导出为CSV
    function exportToCSV() {
        if (allReplies.length === 0) {
            showToast('没有数据可以导出!');
            return;
        }

        // CSV头部
        const headers = ['时间', '主题作者', '板块', '主题标题', '主题链接', '回复内容'];
        
        // 转换为CSV格式
        let csv = '\uFEFF'; // 添加BOM以支持中文
        csv += headers.join(',') + '\n';

        allReplies.forEach(reply => {
            const row = headers.map(header => {
                let value = reply[header] || '';
                // 转义双引号并用双引号包裹包含逗号、换行或双引号的字段
                value = value.replace(/"/g, '""');
                if (value.includes(',') || value.includes('\n') || value.includes('"')) {
                    value = '"' + value + '"';
                }
                return value;
            });
            csv += row.join(',') + '\n';
        });

        // 创建下载
        const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
        const link = document.createElement('a');
        const url = URL.createObjectURL(blob);
        
        // 获取用户名
        const username = window.location.pathname.match(/\/member\/([^\/]+)/)?.[1] || 'user';
        const filename = `v2ex_${username}_replies_${new Date().getTime()}.csv`;
        
        link.setAttribute('href', url);
        link.setAttribute('download', filename);
        link.style.visibility = 'hidden';
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);

        showToast(`成功导出 ${allReplies.length} 条回复!`);
    }

    // 导出为Markdown格式(用于AI分析)
    function exportToMarkdown() {
        if (allReplies.length === 0) {
            showToast('没有数据可以导出!');
            return;
        }

        // 文本清洗,节约token
        const sanitizeForLLM = (text) => {
            let t = (text || '').toString();
            // 移除URL
            t = t.replace(/https?:\/\/[^\s)]+/g, '');
            // 去掉强调/代码等常见Markdown符号
            t = t.replace(/\*\*|__|`/g, '');
            // 折叠多空格
            t = t.replace(/\s{2,}/g, ' ');
            // 规范换行
            t = t.replace(/\n{3,}/g, '\n\n');
            return t.trim();
        };

        // 获取用户名
        const username = window.location.pathname.match(/\/member\/([^\/]+)/)?.[1] || 'unknown_user';
        
        // 统计信息
        const totalReplies = allReplies.length;
        const boards = [...new Set(allReplies.map(r => r.板块))];
        const boardStats = {};
        allReplies.forEach(reply => {
            const board = reply.板块 || '未知';
            boardStats[board] = (boardStats[board] || 0) + 1;
        });
        const sortedBoards = Object.entries(boardStats).sort((a, b) => b[1] - a[1]);

        // 构建Markdown内容
        let markdown = `# V2EX 用户画像分析任务

## 📋 任务说明

你是一位专业的用户行为分析师。现在需要你根据下方提供的V2EX用户回复数据,深入分析该用户的完整人物画像。

---

## 👤 分析对象

- **用户名**: ${username}
- **数据来源**: V2EX (一个面向创意工作者的中文社区)
- **回复总数**: ${totalReplies} 条
- **活跃板块数**: ${boards.length} 个
- **数据提取时间**: ${new Date().toLocaleString('zh-CN')}

---

## 📊 基础数据概览

### 板块活跃度统计(Top 10)

| 排名 | 板块名称 | 回复次数 | 占比 |
|------|---------|---------|------|
`;

        // 添加板块统计
        sortedBoards.slice(0, 10).forEach((item, index) => {
            const [board, count] = item;
            const percentage = ((count / totalReplies) * 100).toFixed(1);
            markdown += `| ${index + 1} | ${board} | ${count} | ${percentage}% |\n`;
        });

        markdown += `\n---

## 🧵 用户创建的主题(采样)

从用户创建的主题中抽取正文内容(最多展示30篇,用于辅助AI判断立场与真实度):

${(allTopics && allTopics.length ? allTopics : []).map((t, idx) => `### 主题 #${idx + 1}\n\n节点: ${t.节点 || '-'}\n标题: ${t.标题 || '-'}\n\n正文:\n> ${(t.正文 || '').split('\\n').join('\\n> ')}\n\n---\n`).join('')}

## 💬 完整回复记录(最多500条)

以下为该用户的回复内容(按时间从新到旧,最多500条):

`;

        // 添加所有回复(最多500条)
        (allReplies.slice(0, 500)).forEach((reply, index) => {
            markdown += `### 回复 #${index + 1}\n\n时间: ${reply.时间}  \n板块: ${reply.板块}  \n主题: ${reply.主题标题}  \n主题作者: ${reply.主题作者}  \n回复内容:\n> ${reply.回复内容.split('\\n').join('\\n> ')}\n\n---\n\n`;
        });

        // 添加分析要求
        markdown += `
---

## 🎯 分析任务要求

请基于以上所有回复数据,从以下维度深入分析该用户,并生成一份详细的**量化用户画像报告**。

**重要**: 每个维度必须按照给定的评分标准打分,不能凭主观感觉!

---

## 📊 评分标准与分析维度

### 1. 技术能力评估 💻 (1-10分)

**评分标准**:
- **1-3分**: 非技术用户,基本不涉及技术讨论
- **4-6分**: 技术爱好者,了解基础技术概念,偶尔讨论技术话题
- **7-8分**: 技术从业者,熟悉特定技术栈,经常分享技术见解
- **9-10分**: 技术专家,深入讨论底层原理,能解决复杂技术问题

**量化指标**:
- 技术相关回复占比: ____%
- 提及的技术关键词数量: ___个
- 技术深度(是否涉及原理/架构/底层): 是/否

**分析要点**:
- 主要技术栈(编程语言、框架、工具等)
- 技术广度与深度
- 是否有专业技术背景
- 对新技术的接受程度

**评分**: ___/10 分

---

### 2. 消费能力评估 💰 (1-10分)

**评分标准**:
- **1-3分**: 消费保守,注重性价比,多讨论如何省钱
- **4-6分**: 消费适中,偶尔购买中高端产品,理性消费
- **7-8分**: 消费能力较强,经常购买中高端产品,品质优先
- **9-10分**: 消费能力很强,购买高端/奢侈品,价格不敏感

**量化指标**:
- 提及的产品价格范围: ¥___ - ¥___
- 高价值物品(>5000元)提及次数: ___次
- 投资/理财相关讨论: ___次

**分析要点**:
- 提及的具体产品及价格(如手机、电脑、旅行等)
- 消费观念(性价比/品质/奢侈)
- 是否有投资理财意识
- 经济压力感知

**评分**: ___/10 分

---

### 3. 专业深度评估 🎓 (1-10分)

**评分标准**:
- **1-3分**: 泛泛而谈,缺乏专业见解
- **4-6分**: 在某些领域有一定见解,但不够深入
- **7-8分**: 在1-2个领域有专业见解,能给出专业建议
- **9-10分**: 多领域专家,回复经常被认可,有行业影响力

**量化指标**:
- 专业术语使用频率: 高/中/低
- 深度分析回复占比: ____%
- 被@请教的次数: ___次(从回复中推断)

**分析要点**:
- 专业领域识别(职业相关)
- 知识深度与广度
- 是否经常解答他人问题
- 专业表达能力

**评分**: ___/10 分

---

### 4. 社交活跃度 👥 (1-10分)

**评分标准**:
- **1-3分**: 很少互动,回复简短,不主动交流
- **4-6分**: 适度互动,偶尔参与讨论,回复中等长度
- **7-8分**: 活跃互动,经常@他人,回复详细,乐于助人
- **9-10分**: 高度活跃,社区KOL,有固定交流圈子

**量化指标**:
- 平均回复长度: ___字
- @他人次数: ___次
- 回复情感倾向: 友善/中性/冷淡
- 活跃板块数量: ___个

**分析要点**:
- 交流主动性
- 互动频率和质量
- 是否有固定交流对象
- 社交风格(热情/礼貌/高冷)

**评分**: ___/10 分

---

### 5. 兴趣广度评估 🎮 (1-10分)

**评分标准**:
- **1-3分**: 兴趣单一,只关注1-2个领域
- **4-6分**: 兴趣适中,关注3-5个不同领域
- **7-8分**: 兴趣广泛,跨多个领域(科技/生活/娱乐等)
- **9-10分**: 兴趣极其广泛,涉猎各个领域,博学多才

**量化指标**:
- 涉及的主题类别数: ___个
- 话题分散度: 高/中/低
- 跨领域讨论占比: ____%

**分析要点**:
- 主要兴趣点列表
- 兴趣深度(入门/进阶/专家)
- 是否有特别突出的兴趣
- 兴趣是否与职业相关

**评分**: ___/10 分

---

### 6. 情绪稳定性 🧩 (1-10分)

**评分标准**:
- **1-3分**: 情绪波动大,经常抱怨/焦虑/愤怒
- **4-6分**: 情绪一般,偶尔流露负面情绪
- **7-8分**: 情绪稳定,多数回复平和理性
- **9-10分**: 情绪非常稳定,始终保持积极乐观态度

**量化指标**:
- 负面情绪词汇出现次数: ___次(如:郁闷、烦、气、无语等)
- 正面情绪词汇出现次数: ___次(如:开心、爽、赞、喜欢等)
- 中性客观回复占比: ____%

**分析要点**:
- 主要情绪倾向
- 压力/焦虑表现
- 对挫折的态度
- 生活满意度

**评分**: ___/10 分

---

### 7. 生活品质指数 🌟 (1-10分)

**评分标准**:
- **1-3分**: 生活压力大,多讨论省钱、焦虑、工作压力
- **4-6分**: 生活一般,工作生活平衡,偶尔享受生活
- **7-8分**: 生活品质较高,经常旅行/美食/娱乐
- **9-10分**: 生活品质很高,追求精致生活,时间自由

**量化指标**:
- 休闲娱乐相关回复: ___次
- 旅行/美食/爱好讨论: ___次
- 加班/压力相关吐槽: ___次

**分析要点**:
- 工作生活平衡
- 休闲娱乐方式
- 生活态度(积极/佛系/焦虑)
- 是否有生活追求

**评分**: ___/10 分

---

### 8. 影响力指数 🏆 (1-10分)

**评分标准**:
- **1-3分**: 无影响力,回复少人关注
- **4-6分**: 影响力一般,偶尔有高质量回复
- **7-8分**: 有一定影响力,回复经常被认可
- **9-10分**: 社区意见领袖,高质量输出,被广泛认可

**量化指标**:
- 回复质量(是否有深度见解): 高/中/低
- 是否解答他人问题: ___次
- 是否引发讨论: 是/否
- 回复被感谢的可能性: 高/中/低(从上下文推断)

**分析要点**:
- 内容质量
- 专业权威性
- 对他人的帮助程度
- 在社区的认可度

**评分**: ___/10 分

---

### 9. 学习成长力 📈 (1-10分)

**评分标准**:
- **1-3分**: 学习意愿低,少讨论新知识/新技术
- **4-6分**: 学习意愿一般,偶尔接触新事物
- **7-8分**: 学习意愿强,经常研究新技术/新领域
- **9-10分**: 持续学习,快速接受新事物,有成长型思维

**量化指标**:
- 提问/求教次数: ___次
- 学习/研究相关讨论: ___次
- 对新技术/新产品的关注度: 高/中/低

**分析要点**:
- 学习态度
- 对新事物的接受度
- 是否主动求知
- 成长型/固定型思维

**评分**: ___/10 分

---

### 10. 真实度/可信度 🎭 (1-10分)

**评分标准**:
- **1-3分**: 疑似水军/发帖员,频繁引战,内容前后矛盾,编故事明显
- **4-6分**: 部分内容夸张或不实,偶尔引战,但大部分内容真实
- **7-8分**: 内容基本真实可信,偶有夸张但无恶意
- **9-10分**: 高度真实,言行一致,内容经得起推敲,真诚度高

**量化指标**:
- 内容前后一致性: 高/中/低
- 引战/攻击性言论次数: ___次
- 疑似营销/广告内容: ___次
- 逻辑矛盾或编故事迹象: ___处

**重点识别特征**:

**🚩 发帖员/水军特征**:
- 短期内大量发帖/回复(不正常的活跃度)
- 重复发布相似内容或套路化回复
- 频繁推荐特定产品/服务/链接
- 账号注册时间短但活跃度极高
- 回复内容空洞,缺乏个人观点

**🚩 故意引战特征**:
- 频繁使用攻击性、煽动性语言
- 刻意挑起争议话题
- 对不同观点采取极端对立态度
- 喜欢"抬杠",缺乏建设性讨论
- 制造焦虑或贩卖恐慌

**🚩 编故事/造假特征**:
- 前后描述自相矛盾(职业/收入/经历不一致)
- 过度夸张的个人经历
- 时间线混乱(如"去年"的事在不同回复中日期不符)
- 细节模糊或经不起推敲
- 频繁更换人设或立场

**✅ 真实可信特征**:
- 长期稳定的发言风格
- 内容具体详细,有个人特色
- 前后观点一致,言行相符
- 分享真实经验教训(包括失败)
- 对话真诚,愿意承认不足

**分析要点**:
- 内容真实性(是否有明显编造迹象)
- 动机纯粹性(是否有营销/引导目的)
- 立场一致性(观点是否前后矛盾)
- 言行一致性(说的和做的是否匹配)
- 互动真诚度(回复是否真心还是套路)

**评分**: ___/10 分

---

### 11. 生活地域判断 🏠

**不评分,仅推断**

**分析要点**:
- **居住城市**: _____(根据讨论的地域板块、提及的地点)
- **证据强度**: 强/中/弱
- **可能的活动范围**: _____
- **是否有地域相关特征**: _____

---

## 📋 综合评价

### 综合画像卡片

| 维度 | 评分 | 等级 | 关键特征 |
|------|------|------|---------|
| 技术能力 | __/10 | 专家/从业者/爱好者/无 | _____ |
| 消费能力 | __/10 | 高/中高/中/中低/低 | _____ |
| 专业深度 | __/10 | 专家/资深/中级/初级 | _____ |
| 社交活跃度 | __/10 | 非常活跃/活跃/一般/不活跃 | _____ |
| 兴趣广度 | __/10 | 非常广泛/广泛/适中/单一 | _____ |
| 情绪稳定性 | __/10 | 非常稳定/稳定/一般/不稳定 | _____ |
| 生活品质 | __/10 | 优质/良好/一般/较差 | _____ |
| 影响力 | __/10 | KOL/活跃/普通/潜水 | _____ |
| 学习成长力 | __/10 | 强/较强/一般/弱 | _____ |
| 真实度/可信度 | __/10 | 高度真实/基本可信/存疑/疑似造假 | _____ |

**综合评分**: ___/100 分

---

### 用户画像总结 (200-300字)

[用一段话描述该用户的整体特征,包括:
- 基本信息(年龄段、地域、职业推断)
- 核心特征(最突出的2-3个特点)
- 兴趣爱好概况
- 性格特征
- 生活状态
- 最具代表性的标签]

---

### 特殊标签 🏷️

请根据分析给出3-5个最具代表性的标签:

\`#标签1\` \`#标签2\` \`#标签3\` \`#标签4\` \`#标签5\`

---

### 核心洞察 💡

**优势特征**(最突出的3个方面):
1. _____
2. _____
3. _____

**潜在需求**(可能感兴趣的3个方向):
1. _____
2. _____
3. _____

**性格特质**(MBTI参考):
- 可能的性格类型: _____
- 主要性格特征: _____

---

## 📋 输出格式要求

1. **严格按照评分标准打分**,不得凭感觉评分
2. **必须列出量化指标的具体数值**
3. **每个评分必须有具体的证据支撑**(引用回复内容)
4. **填写综合评价表格**
5. **生成200-300字的用户画像总结**
6. **给出3-5个标签**
7. **不用重新输出评分标准,只给出要求的结果**

---

## ⚡ 开始分析

请开始你的专业量化分析,注意:

✅ **量化优先**: 先统计量化指标,再基于数据打分  
✅ **证据支撑**: 每个结论都要引用具体回复  
✅ **客观准确**: 基于实际数据,不要过度臆测  
✅ **标准一致**: 严格按照评分标准,不得凭主观感觉  

---

*本文档由 V2EX 用户回复提取器自动生成*  
*提取时间: ${new Date().toLocaleString('zh-CN')}*  
*数据量: ${totalReplies} 条回复*  
*评分体系: 10维度量化评估 (总分100分)*  
*版权: su3sl3h06*
`;

        // 创建下载
        const blob = new Blob([markdown], { type: 'text/markdown;charset=utf-8;' });
        const link = document.createElement('a');
        const url = URL.createObjectURL(blob);
        
        const filename = `v2ex_${username}_analysis_prompt_${new Date().getTime()}.md`;
        
        link.setAttribute('href', url);
        link.setAttribute('download', filename);
        link.style.visibility = 'hidden';
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);

        showToast(`成功导出分析提示词!\n文件名: ${filename}\n回复数: ${totalReplies} 条`);
    }

    // 复制Markdown内容到剪贴板
    async function copyMarkdownToClipboard() {
        if (allReplies.length === 0) {
            showToast('没有数据可以复制!');
            return;
        }

        try {
            // 获取用户名
            const username = window.location.pathname.match(/\/member\/([^\/]+)/)?.[1] || 'unknown_user';
            
            // 统计信息
            const totalReplies = allReplies.length;
            const boards = [...new Set(allReplies.map(r => r.板块))];
            const boardStats = {};
            allReplies.forEach(reply => {
                const board = reply.板块 || '未知';
                boardStats[board] = (boardStats[board] || 0) + 1;
            });
            const sortedBoards = Object.entries(boardStats).sort((a, b) => b[1] - a[1]);

            // 构建Markdown内容(与exportToMarkdown相同)
            let markdown = `# V2EX 用户画像分析任务

## 📋 任务说明

你是一位专业的用户行为分析师。现在需要你根据下方提供的V2EX用户回复数据,深入分析该用户的完整人物画像。

---

## 👤 分析对象

- **用户名**: ${username}
- **数据来源**: V2EX (一个面向创意工作者的中文社区)
- **回复总数**: ${totalReplies} 条
- **活跃板块数**: ${boards.length} 个
- **数据提取时间**: ${new Date().toLocaleString('zh-CN')}

---

## 📊 基础数据概览

### 板块活跃度统计(Top 10)

| 排名 | 板块名称 | 回复次数 | 占比 |
|------|---------|---------|------|
`;

            // 添加板块统计
            sortedBoards.slice(0, 10).forEach((item, index) => {
                const [board, count] = item;
                const percentage = ((count / totalReplies) * 100).toFixed(1);
                markdown += `| ${index + 1} | ${board} | ${count} | ${percentage}% |\n`;
            });

            markdown += `\n---

## 🧵 用户创建的主题(采样)

从用户创建的主题中抽取正文内容(最多展示30篇,用于辅助AI判断立场与真实度):

${(allTopics && allTopics.length ? allTopics : []).map((t, idx) => `### 主题 #${idx + 1}\n\n**节点**: ${t.节点 || '-'}  \n**标题**: ${t.标题 || '-'}\n\n**正文节选**:\n> ${(t.正文 || '').split('\n').slice(0, 12).join('\n> ')}\n\n---\n`).join('')}

## 💬 完整回复记录(最多500条)

以下为该用户的所有回复内容,按时间顺序排列(从新到旧):

`;

            // 添加所有回复
            allReplies.forEach((reply, index) => {
                markdown += `### 回复 #${index + 1}

时间: ${reply.时间}  
板块: ${reply.板块}  
主题: ${reply.主题标题}  
主题作者: ${reply.主题作者}  
回复内容:
> ${reply.回复内容.split('\n').join('\n> ')}

---

`;
            });

            // 添加分析要求(与exportToMarkdown相同的完整内容)
            markdown += `
---

## 🎯 分析任务要求

请基于以上所有回复数据,从以下维度深入分析该用户,并生成一份详细的**量化用户画像报告**。

**重要**: 每个维度必须按照给定的评分标准打分,不能凭主观感觉!

---

## 📊 评分标准与分析维度

### 1. 技术能力评估 💻 (1-10分)

**评分标准**:
- **1-3分**: 非技术用户,基本不涉及技术讨论
- **4-6分**: 技术爱好者,了解基础技术概念,偶尔讨论技术话题
- **7-8分**: 技术从业者,熟悉特定技术栈,经常分享技术见解
- **9-10分**: 技术专家,深入讨论底层原理,能解决复杂技术问题

**量化指标**:
- 技术相关回复占比: ____%
- 提及的技术关键词数量: ___个
- 技术深度(是否涉及原理/架构/底层): 是/否

**分析要点**:
- 主要技术栈(编程语言、框架、工具等)
- 技术广度与深度
- 是否有专业技术背景
- 对新技术的接受程度

**评分**: ___/10 分

---

### 2. 消费能力评估 💰 (1-10分)

**评分标准**:
- **1-3分**: 消费保守,注重性价比,多讨论如何省钱
- **4-6分**: 消费适中,偶尔购买中高端产品,理性消费
- **7-8分**: 消费能力较强,经常购买中高端产品,品质优先
- **9-10分**: 消费能力很强,购买高端/奢侈品,价格不敏感

**量化指标**:
- 提及的产品价格范围: ¥___ - ¥___
- 高价值物品(>5000元)提及次数: ___次
- 投资/理财相关讨论: ___次

**分析要点**:
- 提及的具体产品及价格(如手机、电脑、旅行等)
- 消费观念(性价比/品质/奢侈)
- 是否有投资理财意识
- 经济压力感知

**评分**: ___/10 分

---

### 3. 专业深度评估 🎓 (1-10分)

**评分标准**:
- **1-3分**: 泛泛而谈,缺乏专业见解
- **4-6分**: 在某些领域有一定见解,但不够深入
- **7-8分**: 在1-2个领域有专业见解,能给出专业建议
- **9-10分**: 多领域专家,回复经常被认可,有行业影响力

**量化指标**:
- 专业术语使用频率: 高/中/低
- 深度分析回复占比: ____%
- 被@请教的次数: ___次(从回复中推断)

**分析要点**:
- 专业领域识别(职业相关)
- 知识深度与广度
- 是否经常解答他人问题
- 专业表达能力

**评分**: ___/10 分

---

### 4. 社交活跃度 👥 (1-10分)

**评分标准**:
- **1-3分**: 很少互动,回复简短,不主动交流
- **4-6分**: 适度互动,偶尔参与讨论,回复中等长度
- **7-8分**: 活跃互动,经常@他人,回复详细,乐于助人
- **9-10分**: 高度活跃,社区KOL,有固定交流圈子

**量化指标**:
- 平均回复长度: ___字
- @他人次数: ___次
- 回复情感倾向: 友善/中性/冷淡
- 活跃板块数量: ___个

**分析要点**:
- 交流主动性
- 互动频率和质量
- 是否有固定交流对象
- 社交风格(热情/礼貌/高冷)

**评分**: ___/10 分

---

### 5. 兴趣广度评估 🎮 (1-10分)

**评分标准**:
- **1-3分**: 兴趣单一,只关注1-2个领域
- **4-6分**: 兴趣适中,关注3-5个不同领域
- **7-8分**: 兴趣广泛,跨多个领域(科技/生活/娱乐等)
- **9-10分**: 兴趣极其广泛,涉猎各个领域,博学多才

**量化指标**:
- 涉及的主题类别数: ___个
- 话题分散度: 高/中/低
- 跨领域讨论占比: ____%

**分析要点**:
- 主要兴趣点列表
- 兴趣深度(入门/进阶/专家)
- 是否有特别突出的兴趣
- 兴趣是否与职业相关

**评分**: ___/10 分

---

### 6. 情绪稳定性 🧩 (1-10分)

**评分标准**:
- **1-3分**: 情绪波动大,经常抱怨/焦虑/愤怒
- **4-6分**: 情绪一般,偶尔流露负面情绪
- **7-8分**: 情绪稳定,多数回复平和理性
- **9-10分**: 情绪非常稳定,始终保持积极乐观态度

**量化指标**:
- 负面情绪词汇出现次数: ___次(如:郁闷、烦、气、无语等)
- 正面情绪词汇出现次数: ___次(如:开心、爽、赞、喜欢等)
- 中性客观回复占比: ____%

**分析要点**:
- 主要情绪倾向
- 压力/焦虑表现
- 对挫折的态度
- 生活满意度

**评分**: ___/10 分

---

### 7. 生活品质指数 🌟 (1-10分)

**评分标准**:
- **1-3分**: 生活压力大,多讨论省钱、焦虑、工作压力
- **4-6分**: 生活一般,工作生活平衡,偶尔享受生活
- **7-8分**: 生活品质较高,经常旅行/美食/娱乐
- **9-10分**: 生活品质很高,追求精致生活,时间自由

**量化指标**:
- 休闲娱乐相关回复: ___次
- 旅行/美食/爱好讨论: ___次
- 加班/压力相关吐槽: ___次

**分析要点**:
- 工作生活平衡
- 休闲娱乐方式
- 生活态度(积极/佛系/焦虑)
- 是否有生活追求

**评分**: ___/10 分

---

### 8. 影响力指数 🏆 (1-10分)

**评分标准**:
- **1-3分**: 无影响力,回复少人关注
- **4-6分**: 影响力一般,偶尔有高质量回复
- **7-8分**: 有一定影响力,回复经常被认可
- **9-10分**: 社区意见领袖,高质量输出,被广泛认可

**量化指标**:
- 回复质量(是否有深度见解): 高/中/低
- 是否解答他人问题: ___次
- 是否引发讨论: 是/否
- 回复被感谢的可能性: 高/中/低(从上下文推断)

**分析要点**:
- 内容质量
- 专业权威性
- 对他人的帮助程度
- 在社区的认可度

**评分**: ___/10 分

---

### 9. 学习成长力 📈 (1-10分)

**评分标准**:
- **1-3分**: 学习意愿低,少讨论新知识/新技术
- **4-6分**: 学习意愿一般,偶尔接触新事物
- **7-8分**: 学习意愿强,经常研究新技术/新领域
- **9-10分**: 持续学习,快速接受新事物,有成长型思维

**量化指标**:
- 提问/求教次数: ___次
- 学习/研究相关讨论: ___次
- 对新技术/新产品的关注度: 高/中/低

**分析要点**:
- 学习态度
- 对新事物的接受度
- 是否主动求知
- 成长型/固定型思维

**评分**: ___/10 分

---

### 10. 真实度/可信度 🎭 (1-10分)

**评分标准**:
- **1-3分**: 疑似水军/发帖员,频繁引战,内容前后矛盾,编故事明显
- **4-6分**: 部分内容夸张或不实,偶尔引战,但大部分内容真实
- **7-8分**: 内容基本真实可信,偶有夸张但无恶意
- **9-10分**: 高度真实,言行一致,内容经得起推敲,真诚度高

**量化指标**:
- 内容前后一致性: 高/中/低
- 引战/攻击性言论次数: ___次
- 疑似营销/广告内容: ___次
- 逻辑矛盾或编故事迹象: ___处

**重点识别特征**:

**🚩 发帖员/水军特征**:
- 短期内大量发帖/回复(不正常的活跃度)
- 重复发布相似内容或套路化回复
- 频繁推荐特定产品/服务/链接
- 账号注册时间短但活跃度极高
- 回复内容空洞,缺乏个人观点

**🚩 故意引战特征**:
- 频繁使用攻击性、煽动性语言
- 刻意挑起争议话题
- 对不同观点采取极端对立态度
- 喜欢"抬杠",缺乏建设性讨论
- 制造焦虑或贩卖恐慌

**🚩 编故事/造假特征**:
- 前后描述自相矛盾(职业/收入/经历不一致)
- 过度夸张的个人经历
- 时间线混乱(如"去年"的事在不同回复中日期不符)
- 细节模糊或经不起推敲
- 频繁更换人设或立场

**✅ 真实可信特征**:
- 长期稳定的发言风格
- 内容具体详细,有个人特色
- 前后观点一致,言行相符
- 分享真实经验教训(包括失败)
- 对话真诚,愿意承认不足

**分析要点**:
- 内容真实性(是否有明显编造迹象)
- 动机纯粹性(是否有营销/引导目的)
- 立场一致性(观点是否前后矛盾)
- 言行一致性(说的和做的是否匹配)
- 互动真诚度(回复是否真心还是套路)

**评分**: ___/10 分

---

### 11. 生活地域判断 🏠

**不评分,仅推断**

**分析要点**:
- **居住城市**: _____(根据讨论的地域板块、提及的地点)
- **证据强度**: 强/中/弱
- **可能的活动范围**: _____
- **是否有地域相关特征**: _____

---

## 📋 综合评价

### 综合画像卡片

| 维度 | 评分 | 等级 | 关键特征 |
|------|------|------|---------|
| 技术能力 | __/10 | 专家/从业者/爱好者/无 | _____ |
| 消费能力 | __/10 | 高/中高/中/中低/低 | _____ |
| 专业深度 | __/10 | 专家/资深/中级/初级 | _____ |
| 社交活跃度 | __/10 | 非常活跃/活跃/一般/不活跃 | _____ |
| 兴趣广度 | __/10 | 非常广泛/广泛/适中/单一 | _____ |
| 情绪稳定性 | __/10 | 非常稳定/稳定/一般/不稳定 | _____ |
| 生活品质 | __/10 | 优质/良好/一般/较差 | _____ |
| 影响力 | __/10 | KOL/活跃/普通/潜水 | _____ |
| 学习成长力 | __/10 | 强/较强/一般/弱 | _____ |
| 真实度/可信度 | __/10 | 高度真实/基本可信/存疑/疑似造假 | _____ |

**综合评分**: ___/100 分

---

### 用户画像总结 (200-300字)

[用一段话描述该用户的整体特征,包括:
- 基本信息(年龄段、地域、职业推断)
- 核心特征(最突出的2-3个特点)
- 兴趣爱好概况
- 性格特征
- 生活状态
- 最具代表性的标签]

---

### 特殊标签 🏷️

请根据分析给出3-5个最具代表性的标签:

\`#标签1\` \`#标签2\` \`#标签3\` \`#标签4\` \`#标签5\`

---

### 核心洞察 💡

**优势特征**(最突出的3个方面):
1. _____
2. _____
3. _____

**潜在需求**(可能感兴趣的3个方向):
1. _____
2. _____
3. _____

**性格特质**(MBTI参考):
- 可能的性格类型: _____
- 主要性格特征: _____

---

## 📋 输出格式要求

1. **严格按照评分标准打分**,不得凭感觉评分
2. **必须列出量化指标的具体数值**
3. **每个评分必须有具体的证据支撑**(引用回复内容)
4. **填写综合评价表格**
5. **生成200-300字的用户画像总结**
6. **给出3-5个标签**
7. **不用重新输出评分标准,只给出要求的结果**

---

## ⚡ 开始分析

请开始你的专业量化分析,注意:

✅ **量化优先**: 先统计量化指标,再基于数据打分  
✅ **证据支撑**: 每个结论都要引用具体回复  
✅ **客观准确**: 基于实际数据,不要过度臆测  
✅ **标准一致**: 严格按照评分标准,不得凭主观感觉  

---

*本文档由 V2EX 用户回复提取器自动生成*  
*提取时间: ${new Date().toLocaleString('zh-CN')}*  
*数据量: ${totalReplies} 条回复*  
*评分体系: 10维度量化评估 (总分100分)*  
*版权: su3sl3h06*
`;

            // 复制到剪贴板
            await navigator.clipboard.writeText(markdown);
            
            // 成功提示
            const toast = document.createElement('div');
            toast.style.cssText = `
                position: fixed;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                color: white;
                padding: 20px 40px;
                border-radius: 12px;
                box-shadow: 0 8px 32px rgba(102, 126, 234, 0.4);
                z-index: 10001;
                font-size: 16px;
                font-weight: bold;
                text-align: center;
                animation: fadeInOut 2s ease-in-out;
            `;
            toast.innerHTML = `
                <div style="font-size: 48px; margin-bottom: 10px;">✅</div>
                <div>复制成功!</div>
                <div style="font-size: 14px; margin-top: 8px; opacity: 0.9;">
                    ${totalReplies} 条回复已复制到剪贴板
                </div>
                <div style="font-size: 13px; margin-top: 8px; opacity: 0.8;">
                    现在可以粘贴到 ChatGPT/Claude 等AI工具
                </div>
            `;
            
            // 添加动画样式
            if (!document.getElementById('toast-animation-style')) {
                const style = document.createElement('style');
                style.id = 'toast-animation-style';
                style.textContent = `
                    @keyframes fadeInOut {
                        0% { opacity: 0; transform: translate(-50%, -50%) scale(0.8); }
                        15% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
                        85% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
                        100% { opacity: 0; transform: translate(-50%, -50%) scale(0.8); }
                    }
                `;
                document.head.appendChild(style);
            }
            
            document.body.appendChild(toast);
            
            // 2秒后自动移除提示
            setTimeout(() => {
                toast.remove();
            }, 2000);

        } catch (error) {
            console.error('复制失败:', error);
            showToast('复制失败!\n可能原因:\n- 浏览器不支持剪贴板API\n- 没有权限访问剪贴板\n\n建议使用"导出 MD 文件"功能');
        }
    }

    // 创建主页快捷按钮
    function createHomepageButton() {
        const button = document.createElement('div');
        button.id = 'reply-extractor-homepage-btn';
        button.innerHTML = `
            <div style="
                position: fixed;
                bottom: 80px;
                right: 20px;
                width: 160px;
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                color: white;
                padding: 15px 20px;
                border-radius: 12px;
                box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
                cursor: pointer;
                z-index: 10000;
                font-family: Arial, sans-serif;
                text-align: center;
                transition: all 0.3s ease;
            " onmouseover="this.style.transform='translateY(-3px)'; this.style.boxShadow='0 6px 20px rgba(102, 126, 234, 0.5)';" 
               onmouseout="this.style.transform='translateY(0)'; this.style.boxShadow='0 4px 15px rgba(102, 126, 234, 0.4)';">
                <div style="font-size: 24px; margin-bottom: 8px;">📊</div>
                <div style="font-size: 14px; font-weight: bold; margin-bottom: 4px;">提取用户回复</div>
                <div style="font-size: 11px; opacity: 0.9;">点击进入回复页</div>
            </div>
        `;
        
        button.addEventListener('click', function() {
            // 获取用户名
            const username = window.location.pathname.match(/\/member\/([^\/]+)/)?.[1];
            if (username) {
                // 跳转到回复页
                window.location.href = `/member/${username}/replies`;
            }
        });
        
        document.body.appendChild(button);
    }

    // 初始化
    function init() {
        // 检查是否在用户页面
        if (window.location.pathname.includes('/member/')) {
            const username = window.location.pathname.match(/\/member\/([^\/]+)/)?.[1];
            
            if (!username) return;
            
            // 判断是否在回复页
            if (window.location.pathname.includes('/replies')) {
                // 在回复页,显示完整控制面板
                createControlPanel();
                
                // 显示当前页面信息
                const pageInfo = getPageInfo();
                updateUI(pageInfo.currentPage, pageInfo.totalPages, 0, '等待中', 0);
            } else {
                // 在主页,显示快捷按钮
                createHomepageButton();
            }
        }
    }

    // 页面加载完成后初始化
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

})();