首页 时政热点 科技头条 智能AI 安全攻防 数码硬件 开发者生态 汽车 游戏 社会热点 开源推荐 医疗健康 归档 标签 关于

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

摘要

Testing MiniMax M2。7 via API on three real ML and coding workflows I recently got access to some MiniMax M2。

the MiniMax and ANTHROPIC API
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> <a href="/category/qiche" 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/youxi" 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/shehui-redian" 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/kaiyuan-tuijian" 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/yiliao-jiankang" 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> </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> </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>