a2c8d1f4创建于 16 小时前历史提交
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Hello-Agents</title>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="description" content="Description">
    <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@latest/lib/themes/vue.css">
    <style>
        /* --- 1. 原有样式 (保留) --- */
        /* 语言切换按钮样式 */
        .lang-switch {
            position: fixed;
            top: 20px;
            right: 80px;
            z-index: 999;
        }
        .lang-switch button {
            background: #42b983;
            color: white;
            border: none;
            padding: 8px 16px;
            border-radius: 4px;
            cursor: pointer;
            font-size: 14px;
            transition: background 0.3s;
        }
        .lang-switch button:hover {
            background: #33a06f;
        }

        /* Giscus 评论区样式 */
        .giscus-container {
            margin-top: 60px;
            padding-top: 40px;
            border-top: 1px solid #eee;
        }

        /* 可折叠评论区标题 */
        .giscus-toggle {
            display: flex;
            align-items: center;
            justify-content: space-between;
            cursor: pointer;
            padding: 15px 20px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            border-radius: 8px;
            margin-bottom: 20px;
            transition: all 0.3s ease;
            box-shadow: 0 2px 8px rgba(102, 126, 234, 0.2);
        }

        .giscus-toggle:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
        }

        .giscus-toggle-title {
            font-size: 1.3em;
            font-weight: 600;
            color: white;
            margin: 0;
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .giscus-toggle-icon {
            font-size: 1.2em;
            transition: transform 0.3s ease;
            color: white;
        }

        .giscus-toggle-icon.expanded {
            transform: rotate(180deg);
        }

        .giscus-content {
            max-height: 0;
            overflow: hidden;
            transition: max-height 0.4s ease-out, opacity 0.3s ease;
            opacity: 0;
        }

        .giscus-content.expanded {
            max-height: 2000px;
            opacity: 1;
            transition: max-height 0.5s ease-in, opacity 0.4s ease;
        }

        .giscus-hint {
            font-size: 0.9em;
            color: rgba(255, 255, 255, 0.9);
            margin: 0;
        }

        /* --- 2. 新增:暗黑模式样式 (Dark Mode Styles) --- */
        :root {
            --dark-bg: #1a1a1a;
            --dark-text: #c4c4c4;
            --dark-sidebar: #141414;
            --dark-code-bg: #2b2b2b;
            --dark-border: #333;
            --theme-color: #42b983;
        }

        /* 基础反色 */
        body.dark-mode {
            background-color: var(--dark-bg);
            color: var(--dark-text);
        }

        /* 侧边栏适配 */
        body.dark-mode .sidebar {
            background-color: var(--dark-sidebar);
            border-right: 1px solid var(--dark-border);
            color: var(--dark-text);
        }
        body.dark-mode .sidebar-nav li a {
            color: #999;
        }
        body.dark-mode .sidebar-nav li.active > a {
            color: var(--theme-color);
            border-right: 2px solid var(--theme-color);
        }

        /* 代码块适配 */
        body.dark-mode pre {
            background-color: var(--dark-code-bg) !important;
        }
        body.dark-mode code {
            background-color: var(--dark-code-bg) !important;
            color: #e0e0e0 !important;
        }
        body.dark-mode .markdown-section code {
            color: #f08d49;
            background-color: rgba(255,255,255,0.1);
        }

        /* 标题和引用适配 */
        body.dark-mode h1, body.dark-mode h2, body.dark-mode h3, body.dark-mode h4 {
            color: #e0e0e0;
        }
        body.dark-mode blockquote {
            color: #999;
            background: rgba(255,255,255,0.05);
            border-left-color: var(--theme-color);
        }

        /* 表格适配 */
        body.dark-mode .markdown-section tr:nth-child(2n) {
            background-color: rgba(255,255,255,0.03);
        }
        body.dark-mode .markdown-section td, 
        body.dark-mode .markdown-section th {
            border-color: var(--dark-border);
        }

        /* Mermaid 图表适配 (颜色反转) */
        body.dark-mode .mermaid {
            filter: invert(1) hue-rotate(180deg);
        }

        /* Giscus 容器边框适配 */
        body.dark-mode .giscus-container {
            border-top: 1px solid var(--dark-border);
        }

        /* --- 3. 新增:侧边栏开关按钮样式 --- */
        .sidebar-toggle-btn {
            cursor: pointer;
            display: block;
            text-align: center;
            padding: 10px 0;
            margin: 0 15px 10px 15px;
            font-weight: bold;
            font-size: 14px;
            border-radius: 4px;
            background-color: rgba(0,0,0,0.05);
            color: #505d6b;
            border: 1px solid rgba(0,0,0,0.05);
            transition: all 0.3s;
        }
        body.dark-mode .sidebar-toggle-btn {
            background-color: rgba(255,255,255,0.1);
            color: #ccc;
            border: 1px solid #444;
        }
        .sidebar-toggle-btn:hover {
            background-color: var(--theme-color);
            color: white;
        }
    </style>
</head>

<body>
    <!-- 语言切换按钮 -->
    <div class="lang-switch">
        <button id="langBtn" onclick="switchLanguage()">English</button>
    </div>
    <div id="app"></div>
    <script src="//cdn.jsdelivr.net/npm/mermaid@8.0.0-rc.8/dist/mermaid.min.js"></script>
    <script>
        window.$docsify = {
            name: 'Hello-Agents',
            repo: 'https://github.com/datawhalechina/Hello-Agents',
            loadSidebar: true,
            auto2top: true,
            subMaxLevel: 3,
            relativePath: false,
            alias: {
                // 英文路径映射
                '/en/README.md': '/README_EN.md',
                '/en/_sidebar.md': '/_sidebar_en.md',
                '/en/.*/_sidebar.md': '/_sidebar_en.md',
                '/en/chapter(\\d+)/Chapter(.*)': '/chapter$1/Chapter$2',

                // 默认中文侧边栏
                '/_sidebar.md': '/_sidebar.md',
                '/.*/_sidebar.md': '/_sidebar.md'
            },
            pagination: {
                previousText: '上一章节',
                nextText: '下一章节',
            },
            count: {
                countable: true,
                fontsize: '0.9em',
                color: 'rgb(90,90,90)',
                language: 'chinese'
            },
            // 多语言配置
            fallbackLanguages: ['en'],
            nameLink: {
                '/en/': '#/en/',
                '/': '#/'
            },
            // 使用钩子动态处理侧边栏
            plugins: [
                // --- 新增:暗黑模式开关插件 ---
                function(hook, vm) {
                    hook.doneEach(function() {
                        const sidebar = document.querySelector('.sidebar-nav');
                        // 防止重复添加
                        if (!sidebar || document.querySelector('.sidebar-toggle-btn')) return;

                        const btn = document.createElement('div');
                        btn.className = 'sidebar-toggle-btn';
                        
                        // 初始化状态
                        const savedTheme = localStorage.getItem('theme-mode');
                        if (savedTheme === 'dark') {
                            document.body.classList.add('dark-mode');
                            btn.textContent = '🌙 Switch to Light';
                        } else {
                            btn.textContent = '☀️ Switch to Dark';
                        }

                        // 核心:点击事件
                        btn.onclick = function() {
                            // 1. 切换类名
                            document.body.classList.toggle('dark-mode');
                            const isDark = document.body.classList.contains('dark-mode');
                            
                            // 2. 保存状态
                            localStorage.setItem('theme-mode', isDark ? 'dark' : 'light');
                            
                            // 3. 更新按钮文字
                            btn.textContent = isDark ? '🌙 Switch to Light' : '☀️ Switch to Dark';
                            
                            // 4. 关键:通知 Giscus 切换主题 (无需刷新)
                            const iframe = document.querySelector('iframe.giscus-frame');
                            if (iframe) {
                                iframe.contentWindow.postMessage({
                                    giscus: {
                                        setConfig: {
                                            theme: isDark ? 'dark' : 'light'
                                        }
                                    }
                                }, 'https://giscus.app');
                            }
                        };

                        // 插入到侧边栏最顶部
                        sidebar.insertBefore(btn, sidebar.firstChild);
                    });
                },

                // --- 原有逻辑:语言偏好处理 ---
                function(hook, vm) {
                    // 在每次路由变化时检查语言偏好
                    hook.beforeEach(function(content) {
                        const preferredLang = localStorage.getItem('preferredLanguage');
                        const currentPath = vm.route.path;

                        // 根据当前路径或语言偏好更新分页文本
                        if (currentPath.includes('/en/') || preferredLang === 'en') {
                            window.$docsify.pagination.previousText = 'Previous';
                            window.$docsify.pagination.nextText = 'Next';
                        } else {
                            window.$docsify.pagination.previousText = '上一章节';
                            window.$docsify.pagination.nextText = '下一章节';
                        }

                        return content;
                    });

                    // 在页面渲染后添加 Giscus 评论区
                    hook.doneEach(function() {
                        // 检查是否是章节页面(排除首页和前言)
                        const currentPath = vm.route.path;
                        const isChapterPage = currentPath.includes('chapter') ||
                                             currentPath.includes('Chapter') ||
                                             currentPath.includes('第') && currentPath.includes('章');

                        if (!isChapterPage) {
                            return; // 非章节页面不显示评论区
                        }

                        // 移除旧的评论区
                        const oldGiscus = document.querySelector('.giscus-container');
                        if (oldGiscus) {
                            oldGiscus.remove();
                        }

                        // 创建评论区容器
                        const giscusContainer = document.createElement('div');
                        giscusContainer.className = 'giscus-container';

                        // 获取语言设置
                        const preferredLang = localStorage.getItem('preferredLanguage');
                        const isEnglish = currentPath.includes('/en/') || preferredLang === 'en';

                        // --- 获取当前主题状态 (新增逻辑) ---
                        // 这里是为了在创建 Giscus 时就设置正确的初始主题
                        const isDarkMode = document.body.classList.contains('dark-mode');

                        // 创建可折叠的标题栏
                        const toggleButton = document.createElement('div');
                        toggleButton.className = 'giscus-toggle';

                        const titleDiv = document.createElement('div');
                        titleDiv.className = 'giscus-toggle-title';
                        titleDiv.innerHTML = isEnglish
                            ? '💬 Discussion & Questions'
                            : '💬 讨论与提问';

                        const hintText = document.createElement('p');
                        hintText.className = 'giscus-hint';
                        hintText.textContent = isEnglish
                            ? 'Click to expand/collapse'
                            : '点击展开/收起';

                        const iconSpan = document.createElement('span');
                        iconSpan.className = 'giscus-toggle-icon';
                        iconSpan.textContent = '▼';

                        const titleWrapper = document.createElement('div');
                        titleWrapper.appendChild(titleDiv);
                        titleWrapper.appendChild(hintText);

                        toggleButton.appendChild(titleWrapper);
                        toggleButton.appendChild(iconSpan);

                        // 创建评论内容容器
                        const contentDiv = document.createElement('div');
                        contentDiv.className = 'giscus-content';

                        // 创建 Giscus 脚本
                        const giscusScript = document.createElement('script');
                        giscusScript.src = 'https://giscus.app/client.js';
                        giscusScript.setAttribute('data-repo', 'datawhalechina/hello-agents');
                        giscusScript.setAttribute('data-repo-id', 'R_kgDOPrUECg');
                        giscusScript.setAttribute('data-category', '💬 Exercises & Q&A');
                        giscusScript.setAttribute('data-category-id', 'DIC_kwDOPrUECs4Cxfyu');
                        giscusScript.setAttribute('data-mapping', 'pathname');
                        giscusScript.setAttribute('data-strict', '0');
                        giscusScript.setAttribute('data-reactions-enabled', '1');
                        giscusScript.setAttribute('data-emit-metadata', '0');
                        giscusScript.setAttribute('data-input-position', 'top');
                        
                        // --- 修改:强制跟随当前 dark-mode 状态 ---
                        // 如果当前 body 有 dark-mode 类,则初始化为 'dark',否则 'light'
                        giscusScript.setAttribute('data-theme', isDarkMode ? 'dark' : 'light');
                        
                        giscusScript.setAttribute('data-lang', isEnglish ? 'en' : 'zh-CN');
                        giscusScript.setAttribute('data-loading', 'lazy');
                        giscusScript.crossOrigin = 'anonymous';
                        giscusScript.async = true;

                        contentDiv.appendChild(giscusScript);

                        // 组装评论区
                        giscusContainer.appendChild(toggleButton);
                        giscusContainer.appendChild(contentDiv);

                        // 添加折叠/展开功能
                        let isExpanded = false;
                        toggleButton.addEventListener('click', function() {
                            isExpanded = !isExpanded;
                            if (isExpanded) {
                                contentDiv.classList.add('expanded');
                                iconSpan.classList.add('expanded');
                            } else {
                                contentDiv.classList.remove('expanded');
                                iconSpan.classList.remove('expanded');
                            }
                        });

                        // 将评论区添加到内容区域
                        const article = document.querySelector('article.markdown-section');
                        if (article) {
                            article.appendChild(giscusContainer);
                        }
                    });
                }
            ]
        }
    </script>
    <!-- Put them above docsify.min.js -->
    <script src="//cdn.jsdelivr.net/npm/docsify@latest/lib/docsify.min.js"></script>
    <!-- code render-->
    <script src="//cdn.jsdelivr.net/npm/prismjs@latest/components/prism-bash.js"></script>
    <script src="//cdn.jsdelivr.net/npm/prismjs@latest/components/prism-python.js"></script>
    <script src="//cdn.jsdelivr.net/npm/docsify-pagination@latest/dist/docsify-pagination.min.js"></script>
    <script src="//cdn.jsdelivr.net/npm/docsify-copy-code"></script>

    <!-- 新增:图片放大插件 (官方) -->
    <script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/zoom-image.min.js"></script>

    <script src="https://cdn.jsdelivr.net/npm/katex@latest/dist/katex.min.js"></script>
    <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/katex@latest/dist/katex.min.css" />
    <script src="https://cdn.jsdelivr.net/npm/marked@3"></script>
    <!-- CDN files for docsify-katex -->
    <script src="//cdn.jsdelivr.net/npm/docsify-katex@latest/dist/docsify-katex.js"></script>
    <!-- 字数统计 -->
    <script src="//unpkg.com/docsify-count/dist/countable.js"></script>

    <!-- 语言切换脚本 (保留原样) -->
    <script>
        // 章节文件名映射
        const chapterMapping = {
            // 中文 -> 英文
            'zh2en': {
                'README.md': 'README_EN.md',
                '前言.md': 'Preface.md',
                '第一章 初识智能体.md': 'Chapter1-Introduction-to-Agents.md',
                '第二章 智能体发展史.md': 'Chapter2-History-of-Agents.md',
                '第三章 大语言模型基础.md': 'Chapter3-Fundamentals-of-Large-Language-Models.md',
                '第四章 智能体经典范式构建.md': 'Chapter4-Building-Classic-Agent-Paradigms.md',
                '第五章 基于低代码平台的智能体搭建.md': 'Chapter5-Building-Agents-with-Low-Code-Platforms.md',
                '第六章 框架开发实践.md': 'Chapter6-Framework-Development-Practice.md',
                '第七章 构建你的Agent框架.md': 'Chapter7-Building-Your-Agent-Framework.md',
                '第八章 记忆与检索.md': 'Chapter8-Memory-and-Retrieval.md',
                '第九章 上下文工程.md': 'Chapter9-Context-Engineering.md',
                '第十章 智能体通信协议.md': 'Chapter10-Agent-Communication-Protocols.md',
                '第十一章 Agentic-RL.md': 'Chapter11-Agentic-RL.md',
                '第十二章 智能体性能评估.md': 'Chapter12-Agent-Performance-Evaluation.md',
                '第十三章 智能旅行助手.md': 'Chapter13-Intelligent-Travel-Assistant.md',
                '第十四章 自动化深度研究智能体.md': 'Chapter14-Automated-Deep-Research-Agent.md',
                '第十五章 构建赛博小镇.md': 'Chapter15-Building-Cyber-Town.md',
                '第十六章 毕业设计.md': 'Chapter16-Graduation-Project.md'
            },
            // 英文 -> 中文
            'en2zh': {
                'README_EN.md': 'README.md',
                'Preface.md': '前言.md',
                'Chapter1-Introduction-to-Agents.md': '第一章 初识智能体.md',
                'Chapter2-History-of-Agents.md': '第二章 智能体发展史.md',
                'Chapter3-Fundamentals-of-Large-Language-Models.md': '第三章 大语言模型基础.md',
                'Chapter4-Building-Classic-Agent-Paradigms.md': '第四章 智能体经典范式构建.md',
                'Chapter5-Building-Agents-with-Low-Code-Platforms.md': '第五章 基于低代码平台的智能体搭建.md',
                'Chapter6-Framework-Development-Practice.md': '第六章 框架开发实践.md',
                'Chapter7-Building-Your-Agent-Framework.md': '第七章 构建你的Agent框架.md',
                'Chapter8-Memory-and-Retrieval.md': '第八章 记忆与检索.md',
                'Chapter9-Context-Engineering.md': '第九章 上下文工程.md',
                'Chapter10-Agent-Communication-Protocols.md': '第十章 智能体通信协议.md',
                'Chapter11-Agentic-RL.md': '第十一章 Agentic-RL.md',
                'Chapter12-Agent-Performance-Evaluation.md': '第十二章 智能体性能评估.md',
                'Chapter13-Intelligent-Travel-Assistant.md': '第十三章 智能旅行助手.md',
                'Chapter14-Automated-Deep-Research-Agent.md': '第十四章 自动化深度研究智能体.md',
                'Chapter15-Building-Cyber-Town.md': '第十五章 构建赛博小镇.md',
                'Chapter16-Graduation-Project.md': '第十六章 毕业设计.md'
            }
        };

        function switchLanguage() {
            const currentHash = window.location.hash;
            const langBtn = document.getElementById('langBtn');

            // 检测当前语言
            if (currentHash.includes('/en/')) {
                // 从英文切换到中文
                localStorage.setItem('preferredLanguage', 'zh');

                let newHash = currentHash.replace('#/', '').replace('en/', '');

                // 提取文件名
                const parts = newHash.split('/');
                const filename = parts[parts.length - 1];

                // 查找对应的中文文件名
                if (chapterMapping.en2zh[filename]) {
                    parts[parts.length - 1] = chapterMapping.en2zh[filename];
                    newHash = '#/' + parts.join('/');
                } else {
                    newHash = '#/';
                }

                window.location.hash = newHash;
                langBtn.textContent = 'English';
                window.$docsify.pagination.previousText = '上一章节';
                window.$docsify.pagination.nextText = '下一章节';
            } else {
                // 从中文切换到英文
                localStorage.setItem('preferredLanguage', 'en');

                let path = currentHash.replace('#/', '');

                if (path === '' || path === '/') {
                    // 首页
                    window.location.hash = '#/en/README_EN.md';
                } else {
                    // 提取文件名
                    const parts = path.split('/');
                    const filename = parts[parts.length - 1];

                    // 查找对应的英文文件名
                    if (chapterMapping.zh2en[filename]) {
                        parts[parts.length - 1] = chapterMapping.zh2en[filename];
                        window.location.hash = '#/en/' + parts.join('/');
                    } else {
                        window.location.hash = '#/en/README_EN.md';
                    }
                }

                langBtn.textContent = '中文';
                window.$docsify.pagination.previousText = 'Previous';
                window.$docsify.pagination.nextText = 'Next';
            }

            // 重新加载页面以应用新的 sidebar
            window.location.reload();
        }

        // 页面加载时设置按钮文本和检查语言偏好
        window.addEventListener('load', function() {
            const currentHash = window.location.hash;
            const langBtn = document.getElementById('langBtn');
            const preferredLang = localStorage.getItem('preferredLanguage');

            // 只有在用户明确设置了语言偏好后,才自动切换
            // 首次访问(没有偏好设置)时,默认显示中文版
            if (preferredLang) {
                // 如果用户有语言偏好,且当前 URL 不匹配偏好,则自动切换
                if (preferredLang === 'en' && !currentHash.includes('/en/')) {
                    // 用户偏好英文,但当前是中文页面
                    let path = currentHash.replace('#/', '');

                    if (path === '' || path === '/') {
                        window.location.hash = '#/en/README_EN.md';
                    } else {
                        const parts = path.split('/');
                        const filename = parts[parts.length - 1];

                        if (chapterMapping.zh2en[filename]) {
                            parts[parts.length - 1] = chapterMapping.zh2en[filename];
                            window.location.hash = '#/en/' + parts.join('/');
                        }
                    }
                } else if (preferredLang === 'zh' && currentHash.includes('/en/')) {
                    // 用户偏好中文,但当前是英文页面
                    let newHash = currentHash.replace('#/', '').replace('en/', '');
                    const parts = newHash.split('/');
                    const filename = parts[parts.length - 1];

                    if (chapterMapping.en2zh[filename]) {
                        parts[parts.length - 1] = chapterMapping.en2zh[filename];
                        window.location.hash = '#/' + parts.join('/');
                    }
                }
            }

            // 设置按钮文本
            if (currentHash.includes('/en/')) {
                langBtn.textContent = '中文';
            } else {
                langBtn.textContent = 'English';
            }
        });
    </script>
</body>

</html>