<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
            <title type="text">徐洲更的第二大脑</title>
    <updated>2026-02-25T09:29:33+08:00</updated>
        <id>http://xuzhougeng.com</id>
        <link rel="alternate" type="text/html" href="http://xuzhougeng.com" />
        <link rel="self" type="application/atom+xml" href="http://xuzhougeng.com/atom.xml" />
    <rights>Copyright © 2026, 徐洲更的第二大脑</rights>
    <generator uri="https://halo.run/" version="1.6.0">Halo</generator>
            <entry>
                <title><![CDATA[Windows 下 SSH config 权限错误：原因与解决方案]]></title>
                <link rel="alternate" type="text/html" href="http://xuzhougeng.com/archives/windows-ssh-config-permission-error-cause-and-solution" />
                <id>tag:http://xuzhougeng.com,2026-02-25:windows-ssh-config-permission-error-cause-and-solution</id>
                <published>2026-02-25T09:29:10+08:00</published>
                <updated>2026-02-25T09:29:33+08:00</updated>
                <author>
                    <name>徐洲更</name>
                    <uri>http://xuzhougeng.com</uri>
                </author>
                <content type="html">
                        <![CDATA[<blockquote><p>Cursor生成，我负责校对。</p></blockquote><h2 id="%E9%94%99%E8%AF%AF%E7%8E%B0%E8%B1%A1" tabindex="-1">错误现象</h2><p>执行 <code>ssh -G &lt;Host&gt;</code> 或正常 SSH 连接时出现：</p><pre><code class="language-">Bad permissions. Try removing permissions for user: UNKNOWN\UNKNOWN (S-1-5-21-906514677-3100084438-2507395604-3740986366) on file C:/Users/xxx/.ssh/config.Bad owner or permissions on C:\Users\xxx/.ssh/config</code></pre><h2 id="%E5%8E%9F%E5%9B%A0%E5%88%86%E6%9E%90" tabindex="-1">原因分析</h2><ol><li><p><strong>OpenSSH 的权限检查</strong><br />Windows 版 OpenSSH 会校验 <code>~/.ssh/config</code> 的 ACL，要求该文件<strong>只能</strong>被当前用户（以及 SYSTEM、Administrators 等系统账户）访问。若存在其他用户或未知账户的权限，会直接报错。</p></li><li><p><strong>“UNKNOWN\UNKNOWN” 与 SID</strong><br />错误中的 <code>S-1-5-21-906514677-3100084438-2507395604-3740986366</code> 是一个<strong>安全标识符（SID）</strong>。当该 SID 对应的本地账户已被删除或来自另一台机器（例如从旧电脑迁移了用户配置），系统无法解析出用户名，就会显示为 <code>UNKNOWN\UNKNOWN</code>。</p></li><li><p><strong>典型来源</strong></p><ul><li>用户配置文件从旧机器迁移或复制</li><li>重装系统后沿用旧的 <code>.ssh</code> 目录</li><li>域/本地账户变更导致旧 SID 残留在 ACL 中</li></ul><p>只要该 SID 仍在 <code>config</code> 的 ACL 里且具有读/写等权限，OpenSSH 就会认为“其他用户可访问”，从而拒绝使用该配置。</p></li></ol><h2 id="%E8%A7%A3%E5%86%B3%E6%80%9D%E8%B7%AF" tabindex="-1">解决思路</h2><p>从 <code>~/.ssh/config</code> 的 ACL 中<strong>移除该未知/孤儿 SID 的访问项</strong>，只保留当前用户（及必要的系统账户），并保证当前用户至少对 <code>config</code> 有读权限。</p><h2 id="%E8%A7%A3%E5%86%B3%E6%AD%A5%E9%AA%A4" tabindex="-1">解决步骤</h2><h3 id="1.-%E7%A1%AE%E8%AE%A4%E9%97%AE%E9%A2%98" tabindex="-1">1. 确认问题</h3><p>查看当前 ACL 和错误信息：</p><pre><code class="language-powershell"># 查看 config 的 ACLicacls &quot;$env:USERPROFILE\.ssh\config&quot;# 触发错误（会提示具体 SID）ssh -G CPU2</code></pre><p>若输出中存在错误里提示的 SID（如 <code>S-1-5-21-906514677-...</code>）且对应 <code>UNKNOWN</code>，则按下面步骤处理。</p><h3 id="2.-%E5%AF%BC%E5%87%BA%E5%BD%93%E5%89%8D-acl" tabindex="-1">2. 导出当前 ACL</h3><p>在 PowerShell 中执行：</p><pre><code class="language-powershell">icacls &quot;$env:USERPROFILE\.ssh\config&quot; /save &quot;$env:USERPROFILE\.ssh\config_acl.txt&quot;</code></pre><h3 id="3.-%E7%BC%96%E8%BE%91-acl-%E6%96%87%E4%BB%B6%EF%BC%8C%E5%8E%BB%E6%8E%89%E9%97%AE%E9%A2%98-sid" tabindex="-1">3. 编辑 ACL 文件，去掉问题 SID</h3><p><code>config_acl.txt</code> 为 UTF-16 编码，用脚本去掉对应 SID 的 ACE（将下面 <code>S-1-5-21-...</code> 换成你错误信息里的 SID）：</p><pre><code class="language-powershell">$path = &quot;$env:USERPROFILE\.ssh\config_acl.txt&quot;$text = [System.IO.File]::ReadAllText($path, [Text.Encoding]::Unicode)$badSid = &quot;(A;;0x1301ff;;;S-1-5-21-906514677-3100084438-2507395604-3740986366)&quot;  # 改为你的 SID$text = $text.Replace($badSid, &quot;&quot;)[System.IO.File]::WriteAllText($path, $text, [Text.Encoding]::Unicode)</code></pre><p>若不确定 SDDL 格式，可先打开 <code>config_acl.txt</code>，搜索该 SID 所在整段 <code>(A;;...;;;S-1-5-21-...)</code> 并整段删除后保存为 UTF-16。</p><h3 id="4.-%E4%BB%A5%E7%AE%A1%E7%90%86%E5%91%98%E6%9D%83%E9%99%90%E6%81%A2%E5%A4%8D-acl" tabindex="-1">4. 以管理员权限恢复 ACL</h3><p><strong>必须以管理员身份打开 PowerShell</strong>，然后执行：</p><pre><code class="language-powershell">Set-Location &quot;$env:USERPROFILE\.ssh&quot;icacls . /restore &quot;$env:USERPROFILE\.ssh\config_acl.txt&quot;</code></pre><p><code>/restore</code> 会按 ACL 文件中的条目重新应用权限，因此需提升权限。</p><h3 id="5.-%E9%AA%8C%E8%AF%81" tabindex="-1">5. 验证</h3><pre><code class="language-powershell"># 再次查看 ACL，确认问题 SID 已消失icacls &quot;$env:USERPROFILE\.ssh\config&quot;# 应能正常输出配置，不再报错ssh -G CPU2</code></pre><p>正常时，<code>config</code> 上应只剩例如 <code>NT AUTHORITY\SYSTEM</code>、<code>BUILTIN\Administrators</code> 和你的用户名（如 <code>DESKTOP-xxx\你的用户名</code>），且你的用户至少有读权限。</p><h2 id="%E5%8F%AF%E9%80%89%EF%BC%9A%E8%8B%A5%E6%9C%AC%E6%9C%BA%E6%9C%89%E7%AE%A1%E7%90%86%E5%91%98%E6%9D%83%E9%99%90%E4%B8%94%E7%86%9F%E6%82%89-icacls" tabindex="-1">可选：若本机有管理员权限且熟悉 icacls</h2><p>也可在<strong>管理员 PowerShell</strong> 中直接尝试移除该 SID（将 <code>S-1-5-21-...</code> 换成实际 SID）：</p><pre><code class="language-powershell">icacls &quot;$env:USERPROFILE\.ssh\config&quot; /remove &quot;S-1-5-21-906514677-3100084438-2507395604-3740986366&quot;</code></pre><p>若提示“无法解析/找不到主体”，说明系统已不认识该账户，此时用上面的“导出 → 编辑 → 恢复”方式更可靠。</p><h2 id="%E5%B0%8F%E7%BB%93" tabindex="-1">小结</h2><table><thead><tr><th>项目</th><th>说明</th></tr></thead><tbody><tr><td><strong>现象</strong></td><td><code>Bad owner or permissions on .../.ssh/config</code>，并提示 <code>UNKNOWN\UNKNOWN</code> 及一长串 SID</td></tr><tr><td><strong>原因</strong></td><td>config 的 ACL 中存在已失效/跨机器的 SID，OpenSSH 认为存在“其他用户”权限</td></tr><tr><td><strong>本质</strong></td><td>清理该 SID 在 <code>~/.ssh/config</code> 上的访问项，只保留当前用户和系统必要账户</td></tr><tr><td><strong>要点</strong></td><td>修改 ACL 需管理员权限；编辑导出文件时注意 UTF-16 与 SDDL 格式</td></tr></tbody></table><p>按上述步骤操作后，SSH 会正常读取 <code>~/.ssh/config</code>，<code>ssh -G</code> 与日常连接即可恢复使用。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[开发了一个随时随地控制服务器claude code的工具]]></title>
                <link rel="alternate" type="text/html" href="http://xuzhougeng.com/archives/claude-code-interface" />
                <id>tag:http://xuzhougeng.com,2026-02-11:claude-code-interface</id>
                <published>2026-02-11T16:09:24+08:00</published>
                <updated>2026-02-13T20:45:49+08:00</updated>
                <author>
                    <name>徐洲更</name>
                    <uri>http://xuzhougeng.com</uri>
                </author>
                <content type="html">
                        <![CDATA[<p>OpenClaw最近爆火出圈，每当人别人问有没有部署的时候，我都在一个问题，你打算做什么？因为本质上，我只需要一个服务器连接Claude Code就能实现OpenClaw的绝大部分功能了。</p><p>有一个功能我是特别喜欢，那就是 OpenClaw 可以通过不同的终端发送指令，而这是 Claude Code 目前所不能实现的。</p><p>比方说，我有多个服务器，每个服务器都运行着 Claude Code。</p><p>这些服务器运行完之后通常需要手动确认，但如果我当时刚好不在服务器旁边，操作起来就会比较麻烦。所以我想，有没有可能我自己搞一个网页终端？这样我就可以通过网页终端随时获取当前状态，并进行确认工作。</p><p>之所以有这个需求，是因为：</p><ol><li>OpenClaw 的权限特别大，操作不当可能会把服务器搞乱。</li><li>Claude Code 比较谨慎，权限控制相对严格，需要频繁点击确认。</li></ol><p>如果我有这样一个网页工具，能帮我随时随地确认状态，就完全符合我的需求了，甚至不再需要 OpenClaw。</p><p>我跟 ChatGPT 进行了交流，向它输入了流程思路，咨询大概需要什么工具以及具体的实现方法。</p><p>最后我决定使用 Go 语言作为后端，主要基于以下考虑：</p><ol><li>部署简单：Go 可以直接编译成二进制文件，资源占用非常小，直接分发到服务器上即可。</li><li>项目需求：这个项目总体比较简单，后端只需要监控我的 Terminal（终端），前端负责网页展示。相比之下，Python 众多的第三方库在本项目中并非必需。</li></ol><p>至于前端部分，因为逻辑比较简单，我没有使用任何框架，只是进行了原生的 Native 开发。</p><p>经过跟 Cursor 的交流，我们制定了以下开发流程：</p><ol><li>计划阶段：使用 GPT 5.2 (Extra High) 进行整体规划</li><li>编程操作：使用 GPT 5.3 CodeX Extra High)进行核心代码编写</li><li>模型优化：中间穿插使用了 Opus 4.6 模型</li></ol><p>大概经过这十几次 Commit，我们最终完成了代码。开发过程中，发现其中比较复杂的部分在于如何渲染终端和前端页面样式的可视化，难点主要是如何更适合手机端操作。</p><p>我最初的一些想法都在后续的反复开发中不断进行了重构。目前整体设计还是相对比较简洁的，因为 UI 比较简单，绝大部分功能都是通过 API 实现的，所以后面衔接其他程序也会相对容易一些。</p><p>代码开源在 GitHub 上，<a href="https://github.com/xuzhougeng/agent-control" target="_blank">https://github.com/xuzhougeng/agent-control</a></p><p>接下来介绍如何去部署这个工作：</p><p>首先我们需要从 GitHub 上克隆这个项目，然后对其进行编译。</p><pre><code class="language-Go">git clone https://github.com/xuzhougeng/agent-controlcd agent-controlcd cc-controlCGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o cc-control ./cmd/cc-controlcd ../cc-agentCGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o cc-agent ./cmd/cc-agent</code></pre><p>这个项目分为两个部分：其中一个部分是需要一个公网 IP 的服务器，因为我的服务器主要集中在境内，所以我们可以购买一个国内的服务器。</p><p>这里选择购买一个腾讯云服务器，不需要域名，只需要IP即可。</p><p><img src="/upload/2026/02/image.png" alt="image" /></p><p>服务器购买后，我们需要打开防火墙，在里面添加 443 端口。</p><p>之所以需要增加 443 端口，是因为如果使用 HTTP 端口，传输过程就是明文的。这样很有可能导致服务器暴露在外面，尤其是涉及敏感服务器时会非常危险。毕竟我们的权限还是比较大的，所以一定要通过 HTTPS 协议进行传输。</p><p><img src="/upload/2026/02/image-1770797207565.png" alt="image-1770797207565" /></p><p>然后根据服务器的 IP 地址、用户名和密码登录到服务器上。接着在服务器上做如下的配置操作：</p><p>第一步：建立相关的文件夹并赋予其权限</p><pre><code class="language-Bash">sudo mkdir -p /opt/cc-controlsudo chown ubuntu:ubuntu /opt/cc-control</code></pre><p>无域名时无法使用 Let’s Encrypt，可用自签名证书在 Nginx 上启用 TLS，传输仍加密；浏览器和 agent 需接受自签名（浏览器手动信任，agent 用 <code>-tls-skip-verify</code>）。</p><blockquote><p>下面的1.2.3.4得改成实际的IP地址</p></blockquote><pre><code class="language-Bash">mkdir -p /opt/cc-control/tlscd /opt/cc-control/tlscat &gt; openssl.cnf &lt;&lt; &#39;EOF2&#39;[req]distinguished_name = req_distinguished_namereq_extensions = v3_reqprompt = no[req_distinguished_name]CN = cc-control[v3_req]subjectAltName = @alt[alt]IP.1 = 1.2.3.4EOF2openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \  -keyout key.pem -out cert.pem -config openssl.cnf -extensions v3_req</code></pre><p>接着我们需要安装 Nginx</p><pre><code class="language-Bash">sudo apt install nginx</code></pre><p>增加配置文件 /etc/nginx/conf.d/cc.conf</p><pre><code class="language-nginx">server {    listen 443 ssl http2 default_server;    listen [::]:443 ssl http2 default_server;    server_name _;    ssl_certificate     /opt/cc-control/tls/cert.pem;    ssl_certificate_key /opt/cc-control/tls/key.pem;    location /ws/ {        proxy_pass http://127.0.0.1:18080;        proxy_http_version 1.1;        proxy_set_header Upgrade $http_upgrade;        proxy_set_header Connection &quot;upgrade&quot;;        proxy_set_header Host $host;        proxy_set_header X-Real-IP $remote_addr;        proxy_read_timeout 3600s;        proxy_send_timeout 3600s;    }    location / {        proxy_pass http://127.0.0.1:18080;        proxy_set_header Host $host;        proxy_set_header X-Real-IP $remote_addr;    }}</code></pre><p>重启nginx服务</p><pre><code class="language-Bash">sudo nginx -t sudo systemctl reload nginx</code></pre><p>在服务器这部分操作结束后，我们需要回到本地，将我们编译的代码进行上传。</p><pre><code class="language-Bash">scp cc-control ubuntu@106.54.201.18:/opt/cc-control/scp -r ../ui ubuntu@106.54.201.18:/opt/cc-control/ui</code></pre><p>然后是非常关键的一步，需要生成两个 token，分别是 AGENT_TOKEN 和 UI_TOKEN：</p><ol><li><p>AGENT_TOKEN</p><p>负责本地 agent 与服务器端进行连接（Service Network）。</p></li><li><p>UI_TOKEN</p><p>相当于一个密码。当别人访问页面时，在没有授权的情况下无法直接查看，需要输入这个密码才能够查看你的网页。</p></li></ol><pre><code class="language-Bash">ADMIN_TOKEN=$(openssl rand -hex 32)echo &quot;ADMIN_TOKEN=$ADMIN_TOKEN&quot;</code></pre><p>增加一个服务文件，<code>/etc/systemd/system/cc-control.service</code>，这样可以保证开机或重启之后，它会自动启动。</p><p>不然的话，可能服务器会重启，或者程序在某种情况下不小心中断了。如果它不能重连的话，处理起来就比较麻烦，你还得专门打开服务器去配置它，而设置为服务之后，它就会在这些情况下自动重启。</p><pre><code class="language-Ini">[Unit]Description=CC Control PlaneAfter=network.target[Service]Type=simpleUser=ccGroup=ccWorkingDirectory=/opt/cc-controlExecStart=/opt/cc-control/cc-control \  -addr 127.0.0.1:18080 \  -ui-dir /opt/cc-control/ui \  -agent-token ${AGENT_TOKEN} \  -ui-token ${UI_TOKEN} \  -audit-path /opt/cc-control/audit.jsonl \  -offline-after-sec 30EnvironmentFile=/opt/cc-control/.envRestart=alwaysRestartSec=3[Install]WantedBy=multi-user.target</code></pre><p>需要注意的是，这里面涉及到一个环境文件<code>/opt/cc-control/.env</code>，里面的 token 都是我们刚才生成的。</p><pre><code class="language-Bash">ADMIN_TOKEN=&lt;your-admin-token&gt;# optional: persist tokens across restartsTOKEN_DB=/opt/cc-control/tokens.db</code></pre><p>为了安全，我们继续新建一个不允许被登录的账号。同时，把刚才环境变量的权限改一改，进一步增加安全性，然后重启该服务。</p><pre><code class="language-Bash">sudo useradd -r -s /sbin/nologin ccsudo chown -R cc:cc /opt/cc-controlsudo chmod 600 /opt/cc-control/.envsudo systemctl daemon-reloadsudo systemctl enable --now cc-control</code></pre><p>等这些配置完成后，我们就可以打开浏览器访问我们的网站了。</p><p>由于 TLS 或者说 HTTP 协议（也就是 SSL 证书）是我们自签名的，浏览器会提示该连接不安全。但这没有关系，只需按照以下步骤操作：</p><ol><li>在浏览器提示界面选择“高级”</li><li>点击“继续访问”即可进入网站</li></ol><p>手机端访问时也会出现同样的情况，无需担心。</p><p><img src="/upload/2026/02/image-1770797247465.png" alt="image-1770797247465" /></p><p>接下来登录 /admin页面，我们要生成 Tenant ID和Token。</p><p><img src="/upload/2026/02/image-1770986480708.png" alt="image-1770986480708" /></p><p>接下来登录这个tenant页面，我们要生成 UI Token 和 Agent Token</p><p><img src="/upload/2026/02/image-1770986733519.png" alt="image-1770986733519" /></p><p>接着我们需要填写里面的 UI Token，也就是我们刚才生成的。不然的话，我们是看不到连接服务的。当然，现在连上去也看不到服务，毕竟我们本地agent都还没有连上去。</p><p><img src="/upload/2026/02/image-1770797259218.png" alt="image-1770797259218" /></p><p>然后需要启动本地端的 agent 了。</p><ol><li>IP 地址：我们现在写的是 1234，你得改成我们实际的 IP 地址</li><li>Agent Token：也一样，也要改成实际的 Agent Token</li></ol><p>当然，服务器上必须安装 Claude 并配置 Claude 的相关信息，这部分内容就不在这里过多介绍了。</p><pre><code class="language-Bash">cc-agent \  -control-url wss://1.2.3.4/ws/agent \  -tls-skip-verify \  -agent-token &quot;$AGENT_TOKEN&quot; \  -server-id srv-gpu-01 \  -allow-root /home/deploy/repos \  -claude-path /usr/local/bin/claude</code></pre><p>实际效果如下：</p><p><img src="/upload/2026/02/image-1770797278994.png" alt="image-1770797278994" /></p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[基于免费的Cloudflare搭建单细胞可视化网站]]></title>
                <link rel="alternate" type="text/html" href="http://xuzhougeng.com/archives/building-single-cell-visualization-website-with-free-cloudflare" />
                <id>tag:http://xuzhougeng.com,2026-01-18:building-single-cell-visualization-website-with-free-cloudflare</id>
                <published>2026-01-18T19:59:32+08:00</published>
                <updated>2026-01-20T21:37:08+08:00</updated>
                <author>
                    <name>徐洲更</name>
                    <uri>http://xuzhougeng.com</uri>
                </author>
                <content type="html">
                        <![CDATA[<p>这一篇是在<a href="http://xuzhougeng.com/archives/refactoring-of-published-single-cell-databases-by-atlasmap" target="_blank">AtlasMap重构已发表的单细胞数据库</a>的基础上，使用Cloudflare提供的page和worker功能进行前后端分离搭建。</p><h2 id="%E5%A6%82%E6%9E%9C%E4%BD%A0%E7%9A%84%E5%90%8E%E5%8F%B0%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%8F%AF%E4%BB%A5%E5%85%AC%E7%BD%91%E8%AE%BF%E9%97%AE" tabindex="-1">如果你的后台服务器可以公网访问</h2><p>在frontend生成用于发布的静态文件，这里你需要设置你的后台服务器。</p><pre><code class="language-bash">UPSTREAM_ORIGIN=http://your.backend.server npm run build:cloudflare</code></pre><p>此时会在frontend目录下生成两个子目录:</p><ul><li>dist: 静态资源站点</li><li>functionns : 基于worker实现方向代理</li></ul><p>使用cloudflare wrangler命令进行部署。这一步需要你的注册一个Cloudflare的账号</p><pre><code class="language-bash"># 1) 登录npx wrangler login# 2) （可选）创建 Pages 项目npx wrangler pages project create &lt;PROJECT_NAME&gt;# 3) 部署：在项目根目录执行（根目录要有 functions/）npx wrangler pages deploy dist --project-name &lt;PROJECT_NAME&gt;</code></pre><p>注: 后台服务器 nginx 转发设置保持不变，参考<a href="http://xuzhougeng.com/archives/refactoring-of-published-single-cell-databases-by-atlasmap" target="_blank">AtlasMap重构已发表的单细胞数据库</a>里的后端配置部分。</p><p>此时，他会提供一个跟项目关联的域名给你，类似于 <a href="https://plantcellatlas.pages.dev" target="_blank">https://plantcellatlas.pages.dev</a> , 当然你也可以选择使用CNAME设置自定义域名。</p><p><img src="/upload/2026/01/image-1768737508340.png" alt="image-1768737508340" /></p><h2 id="%E5%A6%82%E6%9E%9C%E4%BD%A0%E7%9A%84%E5%90%8E%E5%8F%B0%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%A4%84%E4%BA%8E%E5%86%85%E7%BD%91" tabindex="-1">如果你的后台服务器处于内网</h2><p>借助于赛博活菩萨Cloudflare提供tunnel服务。</p><p>目标：<strong>无需公网服务器/公网 IP</strong>（后端在内网/NAT/校园网），实现<strong>前后端分离部署</strong>：</p><ul><li>前端：Cloudflare Pages 托管静态站点</li><li>后端：任意一台可出网的机器上运行 <code>server/bin/server</code>（只需本机可监听端口）</li><li>连接：用 Cloudflare Tunnel 把后端暴露到一个 Cloudflare 子域名；前端通过 Pages Functions 同源代理 <code>/api/*</code>、<code>/d/*</code> 到该子域名（浏览器侧无 CORS 问题）</li></ul><p>注: 后端主机必须能连通到Cloudflare tunnel服务, 参考<a href="https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/troubleshoot-tunnels/connectivity-prechecks/" target="_blank">Connectivity pre-checks</a>, 即，如果内网服务器被屏蔽这类服务，或者无法访问外网，无法使用改方案。</p><h3 id="%E5%90%8E%E7%AB%AF%EF%BC%9A%E5%90%AF%E5%8A%A8%E6%9C%8D%E5%8A%A1%EF%BC%88%E5%86%85%E7%BD%91%E6%9C%BA%E5%99%A8%E5%8D%B3%E5%8F%AF%EF%BC%89" tabindex="-1">后端：启动服务（内网机器即可）</h3><p>后端数据准备与 <code>server.yaml</code> 配置同其它方式一致，然后在后端机器上启动：</p><pre><code class="language-bash">server/bin/server -config &quot;data/server.yaml&quot;</code></pre><p>默认后端监听 <code>:8080</code>（以实际配置为准）。<strong>不需要</strong>给这台机器配置公网 IP，也不需要额外的 nginx 反代（Tunnel 会负责入口）。</p><h3 id="%E5%90%8E%E7%AB%AF%EF%BC%9A%E5%88%9B%E5%BB%BA%E5%B9%B6%E8%BF%90%E8%A1%8C-cloudflare-tunnel" tabindex="-1">后端：创建并运行 Cloudflare Tunnel</h3><p>从Github上下载cloudflared</p><pre><code class="language-bash">wget https://github.com/cloudflare/cloudflared/releases/download/2026.1.1/cloudflared-linux-amd64mv cloudflared-linux-amd64 cloudflaredchmod +x cloudflared</code></pre><p>参考<a href="https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/local-management/create-local-tunnel/" target="_blank">Create a locally-managed tunnel</a></p><p>安装完成后，登录并创建 Tunnel, 此时会弹出一个网页，要求你选择一个 Cloudflare 托管域名下的子域名作为上游入口</p><pre><code class="language-bash">cloudflared tunnel login</code></pre><p>创建一个隧道，名字自取，这里我写的是atlasmap</p><pre><code class="language-bash">cloudflared tunnel create atlasmap</code></pre><p>后续步骤中的<code>&lt;USER&gt;</code>, <code>TUNNEL_ID</code> 和  <code>HOST_DOMAIN</code> 是需要根据实际结果进行修改。</p><p>创建 <code>cloudflared</code> 配置文件（示例路径 <code>~/.cloudflared/config.yml</code>）：</p><pre><code class="language-yaml">tunnel: atlasmapcredentials-file: /home/&lt;USER&gt;/.cloudflared/&lt;TUNNEL_ID&gt;.jsoningress:  - hostname: &lt;HOST_DOMAIN&gt;    service: http://127.0.0.1:8080  - service: http_status:404</code></pre><p>建立DNS记录（非常重要，也可以在Cloudflare dashboard中DNS里面手动创建）</p><pre><code class="language-bash">cloudflared tunnel route dns atlasmap &lt;HOST_DOMAIN&gt;</code></pre><p>启动 Tunnel：</p><pre><code class="language-bash">cloudflared tunnel run atlasmap</code></pre><p>日志信息只要不出现ERR都算运行正常。</p><p>可选：将 Tunnel 配置为 systemd 服务，保证重启后自启动（按 cloudflared 官方文档即可）。</p><h3 id="%E5%89%8D%E7%AB%AF%EF%BC%9A%E6%9E%84%E5%BB%BA-cloudflare-pages-%E4%BA%A7%E7%89%A9%EF%BC%88%E5%8C%85%E5%90%AB-functions-%E4%BB%A3%E7%90%86%EF%BC%89" tabindex="-1">前端：构建 Cloudflare Pages 产物（包含 Functions 代理）</h3><p>本项目已提供 Pages Functions 的同源代理实现：部署到 Pages 后，<code>/api/*</code> 与 <code>/d/*</code> 会被转发到 <code>UPSTREAM_ORIGIN</code> 指定的上游。</p><p>在 <code>frontend/</code> 目录构建（把上游指向刚才的 Tunnel 子域名）：</p><pre><code class="language-bash">cd frontendUPSTREAM_ORIGIN=&lt;HOST_DOMAIN&gt; npm run build:cloudflare</code></pre><p>构建完成后会生成：</p><ul><li><code>frontend/dist/</code>：静态站点</li><li><code>frontend/functions/</code>：Pages Functions（同源反代 <code>/api/*</code>、<code>/d/*</code>）</li></ul><h3 id="%E9%83%A8%E7%BD%B2%E5%88%B0-cloudflare-pages" tabindex="-1">部署到 Cloudflare Pages</h3><p>用 wrangler 一键发布</p><pre><code class="language-bash">cd frontendnpx wrangler loginnpx wrangler pages project create &lt;PROJECT_NAME&gt;npx wrangler pages deploy dist --project-name &lt;PROJECT_NAME&gt;</code></pre><h3 id="%E9%AA%8C%E8%AF%81%E4%B8%8E%E6%8E%92%E9%94%99" tabindex="-1">验证与排错</h3><ul><li>访问 Pages 域名（例如 <code>https://&lt;PROJECT&gt;.pages.dev</code>）</li><li>打开浏览器 Network：确认请求打到同源的 <code>/api/...</code>、<code>/d/...</code>（由 Pages Functions 转发到 <code>https://api.example.com</code>）</li><li>如果接口返回 502/超时：<ul><li>确认后端机器上 <code>server</code> 正在运行，且本机可访问 <code>http://127.0.0.1:8080/health</code>（或你配置的健康检查）</li><li>确认 <code>cloudflared tunnel run ...</code> 正在运行，且 <code>api.example.com</code> 已在 Cloudflare DNS 中生效</li><li>确认 <code>UPSTREAM_ORIGIN</code> 使用 <code>https://api.example.com</code>（Tunnel 默认提供 HTTPS 入口）</li></ul></li></ul>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[AtlasMap重构已发表的单细胞数据库]]></title>
                <link rel="alternate" type="text/html" href="http://xuzhougeng.com/archives/refactoring-of-published-single-cell-databases-by-atlasmap" />
                <id>tag:http://xuzhougeng.com,2026-01-18:refactoring-of-published-single-cell-databases-by-atlasmap</id>
                <published>2026-01-18T12:34:12+08:00</published>
                <updated>2026-01-18T12:34:12+08:00</updated>
                <author>
                    <name>徐洲更</name>
                    <uri>http://xuzhougeng.com</uri>
                </author>
                <content type="html">
                        <![CDATA[<p>我觉得单细胞文章发表之后，最好是搭配一个对应的网页方便用户查看数据。毕竟我看到你的文章后，第一个想法可能就是我关注的基因是不是在你的数据集中也有某种特征，而不是我要去数据库上下载你的数据，然后在本地进行处理，最后只为了看个表达量。</p><p>因此，我在2019参与发表拟南芥的根的单细胞中就提供了对应网站，当现在已经过去了快6年了，依旧每天都会几个人来看。</p><p>我觉得目前发表的很多单细胞文章之所以不提供对应的工作，其中一个很大原因就是按照目前现成工具部署到一个能够被访问的公网服务器上，一年下来是要不少钱的。我找了一圈，也就是USCS Cell Browser是低资源的，他处理完之后就是一个静态页面，直接用NGINX托管就行。但是有一个小小的问题，就是他是通过用户的浏览器渲染，当细胞数比较多的时候，可能会有点卡顿。</p><p>当然也可能是我调研不够全，还没有找到合适的软件，我借助目前比较强大的人工智能辅助编程，开发了一个新的工具，可以在非常低资源的情况下进行部署，0.2个CPU，128M内存，可能一天不需要1块钱，就能给自己工作增加一个曝光点。</p><p>目前项目开源代码在<a href="https://github.com/xuzhougeng/atlasmap-sc" target="_blank">https://github.com/xuzhougeng/atlasmap-sc</a>。</p><p>以课题组之前发表的，被我托管在shiny-server的数据为例，目标是统一托管在<a href="https://explorer.plantcellatlas.com" target="_blank">https://explorer.plantcellatlas.com</a> 。</p><p>我有一台比较高性能的服务器，但是域名是固定的，假设是http://www.example.com，我们可以将其作为计算中心，负责返回前端静态页面的API请求。</p><p>在高性能的服务器上，我们做如下的操作</p><p>第一步，克隆项目并安装环境</p><pre><code class="language-Bash">git clone https://github.com/xuzhougeng/atlasmap-sc.gitcd atlasmap-sc# 配置Python环境cd preprocessinguv pip install  .cd ..# 配置go环境 cd servergo build -o bin/server ./cmd/server</code></pre><p>第二步，运行atlasmap-preproces做数据预处理</p><pre><code class="language-Bash">uv run atlasmap-preprocess run -i rootatlas.h5ad -o data/ath_root -a -z 11 uv run atlasmap-preprocess run -i shootatlas.h5ad -o data/ath_shoot -a -z 11 uv run atlasmap-preprocess run -i marchantia_census.h5ad -o data/mp_census -a -z 11 </code></pre><p>第三步，配置data/sever.yaml</p><pre><code class="language-YAML">server:  port: 8080   cors_origins:    - &quot;http://localhost:3000&quot;    - &quot;http://localhost:5173&quot;  # Custom title displayed in the header (optional, defaults to &quot;SOMA-Tiles&quot;)  title: &quot;Cell 1K&quot;# Multi-dataset format:data:  ath_root:    zarr_path: &quot;data/ath_root/zarr/bins.zarr&quot;  ath_shoot:    zarr_path: &quot;data/ath_shoot/zarr/bins.zarr&quot;  mp_census:    zarr_path: &quot;data/mp_census/zarr/bins.zarr&quot;cache:  tile_size_mb: 512  tile_ttl_minutes: 10render:  tile_size: 256  default_colormap: viridis</code></pre><p>启动后台</p><pre><code class="language-Bash">server/bin/server -config &quot;data/server.yaml&quot;</code></pre><p>第四步，配置后台的nginx，将前端请求反向代理到前端的到go服务器上，并用<code>ngins -s reload</code>重新加载</p><pre><code class="language-nginx">server {    # .... other    # /api (no trailing slash) -&gt; /api/    location = /api { return 301 /api/; }    location /api/ {        proxy_pass http://127.0.0.1:8080/api/;        proxy_set_header Host $host;        proxy_set_header X-Real-IP $remote_addr;        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;        proxy_set_header X-Forwarded-Proto $scheme;        proxy_read_timeout 300s;    }    # /d (no trailing slash) -&gt; /d/    location = /d { return 301 /d/; }    location /d/ {        proxy_pass http://127.0.0.1:8080/d/;        proxy_set_header Host $host;        proxy_set_header X-Real-IP $remote_addr;        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;        proxy_set_header X-Forwarded-Proto $scheme;        proxy_read_timeout 300s;    }    # 可选：健康检查直通    location /health {        proxy_pass http://127.0.0.1:8080/health;    }    # ... other}</code></pre><p>配置前端：</p><p>我用的是环界云<a href="https://cloud.sealos.io/" target="_blank">https://cloud.sealos.io/</a>提供谷歌云，直接用配置好的镜像：<code>hoptoper/atlasmap-frontend:latest</code>， 最低配置，一天不到5毛钱。</p><p><img src="/upload/2026/01/image-1768710646096.png" alt="image-1768710646096" /></p><p>通过CNAME的方式实现自定义域名。</p><p><img src="/upload/2026/01/image-1768710668398.png" alt="image-1768710668398" /></p><p>保存的时候，提示你应该如何到域名服务上设置CNAME解析，这里面的值就是你需要复制过去的。</p><p><img src="/upload/2026/01/image-1768710678018.png" alt="image-1768710678018" /></p><p>高级配置中，设置环境变量 BACKEND_HOST， BACKEND_PORT, 对应后台服务器NGINX配置的server_name 和listen。</p><p><img src="/upload/2026/01/image-1768710696507.png" alt="image-1768710696507" /></p><p>启动等待一会就可以了，就可以通过域名<a href="https://explorer.plantcellatlas.com/" target="_blank">https://explorer.plantcellatlas.com/</a>访问了，终于实现了我的单细胞数据统一化展示了。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[AHK关掉恼人的微信电脑语音视频电话弹窗]]></title>
                <link rel="alternate" type="text/html" href="http://xuzhougeng.com/archives/close-wechat-notification-using-ahk" />
                <id>tag:http://xuzhougeng.com,2026-01-06:close-wechat-notification-using-ahk</id>
                <published>2026-01-06T08:54:08+08:00</published>
                <updated>2026-01-06T08:54:08+08:00</updated>
                <author>
                    <name>徐洲更</name>
                    <uri>http://xuzhougeng.com</uri>
                </author>
                <content type="html">
                        <![CDATA[<p>我发现微信电脑端（测试的时候是4.1.6.46）有一个很讨厌的问题，就是一旦别人视频或者语音电话给你，你的的右下角就会有一个弹窗，而且离谱的时候，我在设置中，根本关不掉。</p><p><img src="/upload/2026/01/image.png" alt="image" /></p><p>当然这里书都关不掉指的是，我查了各种资料，做了包括不限于如下的操作</p><ul><li>找windows10里的信息通知（没找到）</li><li>消息列表中设置仅限闹钟</li><li>windows防火墙限制微信的UDP</li></ul><p>最后借助AI的力量，用最传统的方法，实时监控电脑，一旦看到弹窗给它瞬间隐藏。</p><p>第一步，安装AHK，这是他的官方站点https://www.autohotkey.com/ （记得之前用这个软件还是为DNF连招）</p><p>第二步，新建一个脚本，命名为 <code>wechat_call_popup_kill.ahk</code>,  粘贴如下的代码，并保存。</p><pre><code class="language-ahk">#Requires AutoHotkey v2.0#SingleInstance ForceSetTimer BlockWeChatCallPopup, 80DetectHiddenWindows false; 你的来电小窗尺寸（允许一点点误差）global TARGET_W := 472global TARGET_H := 170global TOL_W := 30global TOL_H := 30; 右下角容差（像素）global EDGE_PAD := 120BlockWeChatCallPopup() {    for hwnd in WinGetList(&quot;ahk_exe Weixin.exe&quot;) {        try {            if (WinGetClass(&quot;ahk_id &quot; hwnd) != &quot;Qt51514QWindowIcon&quot;)                continue            WinGetPos &amp;x, &amp;y, &amp;w, &amp;h, &quot;ahk_id &quot; hwnd            ; 尺寸匹配（来电小窗）            if (Abs(w - TARGET_W) &gt; TOL_W || Abs(h - TARGET_H) &gt; TOL_H)                continue            ; 位置匹配（贴近主屏右下角工作区）            mon := MonitorGetPrimary()            MonitorGetWorkArea mon, &amp;L, &amp;T, &amp;R, &amp;B            rightGap  := R - (x + w)            bottomGap := B - (y + h)            if (rightGap &gt; EDGE_PAD || bottomGap &gt; EDGE_PAD)                continue            ; 最稳：隐藏（避免 WinClose 无效/闪烁）            WinHide &quot;ahk_id &quot; hwnd            ; 如果你更希望“直接关掉窗口”，用下面替换 WinHide：            ; PostMessage 0x0010, 0, 0, , &quot;ahk_id &quot; hwnd   ; WM_CLOSE        }    }}</code></pre><p>第三步，双击运行。启动后，别人打电话给你，手机端依旧会有提示，电脑端只会一闪而过。</p><p>此外还可以设置开机自动运行。 使用快捷键Win + R → 输入 shell:startup → 回车 ，将脚本放进去。</p><p><img src="/upload/2026/01/image-1767660703050.png" alt="image-1767660703050" /></p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[Github添加Claude作为助手]]></title>
                <link rel="alternate" type="text/html" href="http://xuzhougeng.com/archives/add-claude-app-in-github" />
                <id>tag:http://xuzhougeng.com,2025-12-19:add-claude-app-in-github</id>
                <published>2025-12-19T22:24:45+08:00</published>
                <updated>2025-12-19T22:26:20+08:00</updated>
                <author>
                    <name>徐洲更</name>
                    <uri>http://xuzhougeng.com</uri>
                </author>
                <content type="html">
                        <![CDATA[<p>Claude Code中有一项是 <code>/instal-github-app</code>, 作用就是让Claude Code出现在你的github仓库中作为issue和PR的处理助手。</p><p>如下是操作流程</p><ol><li>使用 <code>gh auth login</code> 注册当前的设备</li><li>到 <a href="https://github.com/apps/claude" target="_blank">https://github.com/apps/claude</a>安装Claude应用</li><li>在Cluade Code 中，运行<code>/instal-github-app</code>, 选择需要安装的功能</li><li>在Claude Code弹出页面中进行授权，粘贴Prompt</li><li>在弹出的github PR页面合并新增的action的PR</li><li>后续在Issue和PR中，就可以使用 <code>@claude</code> 处理简单的任务代码debug和reivew（默认只有repo的所有者能够调用）</li></ol><p>注意，必须要注册Claude的账号，因此无法使用中转站的方式。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[尝鲜了Z-image模型]]></title>
                <link rel="alternate" type="text/html" href="http://xuzhougeng.com/archives/quick-view-on-z-image" />
                <id>tag:http://xuzhougeng.com,2025-11-29:quick-view-on-z-image</id>
                <published>2025-11-29T22:23:37+08:00</published>
                <updated>2025-11-29T22:23:37+08:00</updated>
                <author>
                    <name>徐洲更</name>
                    <uri>http://xuzhougeng.com</uri>
                </author>
                <content type="html">
                        <![CDATA[<p>阿里最近推出了一个6B的生图模型，叫做造相(Z-Image),6B参数，模型文件32.9G，经过我测试，刚好可以跑在24G显存的4090 GPU上，以及我的32G内存内存的M1 Pro（实际用了25.6G）</p><p><img src="/upload/2025/11/image-1764425632521.png" alt="image-1764425632521" /></p><p>因为用的深度学习框架pytorch可以运行在全平台上，所以如下代码实际上可以在macOS, Linux, Windows上运行。我们配置环境用的是uv，目前python生态里非常优秀的环境管理工具。</p><p>使用uv建立一个新的环境</p><pre><code class="language-Bash"># 如果系统没有安装uv，需要先装uvcurl -LsSf https://astral.sh/uv/install.sh | shuv venv -p 3.12source .venv/bin/activate</code></pre><p>安装torch,这一步的命令要看平台了，详见 <a href="https://pytorch.org/get-started/locally/" target="_blank">https://pytorch.org/get-started/locally/</a></p><pre><code class="language-"># Windows cuda 130的uv pip install torch torchvision --index-url https://download.pytorch.org/whl/cu130# macosuv pip install torch torchvision</code></pre><p>安装diffusers</p><pre><code class="language-bash"># 安装diffusers和transformersuv pip install git+https://github.com/huggingface/diffusersuv pip install transformers</code></pre><p>为了提高模型下载速度，我们用的是modelscope，这样子走的就是国内的站点</p><pre><code class="language-bash">uv pip install modelscopemodelscope download --model &#39;Tongyi-MAI/Z-Image-Turbo&#39; --local_dir &#39;Z-Image-Turbo&#39;</code></pre><p>下载的模型位于当前目录下，后续运行的时候需要指定路径，不然会出错。</p><p>安装成功后，我们运行如下的代码进行测序。如果是macOS，记得把下面的cuda改成mps，否则会报错。</p><pre><code class="language-Python">import torchfrom diffusers import ZImagePipeline# 1. Load the pipeline# Use bfloat16 for optimal performance on supported GPUspipe = ZImagePipeline.from_pretrained(    &quot;./Z-Image-Turbo&quot;,    torch_dtype=torch.bfloat16,    low_cpu_mem_usage=False,)pipe.to(&quot;cuda&quot;)# [Optional] Attention Backend# Diffusers uses SDPA by default. Switch to Flash Attention for better efficiency if supported:# pipe.transformer.set_attention_backend(&quot;flash&quot;)    # Enable Flash-Attention-2# pipe.transformer.set_attention_backend(&quot;_flash_3&quot;) # Enable Flash-Attention-3# [Optional] Model Compilation# Compiling the DiT model accelerates inference, but the first run will take longer to compile.# pipe.transformer.compile()# [Optional] CPU Offloading# Enable CPU offloading for memory-constrained devices.# pipe.enable_model_cpu_offload()prompt = &quot;Young Chinese woman in red Hanfu, intricate embroidery. Impeccable makeup, red floral forehead pattern. Elaborate high bun, golden phoenix headdress, red flowers, beads. Holds round folding fan with lady, trees, bird. Neon lightning-bolt lamp (⚡️), bright yellow glow, above extended left palm. Soft-lit outdoor night background, silhouetted tiered pagoda (西安大雁塔), blurred colorful distant lights.&quot;import timestart_time = time.time()# 2. Generate Imageimage = pipe(    prompt=prompt,    height=1024,    width=1024,    num_inference_steps=9,  # This actually results in 8 DiT forwards    guidance_scale=0.0,     # Guidance should be 0 for the Turbo models    generator=torch.Generator(&quot;cuda&quot;).manual_seed(42),).images[0]# 记录结束时间并计算耗时end_time = time.time()elapsed_time = end_time - start_timeprint(f&#39;消耗时间: {elapsed_time}&#39;)image.save(&quot;example.png&quot;)</code></pre><p>经过我测试，相同的我的M1 Mac需要大概率200秒生成一张图，Windows 的4090需要大概160秒，速度也还行吧。但是，如果是NVIDIA RTX PRO 6000，则需要3秒，一下子差异就有了。因此如果想要体验的话，我建议直接去用在线的站点，毕竟在线用也就只需要10秒而已，还不需要自己配置环境。</p><p>PS: 加载模型也需要时间的，模型文件大小是33G，如果不是固态硬盘，可能还需要画个几分钟。</p><p>官方提供的在线站点:</p><ul><li>huggingface: <a href="https://huggingface.co/spaces/Tongyi-MAI/Z-Image-Turbo" target="_blank">https://huggingface.co/spaces/Tongyi-MAI/Z-Image-Turbo</a></li><li>modelspace: <a href="https://www.modelscope.cn/aigc/imageGeneration?tab=advanced&amp;versionId=469191&amp;modelType=Checkpoint&amp;sdVersion=Z_IMAGE_TURBO&amp;modelUrl=modelscope%3A%2F%2FTongyi-MAI%2FZ-Image-Turbo%3Frevision%3Dmaster" target="_blank">https://www.modelscope.cn/aigc/imageGeneration?tab=advanced&amp;versionId=469191&amp;modelType=Checkpoint&amp;sdVersion=Z_IMAGE_TURBO&amp;modelUrl=modelscope%3A%2F%2FTongyi-MAI%2FZ-Image-Turbo%3Frevision%3Dmaster</a></li></ul><p>下图是我自己测试的效果，用的prompt是：“一个生物信息学家，正在努力的赶项目，前面有三个屏幕（左，右是竖屏），桌边是冰美式，脚下是吃掉的麦当劳”</p><p><img src="/upload/2025/11/image-1764426037769.png" alt="image-1764426037769" /></p><p>同样的提示词交给谷歌的生图模式就没有问题，起码冰美式和竖屏都对了。</p><p><img src="/upload/2025/11/image-1764426117168.png" alt="image-1764426117168" /></p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[我卸载了沉浸式翻译，安装了KISS和Ries]]></title>
                <link rel="alternate" type="text/html" href="http://xuzhougeng.com/archives/recommend-on-kiss-and-ries-for-english-learning" />
                <id>tag:http://xuzhougeng.com,2025-11-29:recommend-on-kiss-and-ries-for-english-learning</id>
                <published>2025-11-29T18:25:39+08:00</published>
                <updated>2025-11-29T18:27:08+08:00</updated>
                <author>
                    <name>徐洲更</name>
                    <uri>http://xuzhougeng.com</uri>
                </author>
                <content type="html">
                        <![CDATA[<blockquote><p>本文段落中的英文为Ries自动替换</p></blockquote><p>我应该是沉浸式翻译的老用户，购买过了两年的年度 subscription(订阅)服务。 因为 用起来效果确实挺不错的，上面是英文,下面是对照的中文，相比于全部翻译成中文，我还能有机会了解下我不懂的单词。</p><p><img src="/upload/2025/11/image-1764411786173.png" alt="image-1764411786173" /></p><p>但是用着用着，我就感觉自己的英语水平咋开始倒退了，仔细一想，我发现我在使用的时候几乎看的全是中文那部分，就跟看外语电影，只要有字幕，我肯定就开始盯着屏幕的下方了。</p><p>虽然，我相信随着科技的进步，我们都不需要专门学习英语，只要开着App，然后你说一句，它翻译一句，同时 translate(翻译) 对方说的话（现在应该已经能实现了）。 不过，我个人是觉得翻译本身就是一种信息的不完全的 conversion(转换)，比如说，你将唐诗翻译成英文，就可能失去了原来的那种意境。 所以，我个人还是觉得有必要继续加强下自己。</p><p>我想到的第一个方法就是能够在网页里面自动高亮我不熟悉的单词，这个我用到KISS插件，它里面可以配置highlight(高亮)。</p><p><img src="/upload/2025/11/image-1764411803512.png" alt="image-1764411803512" /></p><p>于是你就能在平时用浏览器看东西的时候，不知不觉的强化对一些陌生单词的记忆，毕竟好歹经过那么多年的教育，大部分的句子都是能读懂，只是少部分单词可能不认识，需要多次接触才能够熟悉。</p><p><img src="/upload/2025/11/image-1764411818259.png" alt="image-1764411818259" /></p><p>后来，我又发现了一个新的工具，叫做Rise。它的思路就是在你平时阅读材料做替换，大概是下面这个效果。基本上一个段落里面就会替换一两处，确保你不会读不下去，又能够接触新的单词。KISS的好处在于读英文材料的时候，帮我高亮我不记得单词，Rise就能够在我读中文的时候，也增加我一些生词的接触机会。</p><p>Rise是懂营销的，新用户首日是五折，抓住了我们捡便宜的心理。不过，最近刚好是黑五打折，有一个离谱的四折活动，我就以199买了一个ultra会员，感觉赚到了（比沉浸式翻译的一年订阅便宜多了）。</p><p><img src="/upload/2025/11/image-1764411826649.png" alt="image-1764411826649" /></p><p>Anyway，如果你感兴趣的话，可以考虑通过我的邀请地址（邀请码是7QBI)，<a href="https://ries.ai?c=7QBI" target="_blank">https://ries.ai?c=7QBI</a>   购买，会有额外一个月的时长</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[做了一个微信公众号Markdown编辑器-02]]></title>
                <link rel="alternate" type="text/html" href="http://xuzhougeng.com/archives/create-a-wx-markdown-editor-02" />
                <id>tag:http://xuzhougeng.com,2025-11-21:create-a-wx-markdown-editor-02</id>
                <published>2025-11-21T22:43:25+08:00</published>
                <updated>2025-11-22T10:37:33+08:00</updated>
                <author>
                    <name>徐洲更</name>
                    <uri>http://xuzhougeng.com</uri>
                </author>
                <content type="html">
                        <![CDATA[<p>前两天自己通过&quot;氛围编程&quot;手搓了一个满足自己需要的微信公众号编辑器，第一版本虽然能用，但是还是没有存在问题，当然问题还是出在图片上。也就是我自己站点的图片，微信公众号后台有一定概率拉取不到，而之前用的墨滴的自带的图床没有这个问题。</p><p>这个方法我的解决思路就是先把图片上传到微信公众后台，然后替换本地markdown里的内容。因此，我专门搞了一个设置页，用配置AppID和开发者密码，可以在微信公众号的后台获取。此外，还得设置IP白名单，这个实在是太严格了。</p><p><img src="/upload/2025/11/image-1763733455594.png" alt="image-1763733455594" /></p><p>我们先可以把远程的图片本地化</p><p><img src="/upload/2025/11/image-1763777947542.png" alt="image-1763777947542" /></p><p>然后上传到公众号就行，而且因为上传到了公众号，就有了防盗链系统，图片就成了下面的情况，一定程度上，让我们知道哪些图片是上传的，哪些是没有的</p><p><img src="/upload/2025/11/image-1763778028862.png" alt="image-1763778028862" /></p><p>虽然编辑器目前还是有很多bug，但至少目前发表公众号就方便多了。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[做了一个微信公众号Markdown编辑器]]></title>
                <link rel="alternate" type="text/html" href="http://xuzhougeng.com/archives/create-a-wx-markdown-editor" />
                <id>tag:http://xuzhougeng.com,2025-11-21:create-a-wx-markdown-editor</id>
                <published>2025-11-21T21:06:34+08:00</published>
                <updated>2025-11-21T21:06:34+08:00</updated>
                <author>
                    <name>徐洲更</name>
                    <uri>http://xuzhougeng.com</uri>
                </author>
                <content type="html">
                        <![CDATA[<p>我平时写东西一般来说都喜欢在我的Halo的后台写，然后到<a href="https://www.mdnice.com/" target="_blank">墨滴</a>上进行渲染，然后粘贴微信公众号的后台。</p><p><img src="/upload/2025/11/image.png" alt="image" /></p><p>整个流程里面有个最讨厌的是步骤就是图片，因为我的图片在Halo后台是相对路径，这就导致复制到墨滴后台，要么是自己一个个添加网站前缀，要么就是重新截图，很麻烦。</p><p>为了节约这点时间，我打算自己做一个本地的编辑器。当然主要原因是最近谷歌推出了Antigravity，里面的Gemini 3 Pro免费用。如下是我的项目的初始化的提示词:</p><blockquote><p>使用rust开发一个跨平台的基于markdown转成微信公众号的编辑器，样式需要内连。</p></blockquote><p>Gemini3 Pro 用的技术栈是 Tauri 和 React，Tauri 主要管“和电脑打交道”的那部分，比如文件操作、窗口管理之类的底层功能；React 就负责“你看到的那一层”，也就是界面、交互、按钮这些前端展示的东西。</p><p>基本上一轮跑下来，完成度大概就有 90% 了，界面如下，其中右上角的网址前缀是我后面迭代一轮得到的，也就是最需要的功能，这篇推文也就是通过这个方式来生成的。</p><p><img src="/upload/2025/11/image-1763729835947.png" alt="image-1763729835947" /></p><p>项目目前开源在在Github上，我通过GitHub action自动化打包了全平台安装包，见<a href="https://github.com/xuzhougeng/WxTyper/releases" target="_blank">releases</a>，至少我在Windows 11里面是能够直接通过exe安装，但是下载的时候会被认为是不安全文件，需要手动选择保存。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[在Shell中配置一个AI智能助手]]></title>
                <link rel="alternate" type="text/html" href="http://xuzhougeng.com/archives/config-ai-assistant-in-shell" />
                <id>tag:http://xuzhougeng.com,2025-09-14:config-ai-assistant-in-shell</id>
                <published>2025-09-14T10:10:45+08:00</published>
                <updated>2025-09-14T10:10:45+08:00</updated>
                <author>
                    <name>徐洲更</name>
                    <uri>http://xuzhougeng.com</uri>
                </author>
                <content type="html">
                        <![CDATA[<p>当前项目是受到Shell_GPT启发的，使用Rust开发的一个命令行工具，作用跟Shell_GPT几乎一样，就是可以让你命令行里面调用LLM。</p><p>相比于Shell_GPT，我搞的sgp_rs应该是可以直接下载二进制文件解压缩就能用的，所以安装代码如下, 以0.4.5版本为例。如果有最新的，从 <a href="https://github.com/xuzhougeng/sgpt-rs/releases/" target="_blank">https://github.com/xuzhougeng/sgpt-rs/releases/</a>下载。</p><pre><code class="language-bash">wget https://github.com/xuzhougeng/sgpt-rs/releases/download/v0.4.5/sgpt-v0.4.5-linux-musl-x86_64.tar.gztar xf sgpt-v0.4.5-linux-musl-x86_64.tar.gz</code></pre><p>接着把sgpt添加到环境变量中，或者在当前目录下用<code>./sgpt</code>的方式使用。</p><p>先使用我的fake模型评估是否安装成功</p><pre><code class="language-bash">sgpt --model fake &quot;Hello world&quot;</code></pre><p>为了真正的使用模型，编辑 ~/.config/sgpt_rs/.sgptrc 设置使用DeepSeek作为默认模型</p><pre><code class="language-yaml">API_BASE_URL=https://api.deepseek.comOPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxDEFAULT_MODEL=deepseek-chat</code></pre><p>也可以直接在环境变量或者在~/.zshrc, ~/.bashrc中配置</p><pre><code class="language-bash">export API_BASE_URL=https://api.deepseek.comexport OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxexport DEFAULT_MODEL=deepseek-chat</code></pre><p>大抵是支持所所有OpenAI接口兼容的模型，比如说轨迹流动的接口。</p><pre><code class="language-bash">export API_BASE_URL=https://api.siliconflow.cnexport OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxexport DEFAULT_MODEL=moonshotai/Kimi-K2-Instruct-0905</code></pre><p>也支持本地Ollama</p><pre><code class="language-bash"># 推荐写法：带 /v1（客户端会自动补齐 /v1，不带也可以）export API_BASE_URL=http://localhost:11434/v1# Ollama 不需要API_KEY, 随便写export OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx# 选择已拉取的模型，例如：llama3.1 / qwen2.5 / mistral 等export DEFAULT_MODEL=gpt-oss:120b</code></pre><p>如果你是服务器A上配置了Ollama，想让服务器B也能用。千万不要修改让Ollama的Host为0.0.0.0，因为Ollama无法设置API_KEY，很容易被其他人用。最好的方法你用Nignx转发。</p><pre><code class="language-bash">server {  listen 80;  server_name _;   # 或者写你的内网主机名/IP  # 基本认证  # （可选）内网 IP 白名单，更安全  allow 172.16.0.0/12;  allow 192.168.0.0/16;  deny all;  location / {    proxy_pass http://127.0.0.1:11434;    proxy_http_version 1.1;    proxy_set_header Host $host;    proxy_set_header X-Real-IP $remote_addr;    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;    proxy_set_header X-Forwarded-Proto $scheme;    # 对流式响应（SSE）很重要    proxy_buffering off;    proxy_read_timeout 3600s;    proxy_send_timeout 3600s;  }}</code></pre><p>然后其他服务器只需要修改 <code>export API_BASE_URL=http://你的Ollama的服务器:11434/v1</code>即可使用</p><p>对于我而言，sgpt的主要用户就是如下几个</p><p>第一，一些复杂的命令，我想不到起来，例如find查找一天内生成的文件</p><pre><code class="language-bash">sgpt -s &#39;find查找一天内生成的文件&#39;# 输出的结果find . -type f -mtime -1[E]xecute, [M]odify, [D]escribe, [A]bort:</code></pre><p>这里的E表示执行，M表示还不对，继续提示，D表示解释这个命令，A表示退出。</p><p>第二，就是不想复制信息到网页里，可以直接通过管道符合给sgpt，比如说</p><pre><code class="language-">cat install.sh  | sgpt &#39;这个脚本用途是什么?&#39;</code></pre><p>第三，直接生成脚本</p><pre><code class="language-">sgpt --code &#39;来一个shell脚本分析下最近的登录用户&#39; &gt; run.shbash run.sh</code></pre><p>当然实际上我还开发了很多有趣的功能，就后面慢慢介绍了</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[使用银河录像店代充ChatGPT Plus]]></title>
                <link rel="alternate" type="text/html" href="http://xuzhougeng.com/archives/use-nf-video-to-top-up-chatgpt-plus" />
                <id>tag:http://xuzhougeng.com,2025-09-06:use-nf-video-to-top-up-chatgpt-plus</id>
                <published>2025-09-06T10:01:27+08:00</published>
                <updated>2025-09-06T12:50:26+08:00</updated>
                <author>
                    <name>徐洲更</name>
                    <uri>http://xuzhougeng.com</uri>
                </author>
                <content type="html">
                        <![CDATA[<p>之前我一直用的就是野卡充值我的ChatGPT Plus，然而因为不可抗力，它大概率是用不了了，因此目前的思路就是走代充。</p><p>通过银河录像局  <a href="https://nf.video/5iPel" target="_blank">https://nf.video/5iPel</a> （最后的 5iPel 是我的邀请码）注册一个账号，然后到首页代充的ChatGPT Plus代充。</p><p><img src="/upload/2025/09/image-1757123395417.png" alt="ChatGPT Plus代充" /></p><p>跳转到对应的购买页面，需要注意的是，这里的包年实际上，他还是一个月一个月给你充，只不过你现在是一次性付费了而已，所以我选择的是1个月。</p><p><img src="/upload/2025/09/image-1757123443266.png" alt="image-1757123443266" /></p><p>支付成功后有一个车票信息，你点击这个</p><p><img src="/upload/2025/09/image-1757123581647.png" alt="image-1757123581647" /></p><p>然后需要你绑定账号，就是你登录ChatGPT的账号</p><p><img src="/upload/2025/09/image-1757123610171.png" alt="image-1757123610171" /></p><p>接着，我们需要在登录ChatGPT后，通过<a href="https://chatgpt.com/api/auth/session" target="_blank">https://chatgpt.com/api/auth/session</a> 获取我们的认证信息，</p><p><img src="/upload/2025/09/image-1757123694794.png" alt="image-1757123694794" /></p><p>粘贴到图中，然后验证充值账号</p><p><img src="/upload/2025/09/image-1757123778001.png" alt="image-1757123778001" /></p><p>最后点击确认充值，大概需要等到3-5分钟。</p><p><img src="/upload/2025/09/image-1757123954614.png" alt="image-1757123954614" /></p><p>当然也有一定概率失败，那就只能自己填写账号信息让客服帮你处理了。</p><p><img src="/upload/2025/09/image-1757123932779.png" alt="image-1757123932779" /></p><p>成功的结算界面如下</p><p><img src="/upload/2025/09/image-1757134176660.png" alt="image-1757134176660" /></p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[通过代理使用Claude-Code]]></title>
                <link rel="alternate" type="text/html" href="http://xuzhougeng.com/archives/use-claude-code-by-proxy" />
                <id>tag:http://xuzhougeng.com,2025-09-05:use-claude-code-by-proxy</id>
                <published>2025-09-05T13:12:02+08:00</published>
                <updated>2026-01-06T09:12:23+08:00</updated>
                <author>
                    <name>徐洲更</name>
                    <uri>http://xuzhougeng.com</uri>
                </author>
                <content type="html">
                        <![CDATA[<p>之前使用API搞Claude-Code开发，但是发现太费钱了。后面又搞了订阅，但是20美刀不够用，100美刀又太贵，而且还担心封号。还好上有政策下有对策，总有转发的方案，目前我的主力方案就是<a href="https://www.aicodemirror.com/" target="_blank">https://www.aicodemirror.com/</a>。</p><p>在 <a href="https://www.aicodemirror.com/register?invitecode=A6DYDL" target="_blank">https://www.aicodemirror.com/register?invitecode=A6DYDL</a> 注册（A6DYDL是我的邀请码），然后到控制台<a href="https://www.aicodemirror.com/dashboard" target="_blank">https://www.aicodemirror.com/dashboard</a>，会有一个弹窗提示添加企业微信可以领取8元尝鲜券，进行试用。</p><p><img src="/upload/2025/09/image-1758290776779.png" alt="image-1758290776779" /></p><p>点击“API密钥”，然后创建API密钥</p><p><img src="/upload/2025/09/image-1757048971860.png" alt="image-1757048971860" /></p><p>需要注意，这个密钥你得复制一份到本地记事本存下，后面要用到。如果忘了，就重新建立一个。</p><p><img src="/upload/2025/09/image-1757044443658.png" alt="image-1757044443658" /></p><p>之后，使用aicoder提供的自动化安装脚本，安装npm</p><pre><code class="language-">curl -fsSL https://download.aicodemirror.com/env_deploy/env-install.sh | bash</code></pre><p><img src="/upload/2025/09/image-1757047884543.png" alt="image-1757047884543" /></p><p>安装之后，你应该可以看到npm是在你的家目录下了，比如说我的家目录就是 /home/xzg</p><pre><code class="language-bash">$ which npm/home/xzg/.nvm/versions/node/v22.19.0/bin/npm</code></pre><p>然后运行运行命令，安装官方claude-code</p><pre><code class="language-bash">npm install -g @anthropic-ai/claude-code</code></pre><p>接着使用如下脚本，配置环境，需要用到刚才获取的API_KYE</p><pre><code class="language-">curl -fsSL https://download.aicodemirror.com/env_deploy/env-deploy.sh | bash -s -- &quot;你的API_KEY&quot;</code></pre><p>如果因为环境没有jq，导致无法正确编辑 ~/.claude.json ，可以手动编辑。后续变更密钥后也可以自己手动改</p><pre><code class="language-">{  &quot;customApiKeyResponses&quot;: {    &quot;approved&quot;: [      &quot;你的API_KEY的最后20位&quot;    ]  }}</code></pre><p>可以自己手动在 .bashrc，.zshrc 添加如下的环境变量。</p><pre><code class="language-">export ANTHROPIC_BASE_URL=https://api.aicodemirror.com/api/claudecodeexport ANTHROPIC_API_KEY=刚才复制的你的密钥export ANTHROPIC_AUTH_TOKEN=&quot;&quot;</code></pre><p>使用claude打开后，会让配置主题这些，最后就会看到下图，其中API Base URL就是代理商的地址。</p><p><img src="/upload/2025/09/image-1757044729711.png" alt="image-1757044729711" /></p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[Juicer 1.6 数据处理流程详解]]></title>
                <link rel="alternate" type="text/html" href="http://xuzhougeng.com/archives/detailed-explanation-of-the-data-processing-flow-of-juicer-1-6" />
                <id>tag:http://xuzhougeng.com,2025-09-04:detailed-explanation-of-the-data-processing-flow-of-juicer-1-6</id>
                <published>2025-09-04T21:38:13+08:00</published>
                <updated>2025-09-04T21:38:13+08:00</updated>
                <author>
                    <name>徐洲更</name>
                    <uri>http://xuzhougeng.com</uri>
                </author>
                <content type="html">
                        <![CDATA[<h2 id="%E6%A6%82%E8%BF%B0" tabindex="-1">概述</h2><p>Juicer 是一个用于处理 Hi-C 测序数据的完整分析流程，从原始 FASTQ 文件到最终的接触矩阵（.hic 文件）。</p><p>安装方法如下</p><pre><code class="language-bash">wget https://github.com/aidenlab/juicer/archive/refs/tags/1.6.tar.gztar xf 1.6.tar.gzcd juicer-1.6ln -s $PWD/CPU scriptscd scripts/commonwget https://hicfiles.tc4ga.com/public/juicer/juicer_tools.1.9.9_jcuda.0.8.jarln -s juicer_tools.1.9.9_jcuda.0.8.jar  juicer_tools.jar</code></pre><h2 id="%E4%B8%BB%E8%A6%81%E5%A4%84%E7%90%86%E9%98%B6%E6%AE%B5" tabindex="-1">主要处理阶段</h2><h3 id="1.-%E6%AF%94%E5%AF%B9%E9%98%B6%E6%AE%B5-(alignment)" tabindex="-1">1. 比对阶段 (Alignment)</h3><p><strong>功能</strong>：将双端测序reads比对到参考基因组</p><ul><li>使用 BWA mem 进行比对</li><li>参数 <code>-SP5M</code> 专门针对 Hi-C 数据优化<ul><li><code>-SP</code>: 跳过配对救援，将read1和read2独立比对</li><li><code>-5</code>: 对于split reads，输出主要和补充比对</li><li><code>-M</code>: 将较短的split标记为次要比对</li></ul></li><li>输出：SAM 格式的比对文件</li></ul><h3 id="2.-%E5%B5%8C%E5%90%88reads%E5%A4%84%E7%90%86-(chimeric-reads-processing)" tabindex="-1">2. 嵌合reads处理 (Chimeric Reads Processing)</h3><p><strong>功能</strong>：识别和处理跨越多个基因组区域的reads</p><h4 id="%E4%BB%80%E4%B9%88%E6%98%AF%E5%B5%8C%E5%90%88reads" tabindex="-1">什么是嵌合reads</h4><p>在Hi-C实验中，一个DNA分子可能包含多个连接点：</p><pre><code class="language-">Read序列: [区域A]--[连接点]--[区域B]--[连接点]--[区域C]</code></pre><h4 id="%E5%A4%84%E7%90%86%E6%9C%BA%E5%88%B6" tabindex="-1">处理机制</h4><p><code>chimeric_blacklist.awk</code> 脚本将reads分为三类：</p><ul><li><strong>正常配对</strong> (<code>_norm.txt</code>)：标准的双端配对，两个reads各映射到单一位置</li><li><strong>异常配对</strong> (<code>_abnorm.sam</code>)：包含嵌合reads，有补充比对（SA tag）</li><li><strong>未映射</strong> (<code>_unmapped.sam</code>)：无法比对的低质量reads</li></ul><h4 id="%E7%94%9F%E7%89%A9%E5%AD%A6%E6%84%8F%E4%B9%89" tabindex="-1">生物学意义</h4><ul><li>反映多重染色质互作（A-B-C三者空间接近）</li><li>可能指示染色体重排或复杂的空间结构</li><li>提供额外的互作信息，提高数据利用率</li></ul><h3 id="3.-%E7%89%87%E6%AE%B5%E5%88%86%E9%85%8D-(fragment-assignment)" tabindex="-1">3. 片段分配 (Fragment Assignment)</h3><p><strong>功能</strong>：将reads分配到对应的限制性酶切片段</p><h4 id="%E4%BD%9C%E7%94%A8%E6%9C%BA%E5%88%B6" tabindex="-1">作用机制</h4><ul><li>使用 <code>fragment.pl</code> 根据酶切位点文件分配片段编号</li><li>为每个read pair添加片段信息（片段号和片段间距离）</li></ul><h4 id="%E6%95%B0%E6%8D%AE%E6%A0%BC%E5%BC%8F%E8%BD%AC%E6%8D%A2" tabindex="-1">数据格式转换</h4><p>分配前：</p><pre><code class="language-">readname chr1 pos1 chr2 pos2 strand1 strand2</code></pre><p>分配后：</p><pre><code class="language-">readname chr1 pos1 frag1 chr2 pos2 frag2 frag_distance</code></pre><h4 id="%E8%B4%A8%E9%87%8F%E6%8E%A7%E5%88%B6%E6%84%8F%E4%B9%89" tabindex="-1">质量控制意义</h4><p>片段分配用于区分：</p><ul><li><strong>有效配对</strong>：不同片段间的连接（真实互作）</li><li><strong>自连片段</strong> (dangling ends)：同一片段内的连接</li><li><strong>自环片段</strong> (self-circles)：片段自身环化</li><li><strong>重连片段</strong> (re-ligation)：相邻片段的非特异连接</li></ul><h4 id="dnase-hi-c%E7%89%B9%E6%AE%8A%E5%A4%84%E7%90%86" tabindex="-1">DNase-Hi-C特殊处理</h4><p>当使用 <code>site=&quot;none&quot;</code> 时，不进行实际片段分配，设置假片段值（0和1）</p><h3 id="4.-%E6%8E%92%E5%BA%8F-(sorting)" tabindex="-1">4. 排序 (Sorting)</h3><p><strong>功能</strong>：对处理后的数据进行多键排序</p><ul><li>排序顺序：染色体 → 片段 → 链方向 → 位置</li><li>使用临时目录处理大文件：<code>-T $tmpdir</code></li></ul><h3 id="5.-%E5%90%88%E5%B9%B6-(merge)" tabindex="-1">5. 合并 (Merge)</h3><p><strong>功能</strong>：将所有排序文件合并为单一文件</p><ul><li>输出：<code>merged_sort.txt</code></li><li>保持排序顺序，为去重做准备</li></ul><h3 id="6.-%E5%8E%BB%E9%87%8D%E5%A4%8D-(deduplication)" tabindex="-1">6. 去重复 (Deduplication)</h3><p><strong>功能</strong>：去除PCR扩增产生的重复reads</p><h4 id="%E5%A4%84%E7%90%86%E9%80%89%E9%A1%B9" tabindex="-1">处理选项</h4><ul><li>默认模式：使用&quot;wobble&quot;策略（允许位置轻微偏移）</li><li>精确模式（<code>-j</code>参数）：仅去除完全相同的重复</li></ul><h4 id="%E8%BE%93%E5%87%BA%E6%96%87%E4%BB%B6" tabindex="-1">输出文件</h4><ul><li><code>merged_nodups.txt</code>：去重后的有效配对</li><li><code>dups.txt</code>：被去除的重复reads</li><li><code>opt_dups.txt</code>：光学重复</li></ul><h3 id="7.-%E7%BB%9F%E8%AE%A1%E5%88%86%E6%9E%90-(statistics)" tabindex="-1">7. 统计分析 (Statistics)</h3><p><strong>功能</strong>：生成质量控制指标</p><h4 id="%E4%B8%BB%E8%A6%81%E7%BB%9F%E8%AE%A1%E5%86%85%E5%AE%B9" tabindex="-1">主要统计内容</h4><ul><li><strong>文库复杂度</strong>：评估文库多样性</li><li><strong>有效配对率</strong>：真实互作的比例</li><li><strong>片段内/间配对</strong>：评估消化和连接效率</li><li><strong>短程/长程互作</strong>：距离分布统计</li><li><strong>碰撞分析</strong>：处理异常和嵌合reads统计</li></ul><h3 id="8.-hic%E6%96%87%E4%BB%B6%E7%94%9F%E6%88%90-(hic-file-creation)" tabindex="-1">8. HiC文件生成 (HiC File Creation)</h3><p><strong>功能</strong>：创建二进制接触矩阵文件</p><h4 id="%E8%B4%A8%E9%87%8F%E7%89%88%E6%9C%AC" tabindex="-1">质量版本</h4><ul><li><strong>inter.hic</strong>：MAPQ ≥ 1（包含更多数据）</li><li><strong>inter_30.hic</strong>：MAPQ ≥ 30（高质量数据）</li></ul><h4 id="%E5%8F%82%E6%95%B0%E8%AF%B4%E6%98%8E" tabindex="-1">参数说明</h4><ul><li><code>-f</code>：包含片段信息（用于片段级分辨率）</li><li><code>-s</code>：统计文件路径</li><li><code>-g</code>：直方图输出</li><li><code>-q</code>：最小映射质量阈值</li></ul><h3 id="9.-%E5%90%8E%E5%A4%84%E7%90%86-(post-processing)" tabindex="-1">9. 后处理 (Post-processing)</h3><p><strong>功能</strong>：特征注释和高级分析</p><ul><li>调用 <code>juicer_postprocessing.sh</code></li><li>添加基因组注释</li><li>识别染色质环等特征</li></ul><h2 id="%E6%96%AD%E7%82%B9%E6%81%A2%E5%A4%8D%E6%9C%BA%E5%88%B6" tabindex="-1">断点恢复机制</h2><p>Juicer 支持从特定阶段恢复，避免重复计算：</p><h3 id="%E6%81%A2%E5%A4%8D%E9%98%B6%E6%AE%B5-(-s-%E5%8F%82%E6%95%B0)" tabindex="-1">恢复阶段 (-S 参数)</h3><ul><li><strong>merge</strong>：从合并步骤开始（比对已完成）</li><li><strong>dedup</strong>：从去重步骤开始（合并已完成）</li><li><strong>final</strong>：从生成HiC文件开始（去重已完成）</li><li><strong>postproc</strong>：仅执行后处理</li><li><strong>early</strong>：在统计后提前退出</li></ul><h2 id="%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98%E5%8F%8A%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88" tabindex="-1">常见问题及解决方案</h2><h3 id="1.-awk-%E5%85%BC%E5%AE%B9%E6%80%A7%E9%97%AE%E9%A2%98" tabindex="-1">1. AWK 兼容性问题</h3><p><strong>问题</strong>：<code>and() function never defined</code><br /><strong>原因</strong>：使用了 mawk 而非 gawk<br /><strong>解决</strong>：安装并使用 GNU awk (gawk)</p><h3 id="2.-%E7%BC%BA%E5%B0%91-juicer_tools" tabindex="-1">2. 缺少 juicer_tools</h3><p><strong>问题</strong>：<code>juicer_tools: No such file or directory</code><br /><strong>解决</strong>：下载 juicer_tools.jar 并创建执行脚本</p><h3 id="3.-%E9%AB%98%E5%B5%8C%E5%90%88reads%E7%8E%87" tabindex="-1">3. 高嵌合reads率</h3><p><strong>可能原因</strong>：</p><ul><li>过度消化（片段太小）</li><li>连接浓度过高</li><li>交联不充分<br /><strong>建议</strong>：优化实验条件，检查酶切和连接步骤</li></ul><h2 id="%E5%85%B3%E9%94%AE%E8%B4%A8%E9%87%8F%E6%8C%87%E6%A0%87" tabindex="-1">关键质量指标</h2><h3 id="%E8%89%AF%E5%A5%BD%E7%9A%84hi-c%E6%95%B0%E6%8D%AE%E5%BA%94%E5%85%B7%E5%A4%87" tabindex="-1">良好的Hi-C数据应具备</h3><ul><li>有效配对率 &gt; 60%</li><li>片段间配对率 &gt; 90%</li><li>长程互作（&gt;20kb）&gt; 40%</li><li>PCR重复率 &lt; 20%</li><li>嵌合reads率 &lt; 15%</li></ul><h3 id="%E8%B4%A8%E9%87%8F%E8%AF%84%E4%BC%B0%E8%A6%81%E7%82%B9" tabindex="-1">质量评估要点</h3><ol><li><strong>比对率</strong>：评估测序质量和基因组匹配度</li><li><strong>有效配对率</strong>：反映实验成功程度</li><li><strong>文库复杂度</strong>：评估数据多样性</li><li><strong>距离分布</strong>：验证是否符合预期的幂律分布</li><li><strong>片段大小分布</strong>：评估酶切效率</li></ol><h2 id="%E4%BC%98%E5%8C%96%E5%BB%BA%E8%AE%AE" tabindex="-1">优化建议</h2><h3 id="%E8%AE%A1%E7%AE%97%E8%B5%84%E6%BA%90" tabindex="-1">计算资源</h3><ul><li>使用多线程加速BWA比对（<code>-t</code> 参数）</li><li>预留足够的临时空间用于排序</li><li>内存需求：至少16GB用于 juicer_tools</li></ul><h3 id="%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86" tabindex="-1">数据处理</h3><ul><li>保留中间文件便于问题排查</li><li>定期检查各阶段输出文件大小</li><li>使用 <code>-S</code> 参数从断点恢复，避免重复计算</li></ul><h2 id="%E6%96%87%E4%BB%B6%E7%BB%84%E7%BB%87%E7%BB%93%E6%9E%84" tabindex="-1">文件组织结构</h2><pre><code class="language-">topDir/├── fastq/          # 原始测序文件├── splits/         # 中间处理文件│   ├── *.sam│   ├── *_norm.txt│   ├── *_abnorm.sam│   ├── *_unmapped.sam│   └── *.sort.txt├── aligned/        # 最终输出文件│   ├── merged_sort.txt│   ├── merged_nodups.txt│   ├── inter.txt│   ├── inter.hic│   └── inter_30.hic└── HIC_tmp/        # 临时文件目录</code></pre><h2 id="%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99" tabindex="-1">参考资料</h2><ul><li><a href="https://github.com/aidenlab/juicer" target="_blank">Juicer GitHub</a></li><li><a href="https://github.com/aidenlab/juicer/wiki" target="_blank">Juicer Wiki</a></li><li>Durand et al., 2016. Cell Systems%</li></ul>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[使用Codex模仿shell_gpt]]></title>
                <link rel="alternate" type="text/html" href="http://xuzhougeng.com/archives/usecodextoimitateshellgpt" />
                <id>tag:http://xuzhougeng.com,2025-08-27:usecodextoimitateshellgpt</id>
                <published>2025-08-27T15:16:54+08:00</published>
                <updated>2025-08-27T15:16:54+08:00</updated>
                <author>
                    <name>徐洲更</name>
                    <uri>http://xuzhougeng.com</uri>
                </author>
                <content type="html">
                        <![CDATA[<blockquote><p>Agent的出现，导致每次任务的token消耗量都特别的大，所以Cursor我也不再订阅了，使用Claude-Code和Codex进行平时的开发。</p></blockquote><p>之前用OpenAI的codex进行项目开发，发现效果非常一般，但是GPT-5出来之后，改变了我的看法。</p><p>我的目标是用Rust写一个<a href="https://github.com/TheR1D/shell_gpt" target="_blank">shell_gpt</a>，这是生成的结果 <a href="https://github.com/xuzhougeng/sgpt-rs" target="_blank">https://github.com/xuzhougeng/sgpt-rs</a> ，确实完成了我的需求，大概就说了如下一些话</p><ol><li>阅读 shellgpt 项目，我计划使用Rust对该项目进行重构，请制定一个项目规划</li><li>仅支持原生 JSON 工具 ；  termimad（更终端友好）； 自行 reqwest 保持更灵活； 然后将规划写到Plan.md中</li><li>请继续搭建 Rust 项目骨架（目录结构与最小 main/CLI 参数）</li><li>yes  proceed with handler routing + config loader next</li><li>start on the reqwest-based LLM streaming client?</li><li>before you start, let me give your a basic information; API_BASE_URL=<a href="https://api.deepseek.com" target="_blank">https://api.deepseek.com</a>  OPENAI_API_KEY=sk-  DEFAULT_MODEL=deepseek-chat ; you should set this to env and use for following test; plase go on toto wire the client into the Default and Chat handlers next, using a simple text printer and START/STOP streaming ;</li><li>implement ChatSession persistence and use it in --chat/–repl next</li><li>first add usage into readme</li><li><a href="http://Plan.md" target="_blank">Plan.md</a> 根据进度表，我们现在是到了哪一步，下一步做什么？</li><li>需要的！</li><li>先把 --show-chat 做成更易读的格式, 开始开始接通 Shell/Code/Describe</li><li>我觉得需要接入termimad了</li><li>需要</li><li>需要</li><li>shell模式不太行，是不是还不能执行命令？</li><li><a href="http://Plan.md" target="_blank">Plan.md</a> 根据计划，我们现在到了哪一步？</li><li><ol><li>接入 DEFAULT_EXECUTE_SHELL_CMD 并完善 Shell 交互</li></ol></li><li>可以，完善README</li><li>需要的</li><li>请这样子做！</li><li>需要</li><li><a href="http://README.md" target="_blank">README.md</a> 区分版本，中文版本在README_zh.md 原来的版本是英文</li><li>增加一个.gitignore</li><li>staget this change and commit with git</li><li>add other file and commit</li><li>use git status check  and add file and commit with message</li><li>yes</li><li>我目前已经按照 <a href="http://Plan.md" target="_blank">Plan.md</a> 仿照 shell_gpt 开发了一部分的 sgpt_rs， 请问的项目支持 git diff | sgpt “Generate git commit message, for my changes” 使用方法吗？</li><li>$ tree -L 2 | sgpt-rs ‘描述下项目’<br />Error: LLM error: 422 Unprocessable Entity</li><li>无法通过build …（长错误日志）</li><li>在错误输出中附带更加明确的修复建议（如检测到 422 且包含 “tool_choice” 时提示 --no-functions）</li><li>我觉得参数 --no-functions 换成–functions 默认不用tools, 除非手动要求启动</li><li>当前的sgpt-rs项目如何读取变量，从 .sgptrc 文件吗？</li><li>修改读取路径为  ~/.config/sgpt_rs/.sgptrc</li><li>不仅仅是配置文件读取路径，应该是配置目录就是  ~/.config/sgpt_rs</li><li>需要的</li><li>i found use cargo build have many warnings , try to fix</li><li>following warnings: …（长 warning 输出）</li><li>sgpt的配置文件的路径哪个？</li><li>i have set ~/.config/sgpt_rs/.sgptrc, but Error: LLM error: 401 Unauthorized {“error”:{“message”:“Authentication Fails, Your api key: ****wjIA is invalid”,“type”:“authentication_error”,“param”:null,“code”:“invalid_request_error”}}<br />Hint: Set OPENAI_API_KEY or export it in your shell</li><li>use git to check change and stage and commmit</li></ol><p><a href="http://xn--Plan-494f35bv7le9qq20ave8azs0c.md" target="_blank">如下是他的计划Plan.md</a></p><h1 id="shellgpt-rust-%E9%87%8D%E6%9E%84%E8%A7%84%E5%88%92%EF%BC%88plan%EF%BC%89" tabindex="-1">ShellGPT Rust 重构规划（Plan）</h1><blockquote><p>决策确认（来自你的偏好）：</p><ul><li>工具调用：仅支持原生 JSON 工具（不再兼容 Python 函数类定义）。</li><li>Markdown 渲染：使用 termimad（更终端友好）。</li><li>LLM 客户端：基于 reqwest 自行实现（保持更高灵活性），不绑定 async-openai。</li></ul></blockquote><h2 id="1.-%E7%9B%AE%E6%A0%87%E4%B8%8E%E8%8C%83%E5%9B%B4" tabindex="-1">1. 目标与范围</h2><ul><li>目标：<ul><li>复刻现有 CLI 行为与输出（参数、互斥关系、REPL、Chat/Cache/Role 等），在性能、稳定性、跨平台（Linux/macOS/Windows）上显著提升。</li><li>可扩展：统一 LLM 适配、原生工具调用（JSON 工具）、可插拔渲染与打印。</li></ul></li><li>非目标：<ul><li>迁移或执行旧版 Python 函数生态；不破坏现有配置与用户数据（会话、缓存、角色）。</li></ul></li></ul><h2 id="2.-%E6%80%BB%E4%BD%93%E6%9E%B6%E6%9E%84" tabindex="-1">2. 总体架构</h2><ul><li>分层：<ul><li>CLI 层：参数解析、命令路由、互斥校验。</li><li>应用层：角色与消息拼装、模式处理器（默认/聊天/REPL/代码/命令）、打印器。</li><li>领域层：配置、请求缓存、会话存储、角色管理、原生 JSON 工具、OS/Shell 检测与执行。</li><li>LLM 适配层：OpenAI 兼容端点/LiteLLM/自托管端点统一抽象，使用 reqwest 实现流式解析。</li></ul></li><li>关键抽象：<ul><li>trait LlmClient：<code>chat_stream(messages, params) -&gt; impl Stream&lt;Item = Delta&gt;</code>，屏蔽供应商差异（tool_calls、增量/终止原因）。</li><li>trait Printer：<code>live_print(stream)</code>, <code>static_print(text)</code>；实现 Text 与 Markdown（termimad）。</li><li>Handler（基类）：生成 messages、驱动 LLM、打印输出；派生 Default/Chat/Repl/Code/Shell/DescribeShell。</li><li>Cache/ChatSession：请求级缓存、会话消息 JSON 存储与截断（保留首条 system）。</li></ul></li></ul><h2 id="3.-%E6%A8%A1%E5%9D%97%E6%98%A0%E5%B0%84%EF%BC%88python-%E2%86%92-rust%EF%BC%89" tabindex="-1">3. 模块映射（Python → Rust）</h2><ul><li>sgpt/app.py → <code>crate::cli</code>：clap 命令与 flags、入口 <code>main</code>、互斥与默认值。</li><li>handlers/* → <code>crate::handlers::{default, chat, repl, code, shell, describe}</code>。</li><li><a href="http://role.py" target="_blank">role.py</a> → <code>crate::role::{SystemRole, DefaultRoles, store}</code>。</li><li><a href="http://printer.py" target="_blank">printer.py</a> → <code>crate::printer::{TextPrinter, MarkdownPrinter(termimad)}</code>。</li><li><a href="http://config.py" target="_blank">config.py</a> → <code>crate::config::{loader, env_merge, defaults}</code>。</li><li><a href="http://cache.py" target="_blank">cache.py</a> → <code>crate::cache::{request_cache, chat_cache}</code>。</li><li><a href="http://function.py" target="_blank">function.py</a> + llm_functions → <code>crate::functions::{schema, registry, executor}</code>（原生 JSON 工具）。</li><li><a href="http://utils.py" target="_blank">utils.py</a> → <code>crate::utils::{editor, run_command, install_integration, version}</code>。</li><li><a href="http://integration.py" target="_blank">integration.py</a> → <code>crate::integration::{bash, zsh}</code>。</li></ul><h2 id="4.-%E6%8A%80%E6%9C%AF%E9%80%89%E5%9E%8B" tabindex="-1">4. 技术选型</h2><ul><li>CLI/REPL：clap v4 + rustyline/reedline（行编辑、历史、多行输入）。</li><li>异步/HTTP：tokio + reqwest（自实现 OpenAI 兼容 Chat Completions 流式接口，SSE 或 chunked）。</li><li>终端与颜色：crossterm + owo-colors。</li><li>Markdown 渲染：termimad（主题可调，匹配 CODE_THEME 近似语义）。</li><li>语法高亮：syntect（代码块高亮，主题近似映射）。</li><li>序列化：serde/serde_json。</li><li>路径与平台：directories + sysinfo。</li><li>错误：anyhow/thiserror。</li><li>测试：assert_cmd、insta（快照）、mockito（HTTP 模拟）、proptest（必要时）。</li></ul><h2 id="5.-cli-%E5%85%BC%E5%AE%B9%E7%9F%A9%E9%98%B5" tabindex="-1">5. CLI 兼容矩阵</h2><ul><li>全量还原参数与互斥：<ul><li>通用：<code>--model --temperature --top-p --md/--no-md --editor --cache/--no-cache --version</code>。</li><li>Assistance：<code>--shell/-s --interaction/--no-interaction --describe-shell/-d --code/-c --functions/--no-functions</code>。</li><li>Chat：<code>--chat --repl --show-chat --list-chats/-lc</code>。</li><li>Role：<code>--role --create-role --show-role --list-roles/-lr</code>。</li><li>隐藏：<code>--install-integration --install-functions</code>。</li></ul></li><li>行为一致性：<ul><li>Shell/Code 模式禁用 markdown；三者（shell/describe/code）互斥；REPL 支持 <code>&quot;&quot;&quot;</code> 多行；stdin 拼接含 <code>__sgpt__eof__</code> 协议。</li></ul></li></ul><h2 id="6.-%E9%85%8D%E7%BD%AE%E4%B8%8E%E6%95%B0%E6%8D%AE%E5%B8%83%E5%B1%80" tabindex="-1">6. 配置与数据布局</h2><ul><li>兼容路径：<code>~/.config/shell_gpt/.sgptrc</code>（优先 env 后配置文件）。</li><li>默认键与语义保持一致：<code>DEFAULT_MODEL, CACHE_PATH, CHAT_CACHE_PATH, CODE_THEME, ...</code>。</li><li>会话与请求缓存：JSON 文件；会话截断保留首条 system；缓存命中键与 Python 逻辑一致（忽略含 @FunctionCall 的结果）。</li></ul><h2 id="7.-llm-%E9%80%82%E9%85%8D%EF%BC%88reqwest-%E5%AE%9E%E7%8E%B0%EF%BC%89" tabindex="-1">7. LLM 适配（reqwest 实现）</h2><ul><li>协议：OpenAI Chat Completions 兼容（<code>/v1/chat/completions</code>），支持 <code>base_url</code> 与 <code>api_key</code>；<code>stream=true</code> 增量解析（SSE/分块）。</li><li>tool_calls：解析增量中的 <code>tool_calls</code>，在 finish_reason=tool_calls 事件时进入工具执行分支并继续对话。</li><li>超时/重试：继承 <code>REQUEST_TIMEOUT</code>，实现指数退避（可配置重试次数与 429/5xx 策略）。</li><li>LiteLLM：通过 <code>base_url</code> 适配（OpenAI 兼容模式），不引入额外依赖。</li></ul><h2 id="8.-%E5%8E%9F%E7%94%9F-json-%E5%B7%A5%E5%85%B7%EF%BC%88functions%EF%BC%89" tabindex="-1">8. 原生 JSON 工具（Functions）</h2><ul><li>目录：<code>~/.config/shell_gpt/functions</code>。</li><li>每个工具一个 JSON 文件，示例：<pre><code class="language-json">{  &quot;name&quot;: &quot;execute_shell_command&quot;,  &quot;description&quot;: &quot;Execute a shell command and return stdout/stderr.&quot;,  &quot;parameters&quot;: {    &quot;type&quot;: &quot;object&quot;,    &quot;properties&quot;: {      &quot;cmd&quot;: {&quot;type&quot;: &quot;string&quot;}    },    &quot;required&quot;: [&quot;cmd&quot;]  },  &quot;exec&quot;: {    &quot;program&quot;: &quot;/bin/sh&quot;,    &quot;args_template&quot;: [&quot;-c&quot;, &quot;{{cmd}}&quot;],    &quot;stdin&quot;: false,    &quot;timeout_sec&quot;: 60  }}</code></pre></li><li>约定：<ul><li><code>parameters</code> 使用 JSON Schema（draft-07 近似）供 LLM 工具调用描述。</li><li><code>exec</code> 描述执行方式：<ul><li><code>program</code> 可执行路径；<code>args_template</code> 支持 <code>{{param}}</code> 占位符替换；</li><li>若 <code>stdin=true</code> 则将完整参数 JSON 通过 stdin 传入；</li><li><code>timeout_sec</code> 超时终止并返回非零状态描述。</li></ul></li></ul></li><li>执行与安全：<ul><li>受 <code>OPENAI_USE_FUNCTIONS</code> 总开关控制；<code>SHOW_FUNCTIONS_OUTPUT</code> 控制是否原样回显输出块。</li><li>仅加载 JSON 工具（忽略 .py）；目录白名单限制，禁止递归外部路径。</li></ul></li></ul><h2 id="9.-%E4%BA%A4%E4%BA%92%E4%B8%8E-shell-%E9%9B%86%E6%88%90" tabindex="-1">9. 交互与 Shell 集成</h2><ul><li><code>--shell</code>：生成后进入 <code>[E]xecute / [M]odify / [D]escribe / [A]bort</code>（或 <code>--no-interaction</code> 直出）。</li><li>执行：按 OS/SHELL 构造命令（PowerShell/CMD/bash/zsh），与 Python 逻辑一致。</li><li>REPL：信息提示一致；<code>e/d</code> 特殊指令保留；历史可视化；termimad 渲染（在默认角色与 describe 模式）。</li><li>Shell integration：复用现有注入脚本（bash/zsh），Windows 后续 PowerShell Profile 支持。</li></ul><h2 id="10.-%E6%B5%8B%E8%AF%95%E4%B8%8E%E8%B4%A8%E9%87%8F%E4%BF%9D%E9%9A%9C" tabindex="-1">10. 测试与质量保障</h2><ul><li>单测：<ul><li>参数解析与互斥；消息构造；缓存/会话裁剪；JSON 工具解析与执行（mock 进程）。</li><li>配置加载/合并；OS/SHELL 路径分支。</li></ul></li><li>集成测：<ul><li>模拟 LLM 流（本地 HTTP mock，SSE/分块），校验 Printer 与增量输出。</li></ul></li><li>端到端：<ul><li>覆盖现有 Python 测试场景的等价用例（默认/代码/命令/聊天/REPL/角色/显示聊天等）。</li></ul></li><li>快照：<ul><li>termimad 渲染与文本颜色输出使用 insta 快照。</li></ul></li><li>CI：<ul><li>Linux/macOS/Windows 矩阵；fmt+clippy+test；最小化网络依赖（完全使用本地 mock）。</li></ul></li></ul><h2 id="11.-%E5%8F%91%E5%B8%83%E4%B8%8E%E4%BA%A4%E4%BB%98" tabindex="-1">11. 发布与交付</h2><ul><li>构建：<code>cargo build --release</code>；提供多平台产物（x86_64/aarch64）。</li><li>包装：Homebrew tap、Scoop、AUR、.deb/.rpm（分阶段推进）。</li><li>文档：README 与迁移指南（JSON 工具编写规范、示例库、常见问题）。</li><li>版本：0.x 快速迭代可用；达完全兼容后 1.0。</li></ul><h2 id="12.-%E8%BF%81%E7%A7%BB%E4%B8%8E%E5%85%BC%E5%AE%B9" tabindex="-1">12. 迁移与兼容</h2><ul><li>配置：首次启动检测 <code>.sgptrc</code>，保留现有键并补全缺省；仍优先 ENV。</li><li>角色/会话/缓存：无损继承现有 JSON 文件；路径可配置；结构不变。</li><li>参数与帮助：名称/互斥逻辑一致，帮助文案同步。</li><li>函数生态：新增 JSON 工具方案与脚手架，不再执行旧 .py 函数；提供迁移示例。</li></ul><h2 id="13.-%E9%87%8C%E7%A8%8B%E7%A2%91%E4%B8%8E%E6%97%B6%E9%97%B4%E7%BA%BF%EF%BC%88%E5%BB%BA%E8%AE%AE%EF%BC%89" tabindex="-1">13. 里程碑与时间线（建议）</h2><ul><li>M0 需求冻结与设计评审（0.5 周）<ul><li>产出：该 <a href="http://Plan.md" target="_blank">Plan.md</a> 确认、JSON 工具规范定稿、termimad 主题策略。</li></ul></li><li>M1 CLI 骨架 + 配置加载 + TextPrinter（1 周）<ul><li>clap 参数/互斥/帮助；.sgptrc/env 合并；版本输出；基础颜色输出。</li></ul></li><li>M2 LLM 适配 + 流式打印 + 默认模式（1 周）<ul><li>reqwest SSE/分块解析；DefaultHandler；请求缓存；超时/重试。</li></ul></li><li>M3 Chat/REPL/会话（1 周）<ul><li>ChatSession JSON 存储与裁剪；REPL（多行、e/d）；显示聊天与列表。</li></ul></li><li>M4 Shell/Code/Describe 模式 + 命令执行（1 周）<ul><li>Shell 执行器（多平台）；Describe 走 markdown；Code 模式禁 md。</li></ul></li><li>M5 原生 JSON 工具 V1 + 默认函数安装（1 周）<ul><li>JSON schema 校验、执行器；示例函数库与安装；tool_calls 分支闭环。</li></ul></li><li>M6 termimad 渲染完善 + 测试矩阵 + 打包（1 周）<ul><li>主题映射；端到端与快照；多平台产物。</li></ul></li><li>M7 文档/迁移指南/候选发布（0.5 周）<ul><li>README、示例、已知问题；RC 发版。</li></ul></li><li>总计：6–7 周（部分并行可压缩至 4–5 周）。</li></ul><h2 id="14.-%E9%A3%8E%E9%99%A9%E4%B8%8E%E5%AF%B9%E7%AD%96" tabindex="-1">14. 风险与对策</h2><ul><li>Markdown 实时渲染卡顿：termimad 增量更新；必要时降级静态打印。</li><li>Windows 兼容：尽早纳入 CI；优先验证 PowerShell/CMD 执行路径。</li><li>LLM 兼容差异：对 LiteLLM/OpenAI 细节通过 HTTP mock 收敛；保留可配置字段透传。</li><li>JSON 工具误用与安全：目录白名单；默认关闭执行；超时与返回码处理；输出可选回显。</li></ul><hr /><h3 id="%E9%99%84%EF%BC%9Ajson-%E5%B7%A5%E5%85%B7%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5%EF%BC%88%E7%AE%80%E7%89%88%EF%BC%89" tabindex="-1">附：JSON 工具最佳实践（简版）</h3><ul><li>用最小参数面向任务；参数命名清晰，与模板占位符一致。</li><li>失败时输出结构化错误 JSON（<code>{&quot;error&quot;: {&quot;code&quot;: , &quot;message&quot;: }}</code>），便于 LLM 复述与纠偏。</li><li>避免副作用命令或明确在 description 中警示；必要时让 LLM 先描述再执行。</li></ul>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[写在Cell上线时（二）]]></title>
                <link rel="alternate" type="text/html" href="http://xuzhougeng.com/archives/written-when-the-article-is-published-in-cell-two" />
                <id>tag:http://xuzhougeng.com,2025-08-19:written-when-the-article-is-published-in-cell-two</id>
                <published>2025-08-19T09:51:21+08:00</published>
                <updated>2025-08-19T12:27:22+08:00</updated>
                <author>
                    <name>徐洲更</name>
                    <uri>http://xuzhougeng.com</uri>
                </author>
                <content type="html">
                        <![CDATA[<p>在2024年5月28日那天，是我的第一篇Cell文章《Reciprocal conversion between annual and polycarpic perennial flowering behavior in the Brassicaceae》上线，我写了一篇文章，叫做<a href="http://xuzhougeng.com/archives/written-when-the-article-is-published-in-cell" target="_blank">写在Cell上线时</a>，回忆了工作的心路历程。今天是2025年8月19日，我参与的另一个工作 《 A unified cell atlas of vascular plants reveals cell-type foundational genes and accelerates gene discovery 》也发表在Cell上，如果你感兴趣的时候，在2025年11月1日之前都可以通过 <a href="https://authors.elsevier.com/c/1ldGh_278y-ENw" target="_blank">https://authors.elsevier.com/c/1ldGh_278y-ENw</a> 免费下载到这篇文章。</p><p>在这个文章的立项初期，我是真的很不看好，因为这个跨度太大，很有可能就烂尾了，所以从没有想法要参与这个课题，不过因为跟师弟经常去健身，所以路上，我们也会讨论这个课题的进展，那个时候我的一个最大的想法就是，为啥不先考虑分选下不同的细胞，做个普通转录组分析下？当然后来发现单细胞确实有它的优势，因为你可以接近无偏的获取所有细胞，这样子你就有可能挖掘到你之前想不到的类型。</p><p>当然，这个工作实际上是我在2023年7月1日开始博后接手的课题，在这之前，我的师弟，也就是文章共一第一，博士生薛皓晨，已经跟另外一位博后在这上面做了有2年多了。直到有一天，王老师把我跟师弟拉到办公室说，这个博后需要追逐更大远大的理想，在第一轮博后结束后就会出站，让我们交接下，于是乎这个工作就交到了我的手上，也算是一种机缘巧合了。</p><p>我觉得这个文章能够比较快的，在我接手后的2年内发表，最关键的因素就是我师弟，他是一个极其努力，做事很有规划不拖延，且还聪明的人。你不怕一个人努力，也不怕一个人聪明，你就怕这个人比你聪明的同时还比你努力。当我听到他在读高中的时候，上厕所还在刷题，就想到我自己高中时的状态，就明白自己上不了北大是有原因的。</p><p>在与师弟开展合作后，他立刻就跟我原本的同桌交换了位置，坐在了我的旁边，这极大的提高了我们的合作效率。至少有如下几方面的原因，一方面是我的技术虽然确实可以，但是有些时候会陷入唯技术论，为了学而学，而忘记了学他的目的，师弟就给我了一个目标，相当于有了一个终止条件，另一方面是我这个人“好为人师”，闲的时候就会看看师弟在做什么，然后顺手解决几个问题。 还有一方面是，我们两个人的作息不太一样，有些时候他早上没来的时候，我会顺手把一些他昨晚没跑完的程序给处理完，某种意义上的轮班了。</p><p>还要需要感谢的是我的另外一个师弟，吴泽宇，他也是文章作者之一，他帮忙完善了我们的基于参考转录组的分析流程<a href="https://github.com/zywu2002/optDNTRA" target="_blank">opTDNTRA</a>，毕竟我的精力有限，不可能面面俱到，所以一些探索性的任务就得麻烦他完成。他也是一个非常靠谱的人，基本上我交给他的工作，他会给我一个完整的README文档，甚至还可能给我一份PPT。 最让我印象深刻的是，我之前拜托他帮我收集数据，在他找到的数据中，有一个数据甚至不在文章的摘要中，必须要下载全文才能拿到数据地址，我都不知道他是怎么收集到的，当然他也忘了（笑）。</p><p>文章虽然已经发了，我也确实参与了很多，但我时常在想一个问题，如果这个文章没有我，换个人是不是也行呢？因此，最多要感谢的应该是我的导师王佳伟研究员，在2017年的时候，让我幸运地加入这个课题组，给我了一个非常好的平台，能够跟优秀的人合作。后续还得继续努力啊，毕竟还是缺一篇自己一作一的文章。</p><p>最后感谢我的前女友兼妻子，慧慧的多年陪伴和本文的校对工作。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[ Rust FASTA 读取库性能基准测试]]></title>
                <link rel="alternate" type="text/html" href="http://xuzhougeng.com/archives/performance-benchmarking-of-rust-fasta-reading-libraries" />
                <id>tag:http://xuzhougeng.com,2025-08-14:performance-benchmarking-of-rust-fasta-reading-libraries</id>
                <published>2025-08-14T09:48:57+08:00</published>
                <updated>2025-08-14T10:02:30+08:00</updated>
                <author>
                    <name>徐洲更</name>
                    <uri>http://xuzhougeng.com</uri>
                </author>
                <content type="html">
                        <![CDATA[<blockquote><p>副标题: Rust FASTA性能测试，拼尽全力仍无法战胜爪哥</p></blockquote><p>本文对比了五种不同的 Rust FASTA 文件读取方案的性能表现，包括四个专门的生物信息学库和一个手动解析方案。</p><h2 id="%E6%B5%8B%E8%AF%95%E7%8E%AF%E5%A2%83" tabindex="-1">测试环境</h2><ul><li><strong>平台</strong>: Linux 5.15.167.4-microsoft-standard-WSL2</li><li><strong>编译器</strong>: Rust 1.88.0</li><li><strong>编译优化</strong>: <code>--release</code> 模式</li><li><strong>测试文件</strong>:<ul><li>100MB FASTA 文件 (13,815 序列, 103,417,298 bp)</li><li>1GB FASTA 文件 (141,160 序列, 1,058,853,624 bp)</li></ul></li></ul><h2 id="%E6%B5%8B%E8%AF%95%E7%9A%84%E5%BA%93" tabindex="-1">测试的库</h2><p>本测试包含单线程和多线程两种实现方式。多线程版本采用生产者-消费者模式，读取线程负责解析FASTA记录，统计线程使用Rayon进行并行计算。</p><h3 id="1.-needletail-(v0.5.1)" tabindex="-1">1. needletail (v0.5.1)</h3><p><strong>特点</strong>: 专为高性能序列处理设计的库</p><pre><code class="language-rust">fn count_sequences_needletail(filename: &amp;str) -&gt; (usize, usize) {    let mut seq_count = 0;    let mut total_length = 0;    let mut reader = needletail::parse_fastx_file(filename).unwrap();    while let Some(record) = reader.next() {        let record = record.unwrap();        seq_count += 1;        total_length += record.seq().len();    }    (seq_count, total_length)}</code></pre><p><strong>多线程版本</strong>:</p><pre><code class="language-rust">use crossbeam_channel::{bounded, Receiver, Sender};use rayon::prelude::*;#[derive(Clone)]struct SequenceInfo {    length: usize,}const BATCH_SIZE: usize = 1000;fn count_sequences_needletail_mt(filename: &amp;str) -&gt; (usize, usize) {    let (sender, receiver): (Sender&lt;Vec&lt;SequenceInfo&gt;&gt;, Receiver&lt;Vec&lt;SequenceInfo&gt;&gt;) = bounded(100);    let filename_clone = filename.to_string();    let reader_thread = thread::spawn(move || {        let mut reader = needletail::parse_fastx_file(&amp;filename_clone).unwrap();        let mut batch = Vec::with_capacity(BATCH_SIZE);        while let Some(record) = reader.next() {            let record = record.unwrap();            batch.push(SequenceInfo {                length: record.seq().len(),            });            if batch.len() &gt;= BATCH_SIZE {                if sender.send(batch.clone()).is_err() {                    break;                }                batch.clear();            }        }        if !batch.is_empty() {            let _ = sender.send(batch);        }    });    let mut seq_count = 0;    let mut total_length = 0;    while let Ok(batch) = receiver.recv() {        let (batch_count, batch_length): (usize, usize) = batch            .par_iter()            .map(|seq_info| (1, seq_info.length))            .reduce(|| (0, 0), |a, b| (a.0 + b.0, a.1 + b.1));        seq_count += batch_count;        total_length += batch_length;    }    reader_thread.join().unwrap();    (seq_count, total_length)}</code></pre><h3 id="2.-noodles-fasta-(v0.38.0)" tabindex="-1">2. noodles-fasta (v0.38.0)</h3><p><strong>特点</strong>: noodles 生物信息学工具包的一部分</p><pre><code class="language-rust">use noodles_fasta as fasta;fn count_sequences_noodles_fasta(filename: &amp;str) -&gt; (usize, usize) {    let file = File::open(filename).unwrap();    let mut reader = fasta::Reader::new(BufReader::new(file));    let mut seq_count = 0;    let mut total_length = 0;    for result in reader.records() {        let record = result.unwrap();        seq_count += 1;        total_length += record.sequence().len();    }    (seq_count, total_length)}</code></pre><h3 id="3.-bio-(v1.6.0)" tabindex="-1">3. bio (v1.6.0)</h3><p><strong>特点</strong>: 功能全面的生物信息学库</p><pre><code class="language-rust">fn count_sequences_bio(filename: &amp;str) -&gt; (usize, usize) {    let file = File::open(filename).unwrap();    let reader = bio::io::fasta::Reader::new(file);    let mut seq_count = 0;    let mut total_length = 0;    for record in reader.records() {        let record = record.unwrap();        seq_count += 1;        total_length += record.seq().len();    }    (seq_count, total_length)}</code></pre><h3 id="4.-seq_io-(v0.3.4)" tabindex="-1">4. seq_io (v0.3.4)</h3><p><strong>特点</strong>: 通用序列 I/O 库</p><pre><code class="language-rust">use seq_io::fasta::Record;fn count_sequences_seq_io(filename: &amp;str) -&gt; (usize, usize) {    let file = File::open(filename).unwrap();    let mut reader = seq_io::fasta::Reader::new(file);    let mut seq_count = 0;    let mut total_length = 0;    while let Some(record) = reader.next() {        let record = record.unwrap();        seq_count += 1;        let seq = record.seq();        // 过滤换行符        total_length += seq.iter().filter(|&amp;&amp;b| b != b&#39;\n&#39; &amp;&amp; b != b&#39;\r&#39;).count();    }    (seq_count, total_length)}</code></pre><h3 id="5.-%E6%89%8B%E5%8A%A8%E8%A7%A3%E6%9E%90" tabindex="-1">5. 手动解析</h3><p><strong>特点</strong>: 使用标准库的基础实现</p><pre><code class="language-rust">fn count_sequences_manual(filename: &amp;str) -&gt; (usize, usize) {    let file = File::open(filename).unwrap();    let reader = BufReader::new(file);    let mut seq_count = 0;    let mut total_length = 0;    for line in reader.lines() {        let line = line.unwrap();        if line.starts_with(&#39;&gt;&#39;) {            seq_count += 1;        } else {            total_length += line.len();        }    }    (seq_count, total_length)}</code></pre><h2 id="%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E7%BB%93%E6%9E%9C" tabindex="-1">性能测试结果</h2><h3 id="100mb-%E6%96%87%E4%BB%B6%E6%B5%8B%E8%AF%95%E7%BB%93%E6%9E%9C" tabindex="-1">100MB 文件测试结果</h3><h4 id="%E5%8D%95%E7%BA%BF%E7%A8%8B%E6%80%A7%E8%83%BD" tabindex="-1">单线程性能</h4><table><thead><tr><th>库名称</th><th>平均时间</th><th>Criterion 基准</th><th>性能排名</th></tr></thead><tbody><tr><td>needletail</td><td>~36ms</td><td>34.1-37.5ms</td><td>🥇 1</td></tr><tr><td>noodles_fasta</td><td>~51ms</td><td>47.5-54.2ms</td><td>🥈 2</td></tr><tr><td>seq_io</td><td>~66ms</td><td>62.2-69.9ms</td><td>🥉 3</td></tr><tr><td>bio</td><td>~70ms</td><td>64.5-75.9ms</td><td>4</td></tr><tr><td>manual</td><td>~83ms</td><td>76.0-90.1ms</td><td>5</td></tr></tbody></table><h4 id="%E5%A4%9A%E7%BA%BF%E7%A8%8B%E6%80%A7%E8%83%BD" tabindex="-1">多线程性能</h4><table><thead><tr><th>库名称</th><th>平均时间</th><th>Criterion 基准</th><th>性能提升</th></tr></thead><tbody><tr><td>needletail_mt</td><td>~32ms</td><td>31.7-32.2ms</td><td>🚀 +12%</td></tr><tr><td>noodles_fasta_mt</td><td>~51ms</td><td>50.2-51.4ms</td><td>≈ 0%</td></tr></tbody></table><h3 id="1gb-%E6%96%87%E4%BB%B6%E6%B5%8B%E8%AF%95%E7%BB%93%E6%9E%9C" tabindex="-1">1GB 文件测试结果</h3><h4 id="%E5%8D%95%E7%BA%BF%E7%A8%8B%E6%80%A7%E8%83%BD-1" tabindex="-1">单线程性能</h4><table><thead><tr><th>库名称</th><th>平均时间</th><th>扩展性</th><th>性能排名</th></tr></thead><tbody><tr><td>needletail</td><td>~382ms</td><td>10.6倍</td><td>🥇 1</td></tr><tr><td>noodles_fasta</td><td>~468ms</td><td>9.2倍</td><td>🥈 2</td></tr><tr><td>seq_io</td><td>~717ms</td><td>10.9倍</td><td>🥉 3</td></tr><tr><td>manual</td><td>~778ms</td><td>9.4倍</td><td>4</td></tr><tr><td>bio</td><td>~2370ms</td><td>33.9倍</td><td>5</td></tr></tbody></table><h4 id="%E5%A4%9A%E7%BA%BF%E7%A8%8B%E6%80%A7%E8%83%BD-1" tabindex="-1">多线程性能</h4><table><thead><tr><th>库名称</th><th>平均时间</th><th>性能提升</th><th>排名</th></tr></thead><tbody><tr><td>needletail_mt</td><td>~371ms</td><td>🚀 +3%</td><td>🥇 1</td></tr><tr><td>noodles_fasta_mt</td><td>~514ms</td><td>⚠️ -10%</td><td>🥈 2</td></tr></tbody></table><h3 id="%E4%B8%8E-seqkit-%E5%AF%B9%E6%AF%94" tabindex="-1">与 seqkit 对比</h3><p>seqkit 是 Go 语言编写的流行生物信息学工具：</p><ul><li><strong>100MB 文件</strong>: ~250ms (包含启动开销)</li><li><strong>1GB 文件</strong>: ~326ms (包含启动开销)</li><li><strong>CPU 时间</strong>: 与 needletail 性能相当</li></ul><h2 id="%E6%80%A7%E8%83%BD%E5%88%86%E6%9E%90" tabindex="-1">性能分析</h2><h3 id="%E5%A4%9A%E7%BA%BF%E7%A8%8B%E8%AE%BE%E8%AE%A1%E8%AF%B4%E6%98%8E" tabindex="-1">多线程设计说明</h3><p>多线程版本采用生产者-消费者模式：</p><ul><li><strong>读取线程</strong>: 负责解析FASTA文件，将序列信息批量发送到channel</li><li><strong>统计线程</strong>: 使用Rayon并行处理批次数据，计算序列数量和长度</li><li><strong>批次大小</strong>: 1000个序列为一批，平衡内存使用和并行效率</li><li><strong>Channel缓冲</strong>: 100个批次的缓冲区，避免生产者阻塞</li></ul><h3 id="%E5%A4%9A%E7%BA%BF%E7%A8%8B%E6%80%A7%E8%83%BD%E5%88%86%E6%9E%90" tabindex="-1">多线程性能分析</h3><h4 id="%E6%80%A7%E8%83%BD%E6%8F%90%E5%8D%87%E6%83%85%E5%86%B5%EF%BC%9A" tabindex="-1">性能提升情况：</h4><ol><li><strong>needletail_mt</strong>: 在100MB文件上有12%的性能提升，1GB文件上有3%的提升</li><li><strong>noodles_fasta_mt</strong>: 在小文件上无明显提升，大文件上性能略有下降</li></ol><h4 id="%E5%A4%9A%E7%BA%BF%E7%A8%8B%E6%95%88%E6%9E%9C%E6%9C%89%E9%99%90%E7%9A%84%E5%8E%9F%E5%9B%A0%EF%BC%9A" tabindex="-1">多线程效果有限的原因：</h4><ol><li><strong>I/O绑定</strong>: FASTA解析主要受磁盘I/O限制，CPU并行化收益有限</li><li><strong>顺序读取</strong>: 文件必须顺序读取，无法并行化最耗时的解析步骤</li><li><strong>通信开销</strong>: 跨线程数据传输的开销抵消了部分并行收益</li><li><strong>简单统计</strong>: 长度统计计算量较小，并行化收益不明显</li></ol><h4 id="%E5%A4%9A%E7%BA%BF%E7%A8%8B%E9%80%82%E7%94%A8%E5%9C%BA%E6%99%AF%EF%BC%9A" tabindex="-1">多线程适用场景：</h4><ul><li>复杂的序列处理算法（如质量控制、序列比对）</li><li>需要对序列内容进行密集计算的任务</li><li>处理多个文件的批量操作</li></ul><h3 id="1.-needletail" tabindex="-1">1. needletail</h3><ul><li><strong>优势</strong>: 性能最佳，专为高性能设计，在大文件处理中扩展性最好</li><li><strong>适用场景</strong>: 需要极致性能的大规模数据处理</li><li><strong>API</strong>: 简洁直观，支持多种序列格式</li></ul><h3 id="2.-noodles_fasta" tabindex="-1">2. noodles_fasta</h3><ul><li><strong>优势</strong>: 性能优秀，API 设计良好，扩展性好</li><li><strong>适用场景</strong>: 平衡性能和功能的选择</li><li><strong>特点</strong>: noodles 生态系统的一部分，与其他格式库兼容性好</li></ul><h3 id="3.-bio" tabindex="-1">3. bio</h3><ul><li><strong>优势</strong>: 功能全面，生态系统成熟</li><li><strong>适用场景</strong>: 需要多种生物信息学功能的项目</li><li><strong>性能</strong>: 中等，但稳定可靠</li></ul><h3 id="4.-seq_io" tabindex="-1">4. seq_io</h3><ul><li><strong>优势</strong>: 通用性好，支持多种格式</li><li><strong>劣势</strong>: 在大文件处理中性能下降明显</li><li><strong>适用场景</strong>: 中小型文件处理</li></ul><h3 id="5.-%E6%89%8B%E5%8A%A8%E8%A7%A3%E6%9E%90-1" tabindex="-1">5. 手动解析</h3><ul><li><strong>优势</strong>: 无额外依赖，简单可控</li><li><strong>劣势</strong>: 功能有限，性能一般</li><li><strong>适用场景</strong>: 简单的统计任务</li></ul><h2 id="%E5%9F%BA%E5%87%86%E6%B5%8B%E8%AF%95%E4%BB%A3%E7%A0%81" tabindex="-1">基准测试代码</h2><p>完整的基准测试项目包含以下文件：</p><pre><code class="language-toml"># Cargo.toml[dependencies]bio = &quot;1.6&quot;needletail = &quot;0.5&quot;seq_io = &quot;0.3&quot;noodles-fasta = &quot;0.38&quot;criterion = &quot;0.5&quot;crossbeam-channel = &quot;0.5&quot;  # 用于多线程通信rayon = &quot;1.11&quot;             # 用于并行计算[[bench]]name = &quot;fasta_bench&quot;harness = false</code></pre><p>使用 criterion 进行精确的基准测试：</p><pre><code class="language-rust">use criterion::{black_box, criterion_group, criterion_main, Criterion};fn benchmark_fasta_readers(c: &amp;mut Criterion) {    let test_file = &quot;../test.fasta&quot;;    c.bench_function(&quot;needletail&quot;, |b| {        b.iter(|| count_sequences_needletail(black_box(test_file)))    });    c.bench_function(&quot;noodles_fasta&quot;, |b| {        b.iter(|| count_sequences_noodles_fasta(black_box(test_file)))    });    c.bench_function(&quot;bio&quot;, |b| {        b.iter(|| count_sequences_bio(black_box(test_file)))    });    c.bench_function(&quot;seq_io&quot;, |b| {        b.iter(|| count_sequences_seq_io(black_box(test_file)))    });    c.bench_function(&quot;manual&quot;, |b| {        b.iter(|| count_sequences_manual(black_box(test_file)))    });    // 多线程基准测试    c.bench_function(&quot;needletail_mt&quot;, |b| {        b.iter(|| count_sequences_needletail_mt(black_box(test_file)))    });    c.bench_function(&quot;noodles_fasta_mt&quot;, |b| {        b.iter(|| count_sequences_noodles_fasta_mt(black_box(test_file)))    });}criterion_group!(benches, benchmark_fasta_readers);criterion_main!(benches);</code></pre><h2 id="%E8%BF%90%E8%A1%8C%E5%9F%BA%E5%87%86%E6%B5%8B%E8%AF%95" tabindex="-1">运行基准测试</h2><pre><code class="language-bash"># 编译cargo build --release# 运行简单测试./target/release/fasta_benchmark test.fasta# 运行详细基准测试cargo bench</code></pre><h2 id="%E7%BB%93%E8%AE%BA%E5%92%8C%E5%BB%BA%E8%AE%AE" tabindex="-1">结论和建议</h2><h3 id="%E5%8D%95%E7%BA%BF%E7%A8%8B%E5%9C%BA%E6%99%AF" tabindex="-1">单线程场景</h3><h4 id="%E6%80%A7%E8%83%BD%E4%BC%98%E5%85%88" tabindex="-1">性能优先</h4><ul><li><strong>首选</strong>: needletail - 在所有测试中表现最佳</li><li><strong>次选</strong>: noodles_fasta - 性能优秀且 API 友好</li></ul><h4 id="%E5%8A%9F%E8%83%BD%E5%B9%B3%E8%A1%A1" tabindex="-1">功能平衡</h4><ul><li><strong>推荐</strong>: bio - 功能全面，生态系统成熟</li><li><strong>备选</strong>: noodles_fasta - 现代化设计，性能优秀</li></ul><h4 id="%E8%BD%BB%E9%87%8F%E7%BA%A7%E9%9C%80%E6%B1%82" tabindex="-1">轻量级需求</h4><ul><li><strong>选择</strong>: 手动解析 - 无额外依赖，适合简单任务</li></ul><h3 id="%E5%A4%9A%E7%BA%BF%E7%A8%8B%E5%9C%BA%E6%99%AF" tabindex="-1">多线程场景</h3><h4 id="%E4%BD%95%E6%97%B6%E4%BD%BF%E7%94%A8%E5%A4%9A%E7%BA%BF%E7%A8%8B" tabindex="-1">何时使用多线程</h4><ul><li><strong>推荐场景</strong>: 复杂的序列计算任务（质量评估、序列比对等）</li><li><strong>不推荐场景</strong>: 简单的统计任务（如本测试的长度统计）</li></ul><h4 id="%E5%A4%9A%E7%BA%BF%E7%A8%8B%E5%BA%93%E9%80%89%E6%8B%A9" tabindex="-1">多线程库选择</h4><ul><li><strong>needletail_mt</strong>: 小幅性能提升，适合CPU密集型后处理</li><li><strong>noodles_fasta_mt</strong>: 性能提升有限，更适合单线程使用</li></ul><h3 id="%E6%96%87%E4%BB%B6%E5%A4%A7%E5%B0%8F%E5%BB%BA%E8%AE%AE" tabindex="-1">文件大小建议</h3><h4 id="%E5%B0%8F%E6%96%87%E4%BB%B6-(%3C-100mb)" tabindex="-1">小文件 (&lt; 100MB)</h4><ul><li>单线程已足够，推荐 needletail 或 noodles_fasta</li></ul><h4 id="%E5%A4%A7%E6%96%87%E4%BB%B6-(%3E-1gb)" tabindex="-1">大文件 (&gt; 1GB)</h4><ul><li><strong>必选</strong>: needletail - 扩展性最好</li><li><strong>备选</strong>: noodles_fasta - 性能稳定</li><li>考虑多线程版本仅当有复杂计算需求时</li></ul><h3 id="%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1%E5%BB%BA%E8%AE%AE" tabindex="-1">架构设计建议</h3><p>对于生产环境的大规模FASTA处理：</p><ol><li><strong>I/O优化</strong>: 使用SSD存储，考虑内存映射文件</li><li><strong>批处理</strong>: 将多个小文件合并处理，减少I/O开销</li><li><strong>流水线设计</strong>: 分离读取、解析和计算阶段</li><li><strong>内存管理</strong>: 对于超大文件，考虑流式处理而非全量加载</li></ol><p>所有库都能正确解析 FASTA 格式并产生一致的结果。选择主要取决于性能需求、并发需求和功能要求的平衡。对于大多数生物信息学应用，needletail 仍是最佳选择，多线程版本适用于有额外计算需求的场景。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[多个gz文件一定要先分别解压缩再合并才能压缩吗？]]></title>
                <link rel="alternate" type="text/html" href="http://xuzhougeng.com/archives/must-decompress-gz-files-before-recompressingsourcesaskchatgpt" />
                <id>tag:http://xuzhougeng.com,2025-08-01:must-decompress-gz-files-before-recompressingsourcesaskchatgpt</id>
                <published>2025-08-01T21:13:01+08:00</published>
                <updated>2025-08-01T21:13:01+08:00</updated>
                <author>
                    <name>徐洲更</name>
                    <uri>http://xuzhougeng.com</uri>
                </author>
                <content type="html">
                        <![CDATA[<blockquote><p>先说答案，<strong>并不一定</strong>。绝大多数场景里，你完全可以直接把几个 <code>.gz</code> 文件用 <code>cat</code> 拼在一起，生成一个合法的 <em>multi-member</em> gzip 流，gunzip 等工具解压时会自动把它们当成一个整体顺序解出；既省时间，也省硬盘 I/O。</p></blockquote><p>首先，让我们知道什么叫 <em>multi-member</em>。 在 RFC 1952 的定义里，一个 gzip <strong>文件其实可以由若干个完整的 “member” 串联而成</strong>。每个 member 自带头、数据块和尾 CRC，因此把多个 member 直接按字节级拼接也依旧合法——解析器读完第一个尾部后，继续顺着流读下去就是下一段数据([<a href="http://rfc-editor.org" target="_blank">rfc-editor.org</a>][1])。</p><pre><code class="language-"># demoecho alpha | gzip &gt; a.gz      # member 1echo beta  | gzip &gt; b.gz      # member 2cat a.gz b.gz &gt; ab_multi.gz   # 合并gunzip -c ab_multi.gz         # 输出 alpha 和 beta</code></pre><p>知道这个知识点后，当你有一个样本，加测好多次的时候后，就不需要用下面的操作</p><pre><code class="language-bash">pigz -dc part1.gz part2.gz part3.gz | pigz &gt; all.gz</code></pre><p>而是直接用cat合并</p><pre><code class="language-bash">cat part1.gz part2.gz part3.gz &gt; all.gz</code></pre><p>后续用gzip或者pigz都是可以顺利解压缩的。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[Hi-C估算分辨率]]></title>
                <link rel="alternate" type="text/html" href="http://xuzhougeng.com/archives/hi-c-estimation-resolution" />
                <id>tag:http://xuzhougeng.com,2025-07-27:hi-c-estimation-resolution</id>
                <published>2025-07-27T15:41:36+08:00</published>
                <updated>2025-09-06T20:40:17+08:00</updated>
                <author>
                    <name>徐洲更</name>
                    <uri>http://xuzhougeng.com</uri>
                </author>
                <content type="html">
                        <![CDATA[<p>Hi-C数据的分辨率（resolution）通常指接触矩阵（contact matrix）的bin大小（如1kb、5kb或10kb），分辨率的高低决定了下游可以做哪些分析。</p><table><thead><tr><th>分辨率范围</th><th>典型分析</th><th>应用研究问题</th></tr></thead><tbody><tr><td>1kb–10kb</td><td>染色质环、<strong>增强子-启动子</strong>互作</td><td>基因精细调控、非编码区域功能</td></tr><tr><td>25kb–100kb</td><td>TAD结构、A/B区室</td><td>染色质结构与表达、疾病状态比较</td></tr><tr><td>100kb–500kb</td><td>染色质区室全局特征</td><td>全基因组结构比较、发育差异</td></tr><tr><td>500kb–2Mb</td><td>染色体区域互作、染色体领地</td><td>核内染色体排布、进化差异</td></tr></tbody></table><p>Hi-C数据有效分辨率定义为，最小的bin大小，其中大部分（通常80%）基因组bin具有足够的接触数（contacts），比如说至少1000个unique contacts，<strong>以确保矩阵不稀疏</strong>。 （<strong>Rao et al., 2014, Cell</strong>）。Hi-C数据的分辨率由测序reads的数量决定，reads越多，能支持的分辨率越高（bin大小越小。</p><p>使用人类数据SRR1658573进行测试</p><blockquote><p>注: <a href="https://github.com/ClaireMarchal/HiCRes" target="_blank">https://github.com/ClaireMarchal/HiCRes</a> 预测结果24744  bp</p></blockquote><p>使用Juicer进行数据预处理，首先构建索引</p><pre><code class="language-Python">python ~/software/juicer-1.6/misc/generate_site_positions.py DpnII GRCh38 GRCh38.genome.fastabwa index GRCh38.genome.fastaseqkit faidx GRCh38.genome.fastacut -f 1,2 GRCh38.genome.fasta.fai &gt; GRCh38.chrom.size</code></pre><p>接着处理数据(要求档期那目录下有fastq目录）</p><pre><code class="language-Bash">~/software/juicer-1.6/scripts/juicer.sh \  -g GRCh38 \  -s DpnII \  -z ./reference/GRCh38.genome.fasta \  -y ./reference/GRCh38_DpnII.txt \  -p ./reference/GRCh38.chrom.size \  -D ~/software/juicer-1.6 \  -t 40 &amp;&gt; juicer.log </code></pre><p>方法1: 参考Juicer提供了一个脚本用于估计分辨率，也就是<code>juicer-1.6/misc/calculate_map_resolution.sh</code>，脚本先算 50 bp 端点覆盖，再用二分法找到“让 ≥ 80 % 的基因组 bin 都累积到 ≥ 1 000 条接触”的最小 bin 大小；这个尺寸就是 Hi‑C 数据能可靠解析的图谱分辨率。 运行所需32分钟，估算是17.8K的分辨率，对应25K分辨率的矩阵。</p><pre><code class="language-Markdown">time bash ~/software/juicer-1.6/misc/calculate_map_resolution.sh merged_nodups.txt cov50.txt# The map resolution is 17800# 1438.80s user 39.90s system 76% cpu 32:15.42 total</code></pre><p>方法2：直接用juicer输出给的hic矩阵里分析，看看不同分辨率下的矩阵是否满足需求。</p><pre><code class="language-Python">#!/usr/bin/env python# -*- coding: utf-8 -*-&quot;&quot;&quot;pip install -i https://pypi.org/simple/ hic-strawEstimate effective Hi-C resolution per chromosome.Usage:    python calc_hic_resolution.py &lt;hic_file&gt; &lt;chromosome&gt; [--thr 1000] [--pct 0.8]&quot;&quot;&quot;import argparseimport sysfrom hicstraw import HiCFile, strawimport numpy as np# ----------------------------------------------------------------------# Helper# ----------------------------------------------------------------------def find_matching_chr(requested, available):    &quot;&quot;&quot;在 available 里寻找与 requested 对应的染色体名称（大小写 / chr 前缀不敏感）。&quot;&quot;&quot;    req = requested.lower().lstrip(&quot;chr&quot;)    for name in available:        if name.lower() == requested.lower() or name.lower().lstrip(&quot;chr&quot;) == req:            return name    return Nonedef coverage_at_bin(hic_path, chrom, res, thr):    &quot;&quot;&quot;计算给定染色体 &amp; bin size 时，≥thr contacts 的 bin 占比。&quot;&quot;&quot;    records = straw(&quot;observed&quot;, &quot;NONE&quot;, hic_path, chrom, chrom, &quot;BP&quot;, res)    counts = {}    for rec in records:                               # contactRecord 对象        counts[rec.binX] = counts.get(rec.binX, 0) + rec.counts        counts[rec.binY] = counts.get(rec.binY, 0) + rec.counts    arr = np.fromiter(counts.values(), dtype=np.int64)    return (arr &gt;= thr).mean() if arr.size else 0.0# ----------------------------------------------------------------------# Main# ----------------------------------------------------------------------def main():    parser = argparse.ArgumentParser(        description=&quot;Estimate Hi-C effective resolution on a given chromosome&quot;,        formatter_class=argparse.ArgumentDefaultsHelpFormatter)    parser.add_argument(&quot;hic_file&quot;, help=&quot;.hic file produced by Juicer/HiC-Pro&quot;)    parser.add_argument(&quot;chromosome&quot;, help=&quot;Chromosome name, e.g. 1 / chr1 / X&quot;)    parser.add_argument(&quot;--thr&quot;, type=int, default=1000,                        help=&quot;Minimum contacts per bin to count as covered&quot;)    parser.add_argument(&quot;--pct&quot;, type=float, default=0.8,                        help=&quot;Coverage fraction defining effective resolution (0–1)&quot;)    args = parser.parse_args()    # 打开 .hic 文件并解析元数据    hic = HiCFile(args.hic_file)    chroms = [c.name for c in hic.getChromosomes() if c.name.lower() != &quot;all&quot;]    chrom = find_matching_chr(args.chromosome, chroms)    if chrom is None:        sys.stderr.write(            f&quot;[ERROR] 未找到染色体 &#39;{args.chromosome}&#39;，&quot;            f&quot;可选值: {&#39;, &#39;.join(chroms)}\n&quot;)        sys.exit(1)    print(f&quot;# File: {args.hic_file}&quot;)    print(f&quot;# Chromosome: {chrom}&quot;)    print(f&quot;# Threshold per bin: {args.thr} contacts&quot;)    print(f&quot;# Required coverage: {args.pct*100:.1f}% bins\n&quot;)    print(&quot;resolution_bp\tcoverage&quot;)    resolutions = sorted(hic.getResolutions())    eff_res = None    for res in resolutions:        cov = coverage_at_bin(args.hic_file, chrom, res, args.thr)        print(f&quot;{res}\t{cov:.3f}&quot;)        if eff_res is None and cov &gt;= args.pct:            eff_res = res    if eff_res:        print(f&quot;\nEffective resolution on {chrom}: {eff_res:,} bp &quot;              f&quot;(≥{args.pct*100:.0f}% bins ≥ {args.thr} contacts)&quot;)    else:        print(f&quot;\nNo resolution met the {args.pct*100:.0f}% / {args.thr} contacts criterion.&quot;)if __name__ == &quot;__main__&quot;:    main()</code></pre><p>结可以发现，10K太高，25K挺好的</p><pre><code class="language-Markdown">    5000        0.000   10000        0.219   25000        0.940   50000        0.963  100000        0.975  250000        0.991  500000        0.993 1000000        0.996 2500000        1.000</code></pre><p>此外，我用Rust在AI的协助下，也实现了上面两个方法，见 <a href="https://github.com/xuzhougeng/hickit_rs" target="_blank">https://github.com/xuzhougeng/hickit_rs</a>，速度可以快5到10倍左右。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[Hi-C 数据分析的类型概述]]></title>
                <link rel="alternate" type="text/html" href="http://xuzhougeng.com/archives/overview-of-hi-c-data-analysis-types" />
                <id>tag:http://xuzhougeng.com,2025-07-24:overview-of-hi-c-data-analysis-types</id>
                <published>2025-07-24T21:01:57+08:00</published>
                <updated>2025-07-24T21:01:57+08:00</updated>
                <author>
                    <name>徐洲更</name>
                    <uri>http://xuzhougeng.com</uri>
                </author>
                <content type="html">
                        <![CDATA[<blockquote><p>文章内容由Grok4生成，我负责检查、编辑和发表。</p></blockquote><p>Hi-C（High-throughput Chromosome Conformation Capture）是一种用于研究染色质3D结构的组学技术，它生成的接触矩阵数据可以揭示基因组的拓扑结构、调控机制和疾病相关变化。Hi-C数据分析通常涉及从原始读段到高级解读的完整管道，不限于特定工具（如HiCExplorer、Juicer、HiC-Pro、TADbit、Fit-Hi-C 或 HiC-bench）。分析类型可以分为基础处理、高级结构识别、比较分析和整合应用等。下面我按类别总结常见分析类型，包括描述、目的和示例工具/方法。列表基于多种来源的综合，如Hi-C管道指南和基准研究。</p><h2 id="1.-%E9%A2%84%E5%A4%84%E7%90%86%E5%92%8C%E8%B4%A8%E9%87%8F%E6%8E%A7%E5%88%B6%EF%BC%88preprocessing-and-quality-control%EF%BC%89" tabindex="-1">1. <strong>预处理和质量控制（Preprocessing and Quality Control）</strong></h2><ul><li><strong>描述</strong>：从原始测序读段开始，包括过滤低质量读段、去除PCR重复、比对到参考基因组、构建接触矩阵（contact matrix，通常以bin大小如5kb划分）。</li><li><strong>目的</strong>：确保数据可靠，移除技术偏差（如酶切位点偏差）。包括检查cis/trans交互比率、距离依赖交互频率衰减曲线。</li><li><strong>示例工具/方法</strong>：HiC-Pro（端到端处理）、cooler（矩阵格式化）、HiC-bench（对齐和过滤）。常见步骤：使用Bowtie2或BWA比对，生成.cool或.hic格式矩阵。</li></ul><h2 id="2.-%E7%9F%A9%E9%98%B5%E6%A0%A1%E6%AD%A3%E5%92%8C%E5%BD%92%E4%B8%80%E5%8C%96%EF%BC%88matrix-correction-and-normalization%EF%BC%89" tabindex="-1">2. <strong>矩阵校正和归一化（Matrix Correction and Normalization）</strong></h2><ul><li><strong>描述</strong>：校正系统偏差（如GC含量、mappability），包括显式（explicit，如Knight-Ruiz (KR)）和隐式（implicit，如ICE）方法。归一化使矩阵可比，如总互动数标准化。</li><li><strong>目的</strong>：去除噪声，提高下游分析准确性。包括诊断绘图（如MAD score）。</li><li><strong>示例工具/方法</strong>：HiCExplorer的hicCorrectMatrix、Juicer的KR normalization、cooltools。</li></ul><h2 id="3.-%E5%8F%AF%E8%A7%86%E5%8C%96%E5%92%8C%E6%8E%A2%E7%B4%A2%E6%80%A7%E5%88%86%E6%9E%90%EF%BC%88visualization-and-exploratory-analysis%EF%BC%89" tabindex="-1">3. <strong>可视化和探索性分析（Visualization and Exploratory Analysis）</strong></h2><ul><li><strong>描述</strong>：生成热图（heatmap）、圆图（circos plot）、距离 vs 计数曲线、虚拟4C（从特定视点查看互动）。</li><li><strong>目的</strong>：直观检查数据模式，如交互频率随距离衰减。</li><li><strong>示例工具/方法</strong>：Juicebox（交互式热图）、HiCExplorer的hicPlotMatrix、WashU Epigenome Browser。</li></ul><h2 id="4.-a%2Fb-%E9%9A%94%E5%AE%A4%E5%88%86%E6%9E%90%EF%BC%88a%2Fb-compartment-analysis%EF%BC%89" tabindex="-1">4. <strong>A/B 隔室分析（A/B Compartment Analysis）</strong></h2><ul><li><strong>描述</strong>：使用主成分分析（PCA）识别开放（A，活跃转录）和封闭（B，抑制）染色质隔室。计算PC1值作为隔室分数。</li><li><strong>目的</strong>：揭示染色质大尺度分区，与基因表达相关。</li><li><strong>示例工具/方法</strong>：HiCExplorer的hicPCA、cooltools的compartment调用、HOMER。</li></ul><h2 id="5.-%E6%8B%93%E6%89%91%E7%9B%B8%E5%85%B3%E5%9F%9F%EF%BC%88tad%EF%BC%89%E8%AF%86%E5%88%AB%EF%BC%88topologically-associating-domains-identification%EF%BC%89" tabindex="-1">5. <strong>拓扑相关域（TAD）识别（Topologically Associating Domains Identification）</strong></h2><ul><li><strong>描述</strong>：检测TAD边界和域，使用insulation score或方向性指数（directionality index）。</li><li><strong>目的</strong>：识别局部互动密集区域，理解基因调控边界。</li><li><strong>示例工具/方法</strong>：Arrowhead (Juicer)、HiCExplorer的hicFindTADs、TADbit。</li></ul><h2 id="6.-%E6%9F%93%E8%89%B2%E8%B4%A8%E7%8E%AF%E6%A3%80%E6%B5%8B%EF%BC%88chromatin-loop-detection%EF%BC%89" tabindex="-1">6. <strong>染色质环检测（Chromatin Loop Detection）</strong></h2><ul><li><strong>描述</strong>：识别远距离互动峰，如增强子-启动子环，使用峰调用算法（如负二项分布或Wilcoxon测试）。</li><li><strong>目的</strong>：揭示调控环，与转录因子如CTCF相关。</li><li><strong>示例工具/方法</strong>：HiCCUPS (Juicer)、HiCExplorer的hicDetectLoops、Fit-Hi-C。</li></ul><h2 id="7.-%E5%B7%AE%E5%BC%82hi-c%E5%88%86%E6%9E%90%EF%BC%88differential-hi-c-analysis%EF%BC%89" tabindex="-1">7. <strong>差异Hi-C分析（Differential Hi-C Analysis）</strong></h2><ul><li><strong>描述</strong>：比较多个样本的矩阵差异，如log2比率、显著差异互动，使用统计测试（如负二项或t-test）。</li><li><strong>目的</strong>：识别条件特异结构变化（如疾病 vs 正常）。</li><li><strong>示例工具/方法</strong>：HiCompare、diffHiC、multiHiCcompare（基准了10种工具）。</li></ul><h2 id="8.-%E8%81%9A%E5%90%88%E5%92%8C%E5%8C%BA%E5%9F%9F%E7%89%B9%E5%BC%82%E5%88%86%E6%9E%90%EF%BC%88aggregation-and-region-specific-analysis%EF%BC%89" tabindex="-1">8. <strong>聚合和区域特异分析（Aggregation and Region-Specific Analysis）</strong></h2><ul><li><strong>描述</strong>：在特定特征（如CTCF位点）周围聚合互动，生成平均图；或网络分析（interaction network）。</li><li><strong>目的</strong>：研究模式如TAD边界富集。</li><li><strong>示例工具/方法</strong>：HiCExplorer的hicAggregateContacts、GraphPad或网络工具。</li></ul><h2 id="9.-3d%E5%9F%BA%E5%9B%A0%E7%BB%84%E5%BB%BA%E6%A8%A1%EF%BC%883d-genome-modeling%EF%BC%89" tabindex="-1">9. <strong>3D基因组建模（3D Genome Modeling）</strong></h2><ul><li><strong>描述</strong>：从接触矩阵推断染色质3D结构，使用分子动力学或优化算法。</li><li><strong>目的</strong>：模拟空间构象。</li><li><strong>示例工具/方法</strong>：TADbit的建模模块、miniMDS、Chrom3D。</li></ul><h2 id="10.-%E5%8D%95%E7%BB%86%E8%83%9Ehi-c%E5%88%86%E6%9E%90%EF%BC%88single-cell-hi-c-analysis%EF%BC%89" tabindex="-1">10. <strong>单细胞Hi-C分析（Single-Cell Hi-C Analysis）</strong></h2><ul><li><strong>描述</strong>：处理稀疏单细胞数据，包括 imputation、聚类、轨迹分析。</li><li><strong>目的</strong>：揭示细胞异质性。</li><li><strong>示例工具/方法</strong>：scHiCExplorer、SnapHiC、Higashi。</li></ul><h2 id="11.-%E9%AB%98%E7%BA%A7%E5%92%8C%E6%95%B4%E5%90%88%E5%88%86%E6%9E%90%EF%BC%88advanced-and-integrative-analysis%EF%BC%89" tabindex="-1">11. <strong>高级和整合分析（Advanced and Integrative Analysis）</strong></h2><ul><li><strong>描述</strong>：应用机器学习/AI（如聚类、预测）、图论（网络建模）、时空分析；整合多组学数据（如ChIP-seq、RNA-seq、ATAC-seq）。</li><li><strong>目的</strong>：揭示调控网络、癌症相关变化。</li><li><strong>示例工具/方法</strong>：DeepHiC（AI增强）、网络分析工具、ENCODE管道。</li></ul><p>这些分析通常形成管道，从预处理到高级解读。选择取决于分辨率、样本类型和计算资源。对于癌症等应用，Hi-C常与多组学整合。</p>]]>
                </content>
            </entry>
</feed>
