首页 时政热点 科技头条 智能AI 安全攻防 数码硬件 开发者生态 归档 标签 关于

通过 API 在三个真实的 ML 和编码工作流程上测试 MiniMax M2.7

2026-05-20 1 阅读 约7分钟阅读 Artgor
分享:
字号:
通过 API 在三个真实的 ML 和编码工作流程上测试 MiniMax M2.7 我最近获得了一些 MiniMax M2.7 API 积分,因此我决定将此模型直接插入 Claude Code 中,并在我经常执行的三个工作流程上运行它。使用 Claude Opus 4.7 作为比较基线运行相同的任务。三个工作流程:为活跃的 Kaggle 竞赛搭建一个条目,为我的 ObsidianVault 起草和审核知识库笔记,以及更新一个过时的旧 PyTorch 项目。我想了解当任务有明确的边界时,M2.7 在代理循环中的工作效果如何。三次运行的结果是一致的:当约束明确并且输出格式具体时,M2.7 很有用。尽管 Opus 4.7 中也出现了一些相同的差距,但当重要的上下文被隐含时,它就陷入了困境。对于更开放式的案例,我仍然会在循环中保留人工审核通过。设置 我添加了一个 claude-mm 命令,将 Claude Code 指向 MiniMax API,并在 CC 界面中将思维设置为 max 来运行 M2.7。我在 MiniMax 的 Plus 层(高速,40 美元/月)上运行,其中上下文窗口和每日吞吐量不再成为多步骤代理工作的瓶颈。 claude-mm () { ANTHROPIC_BASE_URL = "https://api.minimax.io/anthropic" \ ANTHROPIC_AUTH_TOKEN = " $MINIMAX_API_KEY " \ ANTHROPIC_MODEL = "MiniMax-M2.7" \ ANTHROPIC_DEFAULT_SONNET_MODEL = "MiniMax-M2.7" \ ANTHROPIC_DEFAULT_OPUS_MODEL = "MiniMax-M2.7" \ ANTHROPIC_DEFAULT_HAIKU_MODEL = "MiniMax-M2.7" \ ANTHROPIC_SMALL_FAST_MODEL = "MiniMax-M2.7" \ API_TIMEOUT_MS = "3000000" \ CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = "1" \ claude " $@ " } 在代理工作中,线束与模型本身一样重要。我在下面描述的大多数失败都有类似的原因:提示没有明确说明任务所依赖的约束,并且模型用合理的默认值填补了空白。在实践中,模型质量和线束设计很难分开。更强的模型可能会推断出缺失的约束;更好的利用可以使这些限制变得明确。我将其视为工作流程测试,而不是纯粹的模型基准。重构旧的 PyTorch 项目 第一个工作流程是重构:我的 pytorch_tempest 存储库是一个使用 Hydra + PyTorch Lightning 训练神经网络的框架。我想要更新依赖项、现代化工具并清理随着时间的推移积累的代码问题。合并的结果是 PR:重构旧代码并更新依赖项。更改:更新了 CI 版本和预提交挂钩。将 black 和 flake8 替换为 ruff,以实现脱毛和格式化。在 Lightning 训练器配置中启用 fsdp_sharding_strategy。刷新了文档。添加了用于环境管理的紫外线。切换到现代 Python 类型( list[X] 超过 List[X] , X | None 超过Optional[X] )。删除了重复的代码路径。修复了很多小问题。我明确指导了 M2.7:提供了分步要求(“将 black + flake8 切换为 ruff”、“更新预提交配置”),在进行下一个更改之前审查每个更改,并在差异超出范围时提供反馈。我进行了足够的测试来检查更改后是否有任何问题,并且重新运行模型训练只需要几分钟。我在运行 CI 时遇到了一些挑战,代理帮助我一一解决了这些问题。我认识的很多工程师不想让代理自由支配他们关心的代码库;他们想要监督执行并了解每一行现有的代码。 M2.7 非常适合这种方法。您可以编写简短的、范围狭窄的提示,进行行级审查,然后进入下一步。 ObsidianVault 的知识笔记第二个工作流程是为我的 ObsidianVault 编写和审核笔记,我在那里保存了 ML 参考笔记。大部分都是我手写的;有时我会让法学硕士起草一个平行版本来进行比较并从中获取灵感。重要的是要记住,不同的模型喜欢不同的提示样式。针对 Opus 4.7 调整的 100 行提示不会一对一传输到 M2.7。为了解决这个问题,我做了一个小的引导程序:我要求两个模型从相同的起始提示生成注释,然后要求 M2.7 读取这两个注释并为自己提出改进的提示。下一次迭代使用了 M2.7 调整的提示符。我使用了两个提示(一个 writer 命令和一个 Critic 代理),每个提示大约 100 行。这是第一个的精简版本:在 DSWoK 库中填充一个断开的链接存根:研究主题,用 DSWoK 语音起草注释,运行 Draft-critic-mm,保存到正确的文件夹。 1. 阅读上下文:写作风格指南、frontmatter 分类法、别名规则。 2. 选择存根。 3. 查找引用 — 在 Vault 中查找 [[]]。 4. 根据主题组选择目标文件夹。 5. 从相邻的笔记中找到结构模板。 6. 通过 3-5 个来源进行研究,搜索优先——不要相信引用记忆、公式约定或 2024 年后的工作。 6.5.验证eac </div> <!-- Phase 7: 社交分享按钮 --> <div class="mt-8 pt-6 border-t"> <div class="flex items-center gap-2 md:gap-3 flex-wrap"> <span class="text-sm text-gray-500 font-medium">分享文章:</span> <!-- 微博 --> <a href="#" onclick="shareToWeibo(event)" class="share-btn flex items-center gap-1 px-3 py-2 bg-red-500 text-white text-sm rounded-lg hover:bg-red-600 transition"> <svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"><path d="M10.098 20c-4.038 0-7.32-1.948-7.32-4.345 0-2.397 3.282-4.345 7.32-4.345 4.037 0 7.32 1.948 7.32 4.345 0 2.397-3.283 4.345-7.32 4.345zm10.577-7.97c-.34-.166-1.327-.485-2.37-.748-.394-.1-.67-.17-.67-.17s.03-.27.03-.61c0-1.94-.96-4.23-2.38-4.23-.55 0-.91.23-1.13.49-.1-1.13-.39-1.82-1.28-1.82-.88 0-1.18.55-1.28 1.82-.22-.26-.58-.49-1.13-.49-1.42 0-2.38 2.29-2.38 4.23 0 .34.03.61.03.61s-.28.07-.67.17c-1.04.26-2.03.58-2.37.748-.34.167-.55.417-.55.697 0 .28.21.53.55.7.34.17 1.33.49 2.37.75.39.1.67.17.67.17s-.03.27-.03.61c0 1.94.96 4.23 2.38 4.23.55 0 .91-.23 1.13-.49.1 1.13.39 1.82 1.28 1.82.88 0 1.18-.55 1.28-1.82.22.26.58.49 1.13.49 1.42 0 2.38-2.29 2.38-4.23 0-.34-.03-.61-.03-.61s.28-.07.67-.17c1.04-.26 2.03-.58 2.37-.75.34-.17.55-.42.55-.7 0-.28-.21-.53-.55-.7z"/></svg> <span class="hidden sm:inline">微博</span> </a> <!-- QQ --> <a href="#" onclick="shareToQQ(event)" class="share-btn flex items-center gap-1 px-3 py-2 bg-blue-500 text-white text-sm rounded-lg hover:bg-blue-600 transition"> <svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"><path d="M12.003 0c-3.314 0-6.003 2.687-6.003 6.003 0 3.313 2.689 6.002 6.003 6.002 3.312 0 6.002-2.689 6.002-6.002C18.005 2.687 15.315 0 12.003 0z"/></svg> <span class="hidden sm:inline">QQ</span> </a> <!-- 微信 --> <a href="#" onclick="shareToWechat(event)" class="share-btn flex items-center gap-1 px-3 py-2 bg-green-500 text-white text-sm rounded-lg hover:bg-green-600 transition"> <svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"><path d="M8.691 2.188C3.891 2.188 0 5.476 0 9.53c0 2.212 1.17 4.203 3.002 5.55a.59.59 0 0 1 .213.665l-.39 1.48c-.019.07-.048.141-.048.213 0 .163.13.295.29.295a.326.326 0 0 0 .167-.054l1.903-1.114a.864.864 0 0 1 .717-.098 10.16 10.16 0 0 0 2.837.403c.276 0 .55-.012.821-.034-.27-.832-.418-1.71-.418-2.623 0-4.266 3.834-7.73 8.564-7.73.283 0 .558.018.835.044C17.262 3.892 13.326 2.188 8.691 2.188z"/></svg> <span class="hidden sm:inline">微信</span> </a> <!-- 复制链接 --> <a href="#" onclick="copyLink(event)" class="share-btn flex items-center gap-1 px-3 py-2 bg-gray-600 text-white text-sm rounded-lg hover:bg-gray-700 transition"> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"/> </svg> <span class="hidden sm:inline">复制链接</span> </a> </div> </div> <!-- 来源链接 --> <footer class="mt-6 pt-6 border-t"> <a href="https://andlukyane.com//blog/minimax-m27-workflows" target="_blank" rel="noopener noreferrer" class="inline-flex items-center px-4 py-3 md:py-2 bg-primary text-white rounded-lg hover:bg-opacity-90 transition touch-target"> <span>阅读原文</span> <svg class="w-4 h-4 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"/> </svg> </a> </footer> </div> <!-- Phase 13: User Feedback --> <div class="phase13-feedback mt-6 bg-gray-50 rounded-xl p-4"> <div class="flex items-center gap-4 flex-wrap"> <span class="text-sm font-medium text-gray-700">这篇文章对您有帮助吗?</span> <button onclick="submitFeedback('useful')" id="fb-useful" class="px-3 py-1.5 bg-green-50 text-green-600 rounded-lg text-sm hover:bg-green-100 transition border border-green-200"> 👍 有用 </button> <button onclick="submitFeedback('useless')" id="fb-useless" class="px-3 py-1.5 bg-gray-50 text-gray-500 rounded-lg text-sm hover:bg-gray-100 transition border border-gray-200"> 👎 无用 </button> <button onclick="submitFeedback('error_report')" id="fb-error" class="px-3 py-1.5 bg-red-50 text-red-500 rounded-lg text-sm hover:bg-red-100 transition border border-red-200"> 🐛 报错 </button> </div> <div id="fb-stats" class="text-xs text-gray-400 mt-2"></div> </div> <!-- Phase 11: Ad slot - article_bottom --> <div id="ad-article-bottom" class="ad-slot my-4" data-position="article_bottom"></div> <!-- Phase 10: 邮件订阅小部件 --> <div class="mt-6 bg-gray-50 border border-gray-200 rounded-xl p-6 text-center"> <h3 class="text-lg font-semibold text-primary mb-2">订阅66必读</h3> <p class="text-sm text-gray-500 mb-4">每日精选科技资讯,直达你的邮箱</p> <form onsubmit="handleSubscribe(event)" class="flex gap-2 max-w-md mx-auto"> <input type="email" name="email" placeholder="输入邮箱地址" required class="flex-1 px-4 py-2.5 border border-gray-300 rounded-lg text-sm outline-none focus:border-blue-500"> <button type="submit" class="px-5 py-2.5 bg-blue-600 text-white rounded-lg text-sm font-medium hover:bg-blue-700 transition whitespace-nowrap">订阅</button> </form> <p id="subscribeMsg" class="text-xs mt-2 hidden"></p> </div> <!-- 返回分类 --> <div class="mt-6 flex items-center justify-between"> <a href="/category/开发者生态" class="text-primary hover:text-accent transition text-sm md:text-base"> ← 返回 开发者生态 </a> </div> <!-- Phase 9: 相关推荐移动端单列布局 --> </article> <!-- 侧边栏 --> <aside class="lg:w-80 space-y-6 hidden lg:block"> <!-- 相关推荐 --> <!-- Phase 11: Ad slot - article_sidebar --> <div id="ad-article-sidebar" class="ad-slot" data-position="article_sidebar"></div> <!-- 分类 --> <div class="bg-white rounded-xl shadow-sm p-5"> <h3 class="font-bold text-primary mb-4">分类</h3> <div class="flex flex-wrap gap-2"> <a href="/category/shizheng" class="text-xs px-3 py-1.5 bg-gray-100 rounded-full hover:bg-primary/10 hover:text-primary transition "> 时政热点 </a> <a href="/category/keji-toutiao" class="text-xs px-3 py-1.5 bg-gray-100 rounded-full hover:bg-primary/10 hover:text-primary transition "> 科技头条 </a> <a href="/category/zhineng-ai" class="text-xs px-3 py-1.5 bg-gray-100 rounded-full hover:bg-primary/10 hover:text-primary transition "> 智能AI </a> <a href="/category/anquan" class="text-xs px-3 py-1.5 bg-gray-100 rounded-full hover:bg-primary/10 hover:text-primary transition "> 安全攻防 </a> <a href="/category/shuma" class="text-xs px-3 py-1.5 bg-gray-100 rounded-full hover:bg-primary/10 hover:text-primary transition "> 数码硬件 </a> <a href="/category/kaifa-shengtai" class="text-xs px-3 py-1.5 bg-gray-100 rounded-full hover:bg-primary/10 hover:text-primary transition "> 开发者生态 </a> </div> </div> </aside> </div> </div> </main> <!-- Footer --> <footer class="bg-primary text-gray-300 py-12 pb-20 lg:pb-12"> <div class="max-w-7xl mx-auto px-4"> <div class="grid md:grid-cols-4 gap-8"> <!-- 关于 --> <div> <h3 class="text-lg font-bold text-white mb-4"> <span class="text-accent">66</span>66必读 </h3> <p class="text-sm text-gray-400 leading-relaxed"> 每日精选科技资讯、技术文章、安全动态 </p> </div> <!-- 快速链接 --> <div> <h4 class="font-bold text-white mb-4">快速链接</h4> <ul class="space-y-2 text-sm"> <li><a href="/" class="hover:text-accent transition">首页</a></li> <li><a href="/archive" class="hover:text-accent transition">归档</a></li> <li><a href="/tags" class="hover:text-accent transition">标签</a></li> <li><a href="/about" class="hover:text-accent transition">关于我们</a></li> <li><a href="/about#留言板" class="hover:text-accent transition">留言板</a></li> </ul> </div> <!-- 分类 --> <div> <h4 class="font-bold text-white mb-4">分类</h4> <ul class="space-y-2 text-sm"> <li><a href="/category/shizheng" class="hover:text-accent transition">时政热点</a></li> <li><a href="/category/keji-toutiao" class="hover:text-accent transition">科技头条</a></li> <li><a href="/category/zhineng-ai" class="hover:text-accent transition">智能AI</a></li> <li><a href="/category/anquan" class="hover:text-accent transition">安全攻防</a></li> <li><a href="/category/shuma" class="hover:text-accent transition">数码硬件</a></li> <li><a href="/category/kaifa-shengtai" class="hover:text-accent transition">开发者生态</a></li> </ul> </div> <!-- 联系方式 --> <div> <h4 class="font-bold text-white mb-4">联系方式</h4> <p class="text-sm text-gray-400">dongshushu@coze.email</p> </div> </div> <div class="border-t border-gray-700 mt-8 pt-8 text-center text-sm text-gray-500"> <p>© 2026 66必读. All rights reserved.</p> <p class="mt-1">本网站运营由董蜀黍授权 <a href="https://meowvis.com" target="_blank" rel="noopener" class="text-accent hover:text-accent-hover transition">喵维斯</a> - 智能AI运营</p> <p class="mt-2"><a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener" class="text-gray-500 hover:text-gray-400 transition">晋ICP备2020010642号-2</a></p> </div> </div> </footer> <!-- Phase 9: 移动端底部Tab栏 --> <nav id="mobile-tabbar"> <a href="/" class="tab-item "> <svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"/></svg> <span>首页</span> </a> <a href="/archive" class="tab-item "> <svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"/></svg> <span>归档</span> </a> <a href="/tags" class="tab-item "> <svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"/></svg> <span>标签</span> </a> <a href="/about" class="tab-item "> <svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg> <span>关于</span> </a> </nav> <!-- Phase 7: 返回顶部按钮 --> <button id="back-to-top" title="返回顶部"> <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 10l7-7m0 0l7 7m-7-7v18"/> </svg> </button> <script> // Phase 9: 移动端滑出式侧边栏 var mobileMenuBtn = document.getElementById('mobile-menu-btn'); var mobileSidebar = document.getElementById('mobile-sidebar'); var sidebarOverlay = document.getElementById('sidebar-overlay'); var sidebarClose = document.getElementById('sidebar-close'); function openSidebar() { mobileSidebar.classList.add('open'); sidebarOverlay.classList.add('visible'); document.body.style.overflow = 'hidden'; } function closeSidebar() { mobileSidebar.classList.remove('open'); sidebarOverlay.classList.remove('visible'); document.body.style.overflow = ''; } if (mobileMenuBtn) mobileMenuBtn.addEventListener('click', openSidebar); if (sidebarClose) sidebarClose.addEventListener('click', closeSidebar); if (sidebarOverlay) sidebarOverlay.addEventListener('click', closeSidebar); // 图片懒加载 - 对所有未设置loading属性的img添加lazy document.querySelectorAll('img:not([loading])').forEach(function(img) { img.setAttribute('loading', 'lazy'); }); // Service Worker 注册 (PWA) if ('serviceWorker' in navigator) { window.addEventListener('load', function() { navigator.serviceWorker.register('/sw.js').catch(function() {}); }); } // Phase 7: 阅读进度条 var progressBar = document.getElementById('reading-progress'); var backToTop = document.getElementById('back-to-top'); function updateScrollIndicators() { var scrollTop = window.pageYOffset || document.documentElement.scrollTop; var scrollHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight; var scrollPercent = scrollHeight > 0 ? (scrollTop / scrollHeight) * 100 : 0; progressBar.style.width = scrollPercent + '%'; // 返回顶部按钮显示/隐藏 if (scrollTop > 300) { backToTop.classList.add('visible'); } else { backToTop.classList.remove('visible'); } } window.addEventListener('scroll', updateScrollIndicators, { passive: true }); window.addEventListener('load', updateScrollIndicators); // Phase 8: Dark mode toggle var darkToggle = document.getElementById('dark-mode-toggle'); var iconSun = document.getElementById('icon-sun'); var iconMoon = document.getElementById('icon-moon'); function applyDarkMode(isDark) { if (isDark) { document.documentElement.classList.add('dark'); iconSun.classList.remove('hidden'); iconMoon.classList.add('hidden'); } else { document.documentElement.classList.remove('dark'); iconSun.classList.add('hidden'); iconMoon.classList.remove('hidden'); } } // Init: check localStorage first, then system preference (function() { var saved = localStorage.getItem('dark-mode'); var prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; var isDark = saved !== null ? saved === 'true' : prefersDark; applyDarkMode(isDark); })(); darkToggle.addEventListener('click', function() { var isDark = document.documentElement.classList.contains('dark'); applyDarkMode(!isDark); localStorage.setItem('dark-mode', String(!isDark)); }); // Phase 7: 返回顶部点击 backToTop.addEventListener('click', function() { window.scrollTo({ top: 0, behavior: 'smooth' }); }); </script> <script> // 对文章内容中的图片添加loading="lazy" document.querySelectorAll('#article-content img:not([loading])').forEach(function(img) { img.setAttribute('loading', 'lazy'); img.setAttribute('decoding', 'async'); }); // Phase 7: 社交分享功能 var articleUrl = 'https://www.66bd.net/article/7632'; var articleTitle = '通过 API 在三个真实的 ML 和编码工作流程上测试 MiniMax M2.7'; function shareToWeibo(e) { e.preventDefault(); var url = 'https://service.weibo.com/share/share.php?url=' + encodeURIComponent(articleUrl) + '&title=' + encodeURIComponent(articleTitle); window.open(url, '_blank', 'width=600,height=500'); } function shareToQQ(e) { e.preventDefault(); var url = 'https://connect.qq.com/widget/shareqq/index.html?url=' + encodeURIComponent(articleUrl) + '&title=' + encodeURIComponent(articleTitle); window.open(url, '_blank', 'width=600,height=500'); } function shareToWechat(e) { e.preventDefault(); var input = document.createElement('input'); input.value = articleUrl; document.body.appendChild(input); input.select(); try { document.execCommand('copy'); alert('链接已复制,请粘贴到微信中分享'); } catch(err) { prompt('请复制链接分享到微信:', articleUrl); } document.body.removeChild(input); } function copyLink(e) { e.preventDefault(); var input = document.createElement('input'); input.value = articleUrl; document.body.appendChild(input); input.select(); try { document.execCommand('copy'); var btn = e.currentTarget; var originalHTML = btn.innerHTML; btn.innerHTML = '<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>已复制'; setTimeout(function() { btn.innerHTML = originalHTML; }, 2000); } catch(err) { prompt('请手动复制链接:', articleUrl); } document.body.removeChild(input); } // Phase 10: 知乎分享 function shareToZhihu(e) { e.preventDefault(); var url = 'https://www.zhihu.com/search?q=' + encodeURIComponent(articleTitle); window.open(url, '_blank'); } // Phase 10: X/Twitter分享 function shareToTwitter(e) { e.preventDefault(); var url = 'https://twitter.com/intent/tweet?url=' + encodeURIComponent(articleUrl) + '&text=' + encodeURIComponent(articleTitle); window.open(url, '_blank', 'width=600,height=400'); } // Phase 10: 微信QR码分享 function shareToWechatQR(e) { e.preventDefault(); var modal = document.getElementById('wechatQRModal'); if (!modal) return; var qrImg = document.getElementById('wechatQRCode'); if (qrImg) { qrImg.src = 'https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=' + encodeURIComponent(articleUrl); } modal.classList.remove('hidden'); } function closeWechatQR() { var modal = document.getElementById('wechatQRModal'); if (modal) modal.classList.add('hidden'); } // Phase 10: 邮件订阅 function handleSubscribe(e) { e.preventDefault(); var form = e.target; var email = form.email.value.trim(); var msgEl = document.getElementById('subscribeMsg'); var btn = form.querySelector('button[type=submit]'); if (!email) return; btn.disabled = true; btn.textContent = '订阅中...'; fetch('/api/subscribe', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: email }) }).then(function(r) { return r.json(); }) .then(function(data) { msgEl.classList.remove('hidden'); if (data.success) { msgEl.style.color = '#16a34a'; msgEl.textContent = data.message || '订阅成功!'; form.reset(); } else { msgEl.style.color = '#dc2626'; msgEl.textContent = data.message || '订阅失败'; } btn.disabled = false; btn.textContent = '订阅'; }).catch(function() { msgEl.classList.remove('hidden'); msgEl.style.color = '#dc2626'; msgEl.textContent = '网络错误,请稍后重试'; btn.disabled = false; btn.textContent = '订阅'; }); } // Phase 11: User behavior tracking (function() { var articleId = 7632; var sessionId = localStorage.getItem('66bd_session') || ''; if (!sessionId) { sessionId = Array.from({length: 32}, function() { return Math.floor(Math.random() * 16).toString(16); }).join(''); localStorage.setItem('66bd_session', sessionId); } // Track page view if (navigator.sendBeacon) { var data = new Blob([JSON.stringify({ action: 'view', article_id: articleId, session_id: sessionId, referrer: document.referrer || '' })], {type: 'application/json'}); navigator.sendBeacon('/api/analytics/track', data); } else { fetch('/api/analytics/track', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ action: 'view', article_id: articleId, session_id: sessionId, referrer: document.referrer || '' }) }).catch(function() {}); } // Track share actions var shareActions = ['shareToWeibo', 'shareToQQ', 'shareToTwitter', 'shareToZhihu']; shareActions.forEach(function(fnName) { var orig = window[fnName]; if (typeof orig === 'function') { window[fnName] = function(e) { e.preventDefault(); var platform = fnName.replace('shareTo', '').toLowerCase(); fetch('/api/analytics/track', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({action: 'share', article_id: articleId, platform: platform, session_id: sessionId}) }).catch(function() {}); orig.call(this, e); }; } }); })(); // Phase 11: Load ads document.querySelectorAll('.ad-slot').forEach(function(slot) { var position = slot.getAttribute('data-position'); if (!position) return; fetch('/api/ads/position/' + position) .then(function(r) { return r.json(); }) .then(function(data) { if (data.success && data.data) { var ad = data.data; var html = ''; if (ad.image_url) { html = '<a href="' + (ad.target_url || '#') + '" target="_blank" rel="nofollow sponsored">' + '<img src="' + ad.image_url + '" alt="' + (ad.title || '') + '" class="w-full rounded-lg"></a>'; } else if (ad.content) { html = '<a href="' + (ad.target_url || '#') + '" target="_blank" rel="nofollow sponsored" ' + 'class="block p-3 bg-blue-50 rounded-lg text-sm text-blue-700 hover:bg-blue-100 transition">' + '<strong>' + (ad.title || '') + '</strong><br>' + ad.content + '</a>'; } else if (ad.title) { html = '<a href="' + (ad.target_url || '#') + '" target="_blank" rel="nofollow sponsored" ' + 'class="block p-3 bg-gray-50 rounded-lg text-sm text-gray-600 hover:bg-gray-100 transition">' + ad.title + '</a>'; } if (html) { slot.innerHTML = html; var link = slot.querySelector('a'); if (link) { link.addEventListener('click', function() { fetch('/api/ads/click', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ad_id: ad.id}) }).catch(function() {}); }); } } } }).catch(function() {}); }); // Phase 13: UX Enhancement Scripts (function() { // Font size adjustment var fontSize = 16; window.adjustFontSize = function(delta) { fontSize = Math.max(12, Math.min(24, fontSize + delta)); var content = document.getElementById('article-content'); if (content) { content.style.fontSize = fontSize + 'px'; content.style.lineHeight = '1.8'; } try { localStorage.setItem('66bd_fontsize', fontSize); } catch(e) {} }; try { var saved = parseInt(localStorage.getItem('66bd_fontsize')); if (saved && saved >= 12 && saved <= 24) { fontSize = saved; adjustFontSize(0); } } catch(e) {} // TOC generation window.toggleTOC = function() { var toc = document.getElementById('phase13-toc'); if (toc.classList.contains('hidden')) { var content = document.getElementById('article-content'); var headings = content ? content.querySelectorAll('h1,h2,h3,h4') : []; var list = document.getElementById('toc-list'); list.innerHTML = ''; if (headings.length === 0) { list.innerHTML = '<li class="text-xs text-gray-400">本文无目录结构</li>'; } else { headings.forEach(function(h, i) { h.id = h.id || 'heading-' + i; var li = document.createElement('li'); var a = document.createElement('a'); a.href = '#' + h.id; a.textContent = h.textContent.substring(0, 60); a.className = 'text-blue-600 hover:text-blue-800 hover:underline'; a.onclick = function(e) { e.preventDefault(); h.scrollIntoView({behavior:'smooth'}); }; li.appendChild(a); list.appendChild(li); }); } toc.classList.remove('hidden'); } else { toc.classList.add('hidden'); } }; // User feedback var articleIdFb = (window.location.pathname.match(/\/article\/(\d+)/) || [])[1]; window.submitFeedback = function(type) { if (!articleIdFb) return; var sessionId = localStorage.getItem('66bd_session') || ''; fetch('/api/feedback', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({article_id: parseInt(articleIdFb), feedback_type: type, session_id: sessionId}) }).then(function(r) { return r.json(); }) .then(function(data) { if (data.success) { var btnId = type === 'error_report' ? 'fb-error' : 'fb-' + type; var btn = document.getElementById(btnId); if (btn) { btn.classList.add('ring-2', 'ring-green-300'); } loadFeedbackStats(); } }).catch(function() {}); }; function loadFeedbackStats() { if (!articleIdFb) return; fetch('/api/feedback/' + articleIdFb) .then(function(r) { return r.json(); }) .then(function(data) { if (data.success) { var el = document.getElementById('fb-stats'); if (el) { el.textContent = '有用 ' + data.useful + ' | 无用 ' + data.useless + ' | 报错 ' + data.error_report; } } }).catch(function() {}); } if (articleIdFb) { setTimeout(loadFeedbackStats, 500); } })(); </script> <!-- Phase 10: 微信QR码弹窗 --> <div id="wechatQRModal" class="hidden fixed inset-0 bg-black bg-opacity-50 z-[9999] items-center justify-center" onclick="closeWechatQR()"> <div class="bg-white rounded-xl p-6 text-center" onclick="event.stopPropagation()"> <p class="text-base font-semibold text-gray-900 mb-3">微信扫一扫分享</p> <img id="wechatQRCode" src="" alt="QR Code" class="w-48 h-48 mx-auto" /> <p class="text-sm text-gray-500 mt-3">打开微信扫描二维码</p> <button class="mt-4 px-4 py-2 bg-blue-600 text-white rounded-lg text-sm cursor-pointer" onclick="closeWechatQR()">关闭</button> </div> </div> </body> </html>