<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>https://lycaonide.github.io/</id>
  <title type="text">lycaonide 的博客</title>
  <subtitle type="text">技术记录 · 学习笔记</subtitle>
  <updated>2026-09-11T00:00:00.000Z</updated>
  <author><name>lycaonide</name></author>
  <link rel="alternate" href="https://lycaonide.github.io/"/>
  <link rel="self" href="https://lycaonide.github.io/atom.xml"/>
  <generator uri="https://github.com/CuteLeaf/Firefly">Firefly v6.16.8</generator>
    <entry>
      <id>https://lycaonide.github.io/posts/%E4%BB%8Ehexo%E8%BF%81%E7%A7%BB%E5%88%B0astro%E9%83%A8%E7%BD%B2%E8%AE%B0%E5%BD%95/</id>
      <title type="text">从Hexo迁移到Astro部署记录</title>
      <published>2026-09-11T00:00:00.000Z</published>
      <updated>2026-09-11T00:00:00.000Z</updated>
      <author><name>lycaonide</name></author>
      <link rel="alternate" href="https://lycaonide.github.io/posts/%E4%BB%8Ehexo%E8%BF%81%E7%A7%BB%E5%88%B0astro%E9%83%A8%E7%BD%B2%E8%AE%B0%E5%BD%95/"/>
      <summary type="text">记录本站从 Hexo 迁移到 Astro 的全过程：技术选型、双站并存、字体本地化、站点美化、Giscus 评论接入、GitHub Actions 自动部署与 Cloudflare Pages 国内加速。</summary>
      <content type="html"><![CDATA[<section><h4>一、为什么从 Hexo 迁移到 Astro<a href="#一为什么从-hexo-迁移到-astro"><span>#</span></a></h4><p>原来这个博客是用 <strong>Hexo</strong> 搭的（另一篇《学习用Hexo写博客》记录了完整过程），部署在 GitHub Pages 上，用起来没问题。但用久了有几个痛点：</p><ul>
<li><strong>主题老旧</strong>：Hexo 生态里好看的现代主题不多，定制麻烦；</li>
<li><strong>性能一般</strong>：页面是整站生成，JS 和 CSS 越来越重；</li>
<li><strong>想折腾</strong>：Astro 是当下内容站的主流方案，静态输出、组件化、生态活跃。</li>
</ul><p>最终选型：</p>

<table><thead><tr><th>项目</th><th>选择</th><th>理由</th></tr></thead><tbody><tr><td>框架</td><td>Astro 7</td><td>内容驱动、默认零 JS、构建快</td></tr><tr><td>主题</td><td>Firefly</td><td>基于 Fuwari 二次开发，二次元风格、功能全</td></tr><tr><td>托管</td><td>GitHub Pages</td><td>免费、和仓库联动</td></tr><tr><td>部署</td><td>GitHub Actions</td><td>push 即自动构建发布</td></tr></tbody></table></section>
<section><h4>二、搭建项目与本地预览<a href="#二搭建项目与本地预览"><span>#</span></a></h4><p>前置环境：需要 <strong>Node.js 20+</strong>（去 <a href="https://nodejs.org" target="_blank">nodejs.org</a> 下载安装）和 <strong>pnpm</strong> 包管理器：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 安装 pnpm（Node.js 自带 corepack，也可用 npm 装）</span></div></div><div><div><div>2</div></div><div><span>npm</span><span> </span><span>install</span><span> </span><span>-g</span><span> </span><span>pnpm</span></div></div><div><div><div>3</div></div><div><span>pnpm</span><span> </span><span>--version</span><span>   </span><span># 确认安装成功</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>Firefly 主题的仓库地址：<a href="https://github.com/CuteLeaf/Firefly" target="_blank">CuteLeaf/Firefly</a>。克隆后安装依赖：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 克隆模板（我的目录是 my-firefly-blog）</span></div></div><div><div><div>2</div></div><div><span>git</span><span> </span><span>clone</span><span> </span><span>https://github.com/CuteLeaf/Firefly.git</span><span> </span><span>my-firefly-blog</span></div></div><div><div><div>3</div></div><div><span>cd</span><span> </span><span>my-firefly-blog</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span># 安装依赖并启动本地预览</span></div></div><div><div><div>6</div></div><div><span>pnpm</span><span> </span><span>install</span></div></div><div><div><div>7</div></div><div><span>pnpm</span><span> </span><span>dev</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>浏览器打开 <code>http://localhost:4321</code> 即可看到站点。之后每次改配置，本地跑 <code>pnpm build</code> + <code>pnpm preview</code> 验证，确认无误再推送。</p></section>
<section><h4>三、双站并存：旧博客不丢<a href="#三双站并存旧博客不丢"><span>#</span></a></h4><p>迁移期间新站还没完全就绪，旧站不能直接关。方案是<strong>双站并存</strong>：</p><ul>
<li><strong>新站（Astro）</strong>：部署在 <code>lycaonide.github.io</code> 仓库，即主站 <code>https://lycaonide.github.io</code>；</li>
<li><strong>旧站（Hexo）</strong>：保留原内容，作为项目页部署到 <code>https://lycaonide.github.io/hexo-blog/</code>。</li>
</ul><p>等新站内容补齐后，再逐步把旧站文章迁过来，最后下线旧站即可。迁移过程零停服，随时可以回滚。</p></section>
<section><h4>四、字体本地化（最大的坑：jsdelivr 被墙）<a href="#四字体本地化最大的坑jsdelivr-被墙"><span>#</span></a></h4><p>这是迁移过程中最折腾的一环。主题默认从 <strong>jsdelivr CDN</strong> 下载 3 个在线字体（Zen Maru Gothic / Inter / JetBrains Mono），而 jsdelivr 在国内<strong>经常被墙</strong>，导致：</p><ul>
<li>构建卡在字体下载、超时失败；</li>
<li>线上页面字体加载不出来，回退成默认字体，很丑。</li>
</ul><p>试过的方案和结论：</p>

<table><thead><tr><th>方案</th><th>结果</th></tr></thead><tbody><tr><td>全局字体改系统字体</td><td>横幅标题、代码块仍引用在线字体</td></tr><tr><td>把字体装成 npm 包，provider 改 npm</td><td>Astro 7 的 npm provider <strong>依然走 jsdelivr</strong></td></tr><tr><td>local provider</td><td>集成静默失效，复制了字体但没生成 <code>@font-face</code></td></tr><tr><td><strong>手动 <code>@font-face</code> + 本地 woff2</strong> ✅</td><td><strong>成功</strong>，完全离线构建</td></tr></tbody></table><p>最终做法：</p><ol>
<li>把 4 个 woff2 字体文件放进 <code>public/assets/fonts/</code>（字体可从主题自带的 assets 目录复制，或从 Google Fonts 下载对应字重的 woff2）；</li>
<li>新建 <code>src/styles/local-fonts.css</code>，手写 <code>@font-face</code>：</li>
</ol><div><div><div><figure><figcaption><span>src/styles/local-fonts.css</span><span>展开</span><span>收起</span></figcaption><pre><code><div><div><div>1</div></div><div><span>@font-face</span><span> {</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>font-family: </span><span>"Noto Sans SC"</span><span>;</span></div></div><div><div><div>3</div></div><div><span><span>  </span></span><span>src: </span><span>url</span><span>(</span><span>"/assets/fonts/noto-sans-sc-500.woff2"</span><span>) </span><span>format</span><span>(</span><span>"woff2"</span><span>);</span></div></div><div><div><div>4</div></div><div><span><span>  </span></span><span>font-weight: </span><span>500</span><span>;</span></div></div><div><div><div>5</div></div><div><span><span>  </span></span><span>font-display: </span><span>swap</span><span>;</span></div></div><div><div><div>6</div></div><div><span>}</span></div></div><div><div><div>7</div></div><div><span>@font-face</span><span> {</span></div></div><div><div><div>8</div></div><div><span><span>  </span></span><span>font-family: </span><span>"Space Grotesk"</span><span>;</span></div></div><div><div><div>9</div></div><div><span><span>  </span></span><span>src: </span><span>url</span><span>(</span><span>"/assets/fonts/space-grotesk-500.woff2"</span><span>) </span><span>format</span><span>(</span><span>"woff2"</span><span>);</span></div></div><div><div><div>10</div></div><div><span><span>  </span></span><span>font-weight: </span><span>500</span><span>;</span></div></div><div><div><div>11</div></div><div><span><span>  </span></span><span>font-display: </span><span>swap</span><span>;</span></div></div><div><div><div>12</div></div><div><span>}</span></div></div><div><div><div>13</div></div><div><span>@font-face</span><span> {</span></div></div><div><div><div>14</div></div><div><span><span>  </span></span><span>font-family: </span><span>"JetBrains Mono"</span><span>;</span></div></div><div><div><div>15</div></div><div><span><span>  </span></span><span>src: </span><span>url</span><span>(</span><span>"/assets/fonts/jetbrains-mono-400.woff2"</span><span>) </span><span>format</span><span>(</span><span>"woff2"</span><span>);</span></div></div><div><div><div>16</div></div><div><span><span>  </span></span><span>font-weight: </span><span>400</span><span>;</span></div></div><div><div><div>17</div></div><div><span><span>  </span></span><span>font-display: </span><span>swap</span><span>;</span></div></div><div><div><div>18</div></div><div><span>}</span></div></div><div><div><div>19</div></div><div><span>@font-face</span><span> {</span></div></div><div><div><div>20</div></div><div><span><span>  </span></span><span>font-family: </span><span>"JetBrains Mono"</span><span>;</span></div></div><div><div><div>21</div></div><div><span><span>  </span></span><span>src: </span><span>url</span><span>(</span><span>"/assets/fonts/jetbrains-mono-700.woff2"</span><span>) </span><span>format</span><span>(</span><span>"woff2"</span><span>);</span></div></div><div><div><div>22</div></div><div><span><span>  </span></span><span>font-weight: </span><span>700</span><span>;</span></div></div><div><div><div>23</div></div><div><span><span>  </span></span><span>font-display: </span><span>swap</span><span>;</span></div></div><div><div><div>24</div></div><div><span>}</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><ol>
<li><code>fontConfig.ts</code> 里把 selected 设为 <code>["system"]</code>，让全局走系统字体；</li>
<li>写一个<strong>子集化脚本</strong>：扫描构建产物里的所有 HTML，收集实际用到的字符，只保留这些字符生成轻量 woff2（核心代码用了 <code>subset-font</code> 库）：</li>
</ol><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>// scripts/subset-fonts.ts（核心逻辑）</span></div></div><div><div><div>2</div></div><div><span>import</span><span> </span><span>subsetFont</span><span> </span><span>from</span><span> </span><span>"subset-font"</span><span>;</span></div></div><div><div><div>3</div></div><div><span>import</span><span> { </span><span>glob</span><span> } </span><span>from</span><span> </span><span>"glob"</span><span>;</span></div></div><div><div><div>4</div></div><div><span>import</span><span> { </span><span>readFile</span><span>, </span><span>writeFile</span><span> } </span><span>from</span><span> </span><span>"node:fs/promises"</span><span>;</span></div></div><div><div><div>5</div></div><div>
</div></div><div><div><div>6</div></div><div><span>// 1. 收集 dist/ 里所有 HTML 的实际字符</span></div></div><div><div><div>7</div></div><div><span>const</span><span> </span><span>htmlFiles</span><span> </span><span>=</span><span> </span><span>await</span><span> </span><span>glob</span><span>(</span><span>`</span><span>${</span><span>DIST_DIR</span><span>}</span><span>/**/*.html`</span><span>);</span></div></div><div><div><div>8</div></div><div><span>const</span><span> </span><span>charSet</span><span> </span><span>=</span><span> </span><span>new</span><span> </span><span>Set</span><span><span>&lt;</span><span>string</span><span>&gt;();</span></span></div></div><div><div><div>9</div></div><div><span>for</span><span> (</span><span>const</span><span> </span><span>file</span><span> </span><span>of</span><span><span> </span><span>htmlFiles</span><span>) {</span></span></div></div><div><div><div>10</div></div><div><span>  </span><span>const</span><span> </span><span>html</span><span> </span><span>=</span><span> </span><span>await</span><span> </span><span>readFile</span><span><span>(</span><span>file</span><span>, </span></span><span>"utf-8"</span><span>);</span></div></div><div><div><div>11</div></div><div><span>  </span><span>for</span><span> (</span><span>const</span><span> </span><span>c</span><span> </span><span>of</span><span><span> </span><span>html</span><span>.</span></span><span>replace</span><span>(</span><span>/&lt;</span><span>[</span><span>^</span><span>&gt;]</span><span><span>+</span><span>&gt;/</span></span><span>g</span><span>, </span><span>" "</span><span><span>)) </span><span>charSet</span><span>.</span></span><span>add</span><span><span>(</span><span>c</span><span>);</span></span></div></div><div><div><div>12</div></div><div><span>}</span></div></div><div><div><div>13</div></div><div>
</div></div><div><div><div>14</div></div><div><span>// 2. 用 subset-font 生成子集 woff2，再替换 CSS/HTML 里的引用</span></div></div><div><div><div>15</div></div><div><span>const</span><span> </span><span>subset</span><span> </span><span>=</span><span> </span><span>await</span><span> </span><span>subsetFont</span><span><span>(</span><span>fontBuffer</span><span>, [</span></span><span>...</span><span><span>charSet</span><span>].</span></span><span>join</span><span>(</span><span>""</span><span>), {</span></div></div><div><div><div>16</div></div><div><span>  </span><span>targetFormat</span><span>:</span><span> </span><span>"woff2"</span><span>,</span></div></div><div><div><div>17</div></div><div><span>});</span></div></div><div><div><div>18</div></div><div><span>await</span><span> </span><span>writeFile</span><span><span>(</span><span>outFile</span><span>, </span><span>subset</span><span>);</span></span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>这个脚本已集成进 <code>pnpm build</code>（构建链会自动执行），也可以单独跑：<code>npx tsx scripts/subset-fonts.ts</code>。结果：<strong>字体体积从 3MB 压到约 140KB</strong>（换了思源黑体后更小），页面加载快了很多。</p><section><h5>备选：在线字体（简单，但访客需要能连上 jsdelivr）<a href="#备选在线字体简单但访客需要能连上-jsdelivr"><span>#</span></a></h5><p>想省事的话，也可以用 <strong>Fontsource + jsdelivr CDN</strong> 在线引入，主题用的三个字体几行 CSS 就能加：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>/* 放在全局样式入口文件顶部 */</span></div></div><div><div><div>2</div></div><div><span>@import</span><span> </span><span>url</span><span>(</span><span>"https://cdn.jsdelivr.net/npm/@fontsource/zen-maru-gothic@5/index.css"</span><span>);</span></div></div><div><div><div>3</div></div><div><span>@import</span><span> </span><span>url</span><span>(</span><span>"https://cdn.jsdelivr.net/npm/@fontsource/jetbrains-mono@5/index.css"</span><span>);</span></div></div><div><div><div>4</div></div><div><span>@import</span><span> </span><span>url</span><span>(</span><span>"https://cdn.jsdelivr.net/npm/@fontsource/inter@5/index.css"</span><span>);</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>然后在字体配置里直接引用对应字体名即可，不用下载文件、不用子集化。</p><p><strong>但要注意在线方案的工作方式</strong>：字体不是打包进站点的，而是<strong>访客打开页面时由浏览器现场去 <code>cdn.jsdelivr.net</code> 拉取</strong>——访客网络连不上这个域名（国内直连常被墙）时，字体就加载不出来，页面回退成系统字体。它省的是站长的事，赌的是访客的网络。</p><p>本站最终用的是<strong>本地化方案</strong>（上面这套，已实测通过）：字体文件存在站点自己的服务器上，<strong>访客打开本站不需要连任何外部字体服务</strong>，构建和线上都稳。</p></section></section>
<section><h4>五、站点美化：装饰总开关<a href="#五站点美化装饰总开关"><span>#</span></a></h4><p>主题本身是二次元风格，加了几个装饰效果：<strong>樱花飘落、水波纹背景、卡片立体感</strong>。为了让它们可管理，我统一收敛到一个配置文件 <code>src/config/decorationConfig.ts</code>：</p><div><figure><figcaption><span>src/config/decorationConfig.ts</span></figcaption><pre><code><div><div><div>1</div></div><div><span>export</span><span> </span><span>const</span><span> </span><span>decorationConfig</span><span> </span><span>=</span><span> {</span></div></div><div><div><div>2</div></div><div><span>  </span><span>sakura</span><span>:</span><span> </span><span>true</span><span>,   </span><span>// 樱花飘落</span></div></div><div><div><div>3</div></div><div><span>  </span><span>live2d</span><span>:</span><span> </span><span>true</span><span>,   </span><span>// 看板娘</span></div></div><div><div><div>4</div></div><div><span>  </span><span>waves</span><span>:</span><span> </span><span>true</span><span>,    </span><span>// 背景水波纹</span></div></div><div><div><div>5</div></div><div><span>  </span><span>card3d</span><span>:</span><span> </span><span>true</span><span>,   </span><span>// 卡片立体感</span></div></div><div><div><div>6</div></div><div><span>};</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>想换”极简技术风”时，全部改成 <code>false</code> 就行，不用到处找开关。</p></section>
<section><h4>六、评论系统：Giscus<a href="#六评论系统giscus"><span>#</span></a></h4><p>评论用的是 <strong>Giscus</strong>（基于 GitHub Discussions，免费、无广告、数据在自己仓库里）。接入步骤：</p><ol>
<li><strong>开启 Discussions</strong>：仓库 <code>Settings → Features → Discussions</code> 勾选开启。开启后仓库导航栏会出现 Discussions 入口：</li>
</ol><p></p><figure><img src="/assets/blog-migrate/discussions.png" alt="步骤1：开启仓库 Discussions" /><figcaption>步骤1：开启仓库 Discussions</figcaption></figure><p></p><ol>
<li><strong>安装 giscus App</strong>：<a href="https://giscus.app" target="_blank">giscus.app</a> → Install，授权给博客仓库；</li>
<li><strong>生成配置</strong>：在 giscus 配置页填仓库名，页面会校验仓库状态（必须公开、已装 App、已开 Discussions），三项都满足会显示”成功”：</li>
</ol><p></p><figure><img src="/assets/blog-migrate/giscus-repo.png" alt="步骤3：giscus 配置页校验仓库" /><figcaption>步骤3：giscus 配置页校验仓库</figcaption></figure><p></p><ol>
<li><strong>写入主题配置</strong> <code>src/config/commentConfig.ts</code>：</li>
</ol><div><figure><figcaption><span>src/config/commentConfig.ts</span></figcaption><pre><code><div><div><div>1</div></div><div><span>export</span><span> </span><span>const</span><span> </span><span>commentConfig</span><span> </span><span>=</span><span> {</span></div></div><div><div><div>2</div></div><div><span>  </span><span>type</span><span>:</span><span> </span><span>"giscus"</span><span>,</span></div></div><div><div><div>3</div></div><div><span>  </span><span>repo</span><span>:</span><span> </span><span>"lycaonide/lycaonide.github.io"</span><span>,</span></div></div><div><div><div>4</div></div><div><span>  </span><span>repoId</span><span>:</span><span> </span><span>"R_kgDORApdOw"</span><span>,</span></div></div><div><div><div>5</div></div><div><span>  </span><span>category</span><span>:</span><span> </span><span>"Announcements"</span><span>,</span></div></div><div><div><div>6</div></div><div><span>  </span><span>categoryId</span><span>:</span><span> </span><span>"DIC_kwDORApdO84DFWdq"</span><span>,</span></div></div><div><div><div>7</div></div><div><span>  </span><span>mapping</span><span>:</span><span> </span><span>"title"</span><span>,        </span><span>// 按文章标题匹配讨论</span></div></div><div><div><div>8</div></div><div><span>  </span><span>reactionsEnabled</span><span>:</span><span> </span><span>"1"</span><span>,</span></div></div><div><div><div>9</div></div><div><span>  </span><span>inputPosition</span><span>:</span><span> </span><span>"top"</span><span>,</span></div></div><div><div><div>10</div></div><div><span>  </span><span>lang</span><span>:</span><span> </span><span>"zh-CN"</span><span>,</span></div></div><div><div><div>11</div></div><div><span>  </span><span>loading</span><span>:</span><span> </span><span>"lazy"</span><span>,</span></div></div><div><div><div>12</div></div><div><span>};</span></div></div></code></pre><div><div></div><div></div></div></figure></div><blockquote><p>补充：分类我选了 <strong>Announcements</strong>（公告分类），可以防止陌生人随意开新讨论刷屏。</p></blockquote></section>
<section><h4>七、友链页面<a href="#七友链页面"><span>#</span></a></h4><p>主题自带了友链页，只是默认关闭。开启方法：</p><div><figure><figcaption><span>src/config/siteConfig.ts</span></figcaption><pre><code><div><div><div>1</div></div><div><span><span>friends</span><span>: </span></span><span>true</span><span>,   </span><span>// 原来是 false</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>同时新建 <code>src/content/spec/friends.md</code> 写入友链说明（本站信息、申请方式、小要求），页面底部就会显示自定义的友链交换说明。</p><p>注意：友链内容页缺失会导致构建报错 <code>friends page content not found</code>，所以 <strong>开关和内容文件要一起建</strong>。</p></section>
<section><h4>八、GitHub Actions 自动部署<a href="#八github-actions-自动部署"><span>#</span></a></h4><p>推送后自动构建发布，用的是 Actions workflow（<code>.github/workflows/deploy.yml</code>），这是本站实际在用的完整配置：</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>name</span><span>: </span><span>Deploy to GitHub Pages</span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>on</span><span>:</span></div></div><div><div><div>4</div></div><div><span>  </span><span>push</span><span>:</span></div></div><div><div><div>5</div></div><div><span>    </span><span>branches</span><span>: [ </span><span>main</span><span>, </span><span>master</span><span> ]</span></div></div><div><div><div>6</div></div><div><span>  </span><span>workflow_dispatch</span><span>:</span></div></div><div><div><div>7</div></div><div>
</div></div><div><div><div>8</div></div><div><span># Pages 部署需要的权限</span></div></div><div><div><div>9</div></div><div><span>permissions</span><span>:</span></div></div><div><div><div>10</div></div><div><span>  </span><span>contents</span><span>: </span><span>read</span></div></div><div><div><div>11</div></div><div><span>  </span><span>pages</span><span>: </span><span>write</span></div></div><div><div><div>12</div></div><div><span>  </span><span>id-token</span><span>: </span><span>write</span></div></div><div><div><div>13</div></div><div>
</div></div><div><div><div>14</div></div><div><span># 确保只有一个部署任务同时运行</span></div></div><div><div><div>15</div></div><div><span>concurrency</span><span>:</span></div></div><div><div><div>16</div></div><div><span>  </span><span>group</span><span>: </span><span>"pages"</span></div></div><div><div><div>17</div></div><div><span>  </span><span>cancel-in-progress</span><span>: </span><span>false</span></div></div><div><div><div>18</div></div><div>
</div></div><div><div><div>19</div></div><div><span>jobs</span><span>:</span></div></div><div><div><div>20</div></div><div><span>  </span><span>build</span><span>:</span></div></div><div><div><div>21</div></div><div><span>    </span><span>runs-on</span><span>: </span><span>ubuntu-latest</span></div></div><div><div><div>22</div></div><div><span>    </span><span>steps</span><span>:</span></div></div><div><div><div>23</div></div><div><span><span>      </span></span><span>- </span><span>name</span><span>: </span><span>Checkout</span></div></div><div><div><div>24</div></div><div><span>        </span><span>uses</span><span>: </span><span>actions/checkout@v4</span></div></div><div><div><div>25</div></div><div>
</div></div><div><div><div>26</div></div><div><span><span>      </span></span><span>- </span><span>name</span><span>: </span><span>Setup Node.js</span></div></div><div><div><div>27</div></div><div><span>        </span><span>uses</span><span>: </span><span>actions/setup-node@v4</span></div></div><div><div><div>28</div></div><div><span>        </span><span>with</span><span>:</span></div></div><div><div><div>29</div></div><div><span>          </span><span>node-version</span><span>: </span><span>'22'</span></div></div><div><div><div>30</div></div><div>
</div></div><div><div><div>31</div></div><div><span><span>      </span></span><span>- </span><span>name</span><span>: </span><span>Setup pnpm</span></div></div><div><div><div>32</div></div><div><span>        </span><span>uses</span><span>: </span><span>pnpm/action-setup@v4</span></div></div><div><div><div>33</div></div><div><span>        </span><span>with</span><span>:</span></div></div><div><div><div>34</div></div><div><span>          </span><span>version</span><span>: </span><span>11.22.0</span></div></div><div><div><div>35</div></div><div><span>          </span><span>run_install</span><span>: </span><span>false</span></div></div><div><div><div>36</div></div><div>
</div></div><div><div><div>37</div></div><div><span><span>      </span></span><span>- </span><span>name</span><span>: </span><span>Install dependencies</span></div></div><div><div><div>38</div></div><div><span>        </span><span>run</span><span>: </span><span>pnpm install --no-frozen-lockfile</span></div></div><div><div><div>39</div></div><div>
</div></div><div><div><div>40</div></div><div><span><span>      </span></span><span>- </span><span>name</span><span>: </span><span>Build site</span></div></div><div><div><div>41</div></div><div><span>        </span><span>run</span><span>: </span><span>pnpm run build</span></div></div><div><div><div>42</div></div><div>
</div></div><div><div><div>43</div></div><div><span><span>      </span></span><span>- </span><span>name</span><span>: </span><span>Create .nojekyll file</span></div></div><div><div><div>44</div></div><div><span>        </span><span>run</span><span>: </span><span>touch dist/.nojekyll</span></div></div><div><div><div>45</div></div><div>
</div></div><div><div><div>46</div></div><div><span><span>      </span></span><span>- </span><span>name</span><span>: </span><span>Upload artifact</span></div></div><div><div><div>47</div></div><div><span>        </span><span>uses</span><span>: </span><span>actions/upload-pages-artifact@v3</span></div></div><div><div><div>48</div></div><div><span>        </span><span>with</span><span>:</span></div></div><div><div><div>49</div></div><div><span>          </span><span>path</span><span>: </span><span>dist</span><span>  </span><span># Astro默认构建输出目录</span></div></div><div><div><div>50</div></div><div>
</div></div><div><div><div>51</div></div><div><span>  </span><span>deploy</span><span>:</span></div></div><div><div><div>52</div></div><div><span>    </span><span>environment</span><span>:</span></div></div><div><div><div>53</div></div><div><span>      </span><span>name</span><span>: </span><span>github-pages</span></div></div><div><div><div>54</div></div><div><span>      </span><span>url</span><span>: </span><span>${{ steps.deployment.outputs.page_url }}</span></div></div><div><div><div>55</div></div><div><span>    </span><span>runs-on</span><span>: </span><span>ubuntu-latest</span></div></div><div><div><div>56</div></div><div><span>    </span><span>needs</span><span>: </span><span>build</span></div></div><div><div><div>57</div></div><div><span>    </span><span>steps</span><span>:</span></div></div><div><div><div>58</div></div><div><span><span>      </span></span><span>- </span><span>name</span><span>: </span><span>Deploy to GitHub Pages</span></div></div><div><div><div>59</div></div><div><span>        </span><span>id</span><span>: </span><span>deployment</span></div></div><div><div><div>60</div></div><div><span>        </span><span>uses</span><span>: </span><span>actions/deploy-pages@v4</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>几个关键点：</p><ul>
<li><strong><code>touch dist/.nojekyll</code></strong>：GitHub Pages 默认用 Jekyll 处理，不建这个文件会把 <code>_astro</code> 这类目录忽略掉，页面会白屏；</li>
<li><strong><code>concurrency</code></strong>：防止多次 push 时部署任务互相打架；</li>
<li><strong><code>workflow_dispatch</code></strong>：想手动触发重新部署时，Actions 页面点一下即可。</li>
</ul><p>每次 push 后，仓库的 Actions 页面会看到构建部署记录（绿色对勾表示成功，点进去能看每步日志）：</p><p></p><figure><img src="/assets/blog-migrate/github-actions.png" alt="步骤：push 后在 Actions 页面查看部署记录" /><figcaption>步骤：push 后在 Actions 页面查看部署记录</figcaption></figure><p></p><p>以后写文章只需要：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>git</span><span> </span><span>add</span><span> </span><span>.</span></div></div><div><div><div>2</div></div><div><span>git</span><span> </span><span>commit</span><span> </span><span>-m</span><span> </span><span>"新文章"</span></div></div><div><div><div>3</div></div><div><span>git</span><span> </span><span>push</span></div></div></code></pre><div><div></div><div></div></div></figure></div><blockquote><p>前置：<code>git push</code> 走 SSH，需要先在 GitHub 配置好 SSH 密钥（生成密钥、把公钥加到 GitHub → SSH and GPG keys，方法可参考本站《学习用Hexo写博客》一文第五节）。</p></blockquote><p>等待 3-4 分钟，Actions 构建部署完成，线上自动更新，全程不用手动操作。</p></section>
<section><h4>十、Cloudflare Pages 部署（国内访问加速）<a href="#十cloudflare-pages-部署国内访问加速"><span>#</span></a></h4><p>GitHub Pages 的服务器在境外，国内访问时快时慢，图片、字体偶尔要等很久。为了让国内访客更流畅，给本站加了一层 <strong>Cloudflare Pages 双部署</strong>：GitHub Pages 保持不变（原有链接不断），Cloudflare Pages 作为国内加速入口，两个域名内容同步。</p><p><strong>双部署有什么用：</strong></p><ul>
<li><strong>国内加速</strong>：Cloudflare 有全球 CDN（含国内优化节点），页面、图片、字体加载明显更快，这是最主要的价值；</li>
<li><strong>双保险</strong>：一个平台出问题（GitHub 被墙、Pages 服务异常、DNS 污染），另一个域名随时能顶上，站点不”失联”；</li>
<li><strong>评论/友链不受影响</strong>：Giscus 评论挂在 GitHub 仓库上、友链数据在配置里，两个域名共用同一套，换域名不丢数据。</li>
</ul><p><strong>两个网址内容完全一致，按网络环境任选：</strong></p><ul>
<li>GitHub Pages：<code>https://lycaonide.github.io</code></li>
<li>Cloudflare Pages：<code>https://my-firefly-blog.pages.dev</code></li>
</ul><section><h5>为什么选 Cloudflare Pages<a href="#为什么选-cloudflare-pages"><span>#</span></a></h5><ul>
<li><strong>免费额度够用</strong>：每月 100 GB 流量，静态博客轻松覆盖；</li>
<li><strong>自带全球 CDN</strong>：国内节点比 GitHub Pages 快得多；</li>
<li><strong>支持自定义域名、自动 HTTPS</strong>；</li>
<li><strong>和 GitHub 无缝衔接</strong>：可以直接连仓库，也可以用 API Token 手动部署。</li>
</ul></section><section><h5>方案对比：控制台连接 Git vs API Token<a href="#方案对比控制台连接-git-vs-api-token"><span>#</span></a></h5><p>一开始尝试的是 Cloudflare 控制台「连接到 Git」（Workers 和 Pages → 创建 → 连接到 Git → 授权 GitHub → 选仓库），理想情况是自动构建、push 即部署。但实测遇到了几个坑：</p><ul>
<li>点「Connect GitHub」后<strong>反复跳转到 GitHub 的 App 安装配置页</strong>（settings/installations），而不是正常的 OAuth 授权；</li>
<li>仓库权限配好后点 Save，<strong>授权回调不自动回 CF</strong>，仓库列表一直加载不出来；</li>
<li>折腾半天走不到选仓库那一步。</li>
</ul><p><strong>为什么改用 API Token 方案：</strong></p><ul>
<li><strong>不依赖控制台页面</strong>：命令行一条命令完成部署，不碰那个绕圈的 OAuth 流程；</li>
<li><strong>可复现、可写进脚本/CI</strong>：命令即文档，以后换机器也能一键部署；</li>
<li><strong>权限可精确控制</strong>：token 只给「Cloudflare Pages → Edit」权限，用完随时在控制台撤销，比账号级授权更安全。</li>
</ul></section><section><h5>1. 创建 API Token<a href="#1-创建-api-token"><span>#</span></a></h5><p>打开 <strong>Cloudflare 控制台</strong>（<a href="https://dash.cloudflare.com%EF%BC%89%E2%86%92" target="_blank">https://dash.cloudflare.com）→</a> 右上角头像 → <strong>My Profile</strong> → <strong>API Tokens</strong> → <strong>Create Token</strong> → 选 <strong>Custom token</strong>：</p><ul>
<li>Token name：随意（比如 <code>blog-deploy</code>）；</li>
<li>Permissions：<code>Account</code> → <code>Cloudflare Pages</code> → <code>Edit</code>；</li>
<li>Account resources：<code>Include</code> → 你的账号；</li>
<li>其他默认，点 Create 后复制 token（只显示一次）。</li>
</ul><blockquote><p>注意：token 相当于账号钥匙，<strong>不要提交到代码仓库</strong>；部署完可以随时在控制台撤销轮换。</p></blockquote></section><section><h5>2. 构建并部署（wrangler）<a href="#2-构建并部署wrangler"><span>#</span></a></h5><p>本地构建产物在 <code>dist/</code>，用 <a href="https://developers.cloudflare.com/workers/wrangler/" target="_blank">wrangler</a> 直接推上去（Node 自带 npx，无需全局安装）：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 1. 构建（输出 dist/）</span></div></div><div><div><div>2</div></div><div><span>pnpm</span><span> </span><span>build</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span># 2. 配置凭据（PowerShell 用 $env: 前缀）</span></div></div><div><div><div>5</div></div><div><span>export</span><span> </span><span>CLOUDFLARE_API_TOKEN</span><span>=</span><span>"你的API_TOKEN"</span><span>      </span><span># 上一步创建的</span></div></div><div><div><div>6</div></div><div><span>export</span><span> </span><span>CLOUDFLARE_ACCOUNT_ID</span><span>=</span><span>"你的账号ID"</span><span>        </span><span># CF 控制台 URL 里 /xxx/ 那段</span></div></div><div><div><div>7</div></div><div>
</div></div><div><div><div>8</div></div><div><span># 3. 创建 Pages 项目（仅首次）</span></div></div><div><div><div>9</div></div><div><span>npx</span><span> </span><span>wrangler</span><span> </span><span>pages</span><span> </span><span>project</span><span> </span><span>create</span><span> </span><span>my-firefly-blog</span><span> </span><span>--production-branch</span><span> </span><span>main</span></div></div><div><div><div>10</div></div><div>
</div></div><div><div><div>11</div></div><div><span># 4. 部署 dist 目录</span></div></div><div><div><div>12</div></div><div><span>npx</span><span> </span><span>wrangler</span><span> </span><span>pages</span><span> </span><span>deploy</span><span> </span><span>dist</span><span> </span><span>--project-name</span><span> </span><span>my-firefly-blog</span><span> </span><span>--branch</span><span> </span><span>main</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>部署成功输出（真实记录）：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>✨ Success! Uploaded 244 files (17.28 sec)</span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>🌎 Deploying...</span></div></div><div><div><div>4</div></div><div><span>✨ Deployment complete! Take a peek over at https://ca824054.my-firefly-blog.pages.dev</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>生产域名：<strong><a href="https://my-firefly-blog.pages.dev" target="_blank">https://my-firefly-blog.pages.dev</a></strong></p></section><section><h5>3. 验证<a href="#3-验证"><span>#</span></a></h5><p>浏览器打开 <code>https://my-firefly-blog.pages.dev</code>，内容和 GitHub Pages 完全一致（同一个 dist 构建产物），国内访问明显更流畅：</p><p></p><figure><img src="/assets/blog-migrate/cloudflare-pages.jpg" alt="Cloudflare Pages 部署后的博客首页" /><figcaption>Cloudflare Pages 部署后的博客首页</figcaption></figure><p></p><p>Cloudflare 控制台的部署记录页（Production 域名 + 每次部署的提交信息、状态、预览地址）：</p><p></p><figure><img src="/assets/blog-migrate/cf-deploy-page.jpg" alt="Cloudflare Pages 部署记录页" /><figcaption>Cloudflare Pages 部署记录页</figcaption></figure><p></p></section><section><h5>4. 后续自动化：push 双平台同步<a href="#4-后续自动化push-双平台同步"><span>#</span></a></h5><p>目前 GitHub Pages 是 push 自动部署，Cloudflare Pages 是手动 <code>wrangler pages deploy</code>。想做到<strong>推一次代码、两个平台同时更新</strong>，在仓库新建 <code>.github/workflows/deploy-cloudflare.yml</code>，用官方 <code>cloudflare/wrangler-action@v3</code>：</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>name</span><span>: </span><span>Deploy to Cloudflare Pages</span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>on</span><span>:</span></div></div><div><div><div>4</div></div><div><span>  </span><span>push</span><span>:</span></div></div><div><div><div>5</div></div><div><span>    </span><span>branches</span><span>: [</span><span>main</span><span>]</span></div></div><div><div><div>6</div></div><div><span>  </span><span>workflow_dispatch</span><span>:</span></div></div><div><div><div>7</div></div><div>
</div></div><div><div><div>8</div></div><div><span>jobs</span><span>:</span></div></div><div><div><div>9</div></div><div><span>  </span><span>deploy</span><span>:</span></div></div><div><div><div>10</div></div><div><span>    </span><span>runs-on</span><span>: </span><span>ubuntu-latest</span></div></div><div><div><div>11</div></div><div><span>    </span><span>permissions</span><span>:</span></div></div><div><div><div>12</div></div><div><span>      </span><span>contents</span><span>: </span><span>read</span></div></div><div><div><div>13</div></div><div><span>    </span><span>steps</span><span>:</span></div></div><div><div><div>14</div></div><div><span><span>      </span></span><span>- </span><span>name</span><span>: </span><span>Checkout</span></div></div><div><div><div>15</div></div><div><span>        </span><span>uses</span><span>: </span><span>actions/checkout@v4</span></div></div><div><div><div>16</div></div><div>
</div></div><div><div><div>17</div></div><div><span><span>      </span></span><span>- </span><span>name</span><span>: </span><span>Setup Node.js</span></div></div><div><div><div>18</div></div><div><span>        </span><span>uses</span><span>: </span><span>actions/setup-node@v4</span></div></div><div><div><div>19</div></div><div><span>        </span><span>with</span><span>:</span></div></div><div><div><div>20</div></div><div><span>          </span><span>node-version</span><span>: </span><span>'22'</span></div></div><div><div><div>21</div></div><div>
</div></div><div><div><div>22</div></div><div><span><span>      </span></span><span>- </span><span>name</span><span>: </span><span>Setup pnpm</span></div></div><div><div><div>23</div></div><div><span>        </span><span>uses</span><span>: </span><span>pnpm/action-setup@v4</span></div></div><div><div><div>24</div></div><div><span>        </span><span>with</span><span>:</span></div></div><div><div><div>25</div></div><div><span>          </span><span>version</span><span>: </span><span>11.22.0</span></div></div><div><div><div>26</div></div><div><span>          </span><span>run_install</span><span>: </span><span>false</span></div></div><div><div><div>27</div></div><div>
</div></div><div><div><div>28</div></div><div><span><span>      </span></span><span>- </span><span>name</span><span>: </span><span>Install dependencies</span></div></div><div><div><div>29</div></div><div><span>        </span><span>run</span><span>: </span><span>pnpm install --no-frozen-lockfile</span></div></div><div><div><div>30</div></div><div>
</div></div><div><div><div>31</div></div><div><span><span>      </span></span><span>- </span><span>name</span><span>: </span><span>Build</span></div></div><div><div><div>32</div></div><div><span>        </span><span>run</span><span>: </span><span>pnpm run build</span></div></div><div><div><div>33</div></div><div>
</div></div><div><div><div>34</div></div><div><span><span>      </span></span><span>- </span><span>name</span><span>: </span><span>Deploy to Cloudflare Pages</span></div></div><div><div><div>35</div></div><div><span>        </span><span>uses</span><span>: </span><span>cloudflare/wrangler-action@v3</span></div></div><div><div><div>36</div></div><div><span>        </span><span>with</span><span>:</span></div></div><div><div><div>37</div></div><div><span>          </span><span>apiToken</span><span>: </span><span>${{ secrets.CLOUDFLARE_API_TOKEN }}</span></div></div><div><div><div>38</div></div><div><span>          </span><span>accountId</span><span>: </span><span>${{ secrets.CLOUDFLARE_ACCOUNT_ID }}</span></div></div><div><div><div>39</div></div><div><span>          </span><span>command</span><span>: </span><span>pages deploy dist --project-name my-firefly-blog --branch main</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>使用前提：在 GitHub 仓库 Settings → Secrets and variables → Actions 里添加两个 secret：</p><ul>
<li><code>CLOUDFLARE_API_TOKEN</code>：Cloudflare API Token（创建方法见上文）；</li>
<li><code>CLOUDFLARE_ACCOUNT_ID</code>：Cloudflare 账号 ID（控制台 URL 里 <code>/xxx/</code> 那段）。</li>
</ul><p>配好之后，每次 <code>git push</code> 会自动构建并同时部署到 GitHub Pages 和 Cloudflare Pages。</p></section><section><h5>5. 自定义域名（可选）<a href="#5-自定义域名可选"><span>#</span></a></h5><p>Cloudflare Pages 支持绑定自定义域名（免费，自动 HTTPS），在项目页 → Custom domains 里添加即可。本站暂时用 <code>pages.dev</code> 子域名，等有合适域名再绑。绑定后原 <code>pages.dev</code> 域名依然可用，不影响现有访问。</p></section></section>
<section><h4>十一、总结<a href="#十一总结"><span>#</span></a></h4><p>这次迁移的核心经验：</p><ol>
<li><strong>配置收敛</strong>：装饰、评论、友链等开关集中在 config 文件里，方便统一管理；</li>
<li><strong>双站过渡</strong>：新旧站并存，内容迁完再下线，风险可控；</li>
<li><strong>自动化部署</strong>：GitHub Actions 让发布变成”push 就完事”。</li>
</ol><p>最终效果就是你现在看到的这个站：Astro 7 + Firefly 主题 + GitHub Pages，樱花、评论、友链齐全，加载快还免费。</p></section>]]></content>
    </entry>
    <entry>
      <id>https://lycaonide.github.io/posts/%E5%AD%A6%E4%B9%A0%E7%94%A8hexo%E5%86%99%E5%8D%9A%E5%AE%A2%E4%BF%AE%E6%94%B9%E7%89%88/</id>
      <title type="text">学习用Hexo写博客修改版</title>
      <published>2026-03-25T00:00:00.000Z</published>
      <updated>2026-03-25T00:00:00.000Z</updated>
      <author><name>lycaonide</name></author>
      <link rel="alternate" href="https://lycaonide.github.io/posts/%E5%AD%A6%E4%B9%A0%E7%94%A8hexo%E5%86%99%E5%8D%9A%E5%AE%A2%E4%BF%AE%E6%94%B9%E7%89%88/"/>
      <summary type="text"></summary>
      <content type="html"><![CDATA[<section><h4>一、新建博客<a href="#一新建博客"><span>#</span></a></h4><p><strong>操作</strong>：
打开 Git Bash，进入 Hexo 项目目录：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>cd</span><span> </span><span>~/Desktop/my-hexo-blog</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>输入命令新建文章，格式如下：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>hexo</span><span> </span><span>new</span><span> </span><span>"你的博客标题"</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p> </p></section>
<section><h4>二、编辑博客内容<a href="#二编辑博客内容"><span>#</span></a></h4><p><strong>操作</strong>：
打开文章文件：用任意 Markdown 编辑器打开 <code>source/_posts/你的博客标题.md</code> 文件。
配置文章信息：文件开头的「Front-matter」是 Hexo 识别文章属性的区域（必须保留），<strong>格式说明</strong>：</p><ul>
<li><code>---</code>：固定开头和结尾标记，不可省略</li>
<li><code>title:</code>：文章标题，<strong>中文/英文均可</strong>，冒号后必须加空格</li>
<li><code>date:</code>：发布日期，<strong>格式为 <code>YYYY-MM-DD HH:mm:ss</code></strong>，冒号后必须加空格</li>
<li><code>tags:</code>：文章标签，<strong>中文/英文均可</strong>，多个标签用 <code>[标签1, 标签2]</code> 数组格式，冒号后必须加空格</li>
<li><code>categories:</code>：文章分类，<strong>中文/英文均可</strong>，冒号后必须加空格</li>
</ul><section><h5>📝 写博客模板<a href="#-写博客模板"><span>#</span></a></h5><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>---</span></div></div><div><div><div>2</div></div><div><span>title</span><span>: </span><span>你的博客标题</span></div></div><div><div><div>3</div></div><div><span>date</span><span>: </span><span>2026-03-25 14:00:00</span></div></div><div><div><div>4</div></div><div><span>tags</span><span>: [</span><span>标签1</span><span>, </span><span>标签2</span><span>]</span></div></div><div><div><div>5</div></div><div><span>categories</span><span>: </span><span>分类名称</span></div></div><div><div><div>6</div></div><div><span>---</span></div></div><div><div><div>7</div></div><div><span># 一级标题（中文/英文均可）</span></div></div><div><div><div>8</div></div><div><span>正文内容（支持 Markdown 语法）</span></div></div><div><div><div>9</div></div><div>
</div></div><div><div><div>10</div></div><div><span>## 二级标题（中文/英文均可）</span></div></div><div><div><div>11</div></div><div><span><span>-</span><span> 列表项1</span></span></div></div><div><div><div>12</div></div><div><span><span>-</span><span> 列表项2</span></span></div></div><div><div><div>13</div></div><div>
</div></div><div><div><div>14</div></div><div><span>### 三级标题（中文/英文均可）</span></div></div><div><div><div>15</div></div><div><span>[</span><span>链接文字</span><span>]</span><span><span>(</span><span>链接地址</span><span>)</span></span></div></div><div><div><div>16</div></div><div><span>![</span><span>图片描述</span><span>]</span><span><span>(</span><span>/images/图片文件名.jpg</span><span>)</span></span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p> </p></section></section>
<section><h4>三、本地预览博客效果<a href="#三本地预览博客效果"><span>#</span></a></h4><p><strong>操作</strong>：
在 Git Bash 的 Hexo 项目目录下，输入命令启动本地服务：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>hexo</span><span> </span><span>clean</span><span>  </span><span># 先清理旧缓存（建议执行）</span></div></div><div><div><div>2</div></div><div><span>hexo</span><span> </span><span>s</span><span>      </span><span># 启动本地预览</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p><strong>验证</strong>：
打开浏览器访问 <code>http://localhost:4000</code>，在「文章」列表中找到对应文章，点击进入查看格式、图片、链接是否正常显示。</p><p><strong>关闭预览</strong>：
在 Git Bash 中按 <code>Ctrl+C</code> 终止服务。</p><p> </p></section>
<section><h4>四、发布新博客到线上<a href="#四发布新博客到线上"><span>#</span></a></h4><section><h5>🔍 为什么要修改原步骤？<a href="#-为什么要修改原步骤"><span>#</span></a></h5><p><strong>核心原因</strong>：国内网络环境对 GitHub 存在访问限制，直接执行 <code>hexo d</code> 会出现「连接失败、无法解析主机」等错误，导致部署失败。
<strong>解决方案</strong>：使用「红岸加速器」来绕过网络限制，因此需要手动配置 Git 代理，让 Git 走加速器的本地端口（<code>7892</code>），才能正常推送代码到 GitHub。</p></section><section><h5>✅ 修改后的完整操作步骤<a href="#-修改后的完整操作步骤"><span>#</span></a></h5><p>在 Git Bash 的 Hexo 项目目录下，依次执行以下命令：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 1. 清空旧代理配置（避免之前残留的错误端口影响）</span></div></div><div><div><div>2</div></div><div><span>git</span><span> </span><span>config</span><span> </span><span>--global</span><span> </span><span>--unset</span><span> </span><span>http.proxy</span></div></div><div><div><div>3</div></div><div><span>git</span><span> </span><span>config</span><span> </span><span>--global</span><span> </span><span>--unset</span><span> </span><span>https.proxy</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span># 2. 配置红岸加速器代理（本地端口为 7892，与加速器配置一致）</span></div></div><div><div><div>6</div></div><div><span>git</span><span> </span><span>config</span><span> </span><span>--global</span><span> </span><span>http.proxy</span><span> </span><span>http://127.0.0.1:7892</span></div></div><div><div><div>7</div></div><div><span>git</span><span> </span><span>config</span><span> </span><span>--global</span><span> </span><span>https.proxy</span><span> </span><span>http://127.0.0.1:7892</span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span># 3. 清理本地缓存 + 生成静态文件 + 部署到 GitHub</span></div></div><div><div><div>10</div></div><div><span>hexo</span><span> </span><span>clean</span><span>  </span><span># 清理本地缓存，确保生成最新文件</span></div></div><div><div><div>11</div></div><div><span>hexo</span><span> </span><span>g</span><span>      </span><span># 重新生成包含新文章的静态页面</span></div></div><div><div><div>12</div></div><div><span>hexo</span><span> </span><span>d</span><span>      </span><span># 部署到 GitHub 仓库</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h5>📌 成功反馈<a href="#-成功反馈"><span>#</span></a></h5><p>终端显示 <code>INFO  Deploy done: git</code> 即代表部署完成。</p></section><section><h5>🧩写博客的 Git Bash 操作模板<a href="#写博客的-git-bash-操作模板"><span>#</span></a></h5><div><div><div><figure><figcaption><span></span><span>Terminal window</span><span>展开</span><span>收起</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 1. 进入项目目录</span></div></div><div><div><div>2</div></div><div><span>cd</span><span> </span><span>~/Desktop/my-hexo-blog</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span># 2. 新建文章</span></div></div><div><div><div>5</div></div><div><span>hexo</span><span> </span><span>new</span><span> </span><span>"你的博客标题"</span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span># 3. 编辑文章后，本地预览</span></div></div><div><div><div>8</div></div><div><span>hexo</span><span> </span><span>clean</span></div></div><div><div><div>9</div></div><div><span>hexo</span><span> </span><span>s</span></div></div><div><div><div>10</div></div><div>
</div></div><div><div><div>11</div></div><div><span># 4. 预览无误后，部署上线</span></div></div><div><div><div>12</div></div><div><span>git</span><span> </span><span>config</span><span> </span><span>--global</span><span> </span><span>--unset</span><span> </span><span>http.proxy</span></div></div><div><div><div>13</div></div><div><span>git</span><span> </span><span>config</span><span> </span><span>--global</span><span> </span><span>--unset</span><span> </span><span>https.proxy</span></div></div><div><div><div>14</div></div><div><span>git</span><span> </span><span>config</span><span> </span><span>--global</span><span> </span><span>http.proxy</span><span> </span><span>http://127.0.0.1:7892</span></div></div><div><div><div>15</div></div><div><span>git</span><span> </span><span>config</span><span> </span><span>--global</span><span> </span><span>https.proxy</span><span> </span><span>http://127.0.0.1:7892</span></div></div><div><div><div>16</div></div><div><span>hexo</span><span> </span><span>clean</span><span> &amp;&amp; </span><span>hexo</span><span> </span><span>g</span><span> &amp;&amp; </span><span>hexo</span><span> </span><span>d</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section><section><h5>🧩 修改博客的 Git Bash 操作模板<a href="#-修改博客的-git-bash-操作模板"><span>#</span></a></h5><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 1. 进入项目目录</span></div></div><div><div><div>2</div></div><div><span>cd</span><span> </span><span>~/Desktop/my-hexo-blog</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span># 2. 编辑文章后，本地预览</span></div></div><div><div><div>5</div></div><div><span>hexo</span><span> </span><span>clean</span></div></div><div><div><div>6</div></div><div><span>hexo</span><span> </span><span>s</span></div></div><div><div><div>7</div></div><div>
</div></div><div><div><div>8</div></div><div><span># 3. 预览无误后，部署上线</span></div></div><div><div><div>9</div></div><div><span>git</span><span> </span><span>config</span><span> </span><span>--global</span><span> </span><span>--unset</span><span> </span><span>http.proxy</span></div></div><div><div><div>10</div></div><div><span>git</span><span> </span><span>config</span><span> </span><span>--global</span><span> </span><span>--unset</span><span> </span><span>https.proxy</span></div></div><div><div><div>11</div></div><div><span>git</span><span> </span><span>config</span><span> </span><span>--global</span><span> </span><span>http.proxy</span><span> </span><span>http://127.0.0.1:7892</span></div></div><div><div><div>12</div></div><div><span>git</span><span> </span><span>config</span><span> </span><span>--global</span><span> </span><span>https.proxy</span><span> </span><span>http://127.0.0.1:7892</span></div></div><div><div><div>13</div></div><div><span>hexo</span><span> </span><span>clean</span><span> &amp;&amp; </span><span>hexo</span><span> </span><span>g</span><span> &amp;&amp; </span><span>hexo</span><span> </span><span>d</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h5>🧩 一键部署模板（推荐保存为 <code>deploy.sh</code>）<a href="#-一键部署模板推荐保存为-deploysh"><span>#</span></a></h5><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>#!/bin/bash</span></div></div><div><div><div>2</div></div><div><span># 清空旧代理</span></div></div><div><div><div>3</div></div><div><span>git</span><span> </span><span>config</span><span> </span><span>--global</span><span> </span><span>--unset</span><span> </span><span>http.proxy</span></div></div><div><div><div>4</div></div><div><span>git</span><span> </span><span>config</span><span> </span><span>--global</span><span> </span><span>--unset</span><span> </span><span>https.proxy</span></div></div><div><div><div>5</div></div><div>
</div></div><div><div><div>6</div></div><div><span># 配置红岸加速器代理</span></div></div><div><div><div>7</div></div><div><span>git</span><span> </span><span>config</span><span> </span><span>--global</span><span> </span><span>http.proxy</span><span> </span><span>http://127.0.0.1:7892</span></div></div><div><div><div>8</div></div><div><span>git</span><span> </span><span>config</span><span> </span><span>--global</span><span> </span><span>https.proxy</span><span> </span><span>http://127.0.0.1:7892</span></div></div><div><div><div>9</div></div><div>
</div></div><div><div><div>10</div></div><div><span># 执行部署</span></div></div><div><div><div>11</div></div><div><span>hexo</span><span> </span><span>clean</span><span> &amp;&amp; </span><span>hexo</span><span> </span><span>g</span><span> &amp;&amp; </span><span>hexo</span><span> </span><span>d</span></div></div><div><div><div>12</div></div><div>
</div></div><div><div><div>13</div></div><div><span># 部署完成后取消代理（可选）</span></div></div><div><div><div>14</div></div><div><span>git</span><span> </span><span>config</span><span> </span><span>--global</span><span> </span><span>--unset</span><span> </span><span>http.proxy</span></div></div><div><div><div>15</div></div><div><span>git</span><span> </span><span>config</span><span> </span><span>--global</span><span> </span><span>--unset</span><span> </span><span>https.proxy</span></div></div><div><div><div>16</div></div><div>
</div></div><div><div><div>17</div></div><div><span>echo</span><span> </span><span>"部署完成！访问 https://lycaonide.github.io 查看效果"</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>代理说明：仅在部署到 GitHub 时需要配置代理，本地预览（<code>hexo s</code>）无需代理。</p><p> </p></section></section>
<section><h4>五、验证线上效果<a href="#五验证线上效果"><span>#</span></a></h4><p>等待 1–3 分钟后，打开浏览器访问 <code>https://lycaonide.github.io</code>，刷新页面后即可看到新发布/修改的博客文章出现在文章列表中。</p></section>]]></content>
    </entry>
    <entry>
      <id>https://lycaonide.github.io/posts/ros2%E7%9B%AE%E6%A0%87%E6%A3%80%E6%B5%8B%E5%8A%9F%E8%83%BD%E5%8C%85%E6%93%8D%E4%BD%9C%E8%BF%87%E7%A8%8B/</id>
      <title type="text">ROS2目标检测功能包操作过程</title>
      <published>2026-03-25T00:00:00.000Z</published>
      <updated>2026-03-25T00:00:00.000Z</updated>
      <author><name>lycaonide</name></author>
      <link rel="alternate" href="https://lycaonide.github.io/posts/ros2%E7%9B%AE%E6%A0%87%E6%A3%80%E6%B5%8B%E5%8A%9F%E8%83%BD%E5%8C%85%E6%93%8D%E4%BD%9C%E8%BF%87%E7%A8%8B/"/>
      <summary type="text"></summary>
      <content type="html"><![CDATA[<section><h4>一、远程传输所有工程文件到虚拟机工作空间<a href="#一远程传输所有工程文件到虚拟机工作空间"><span>#</span></a></h4><p>将 <code>object_detect_service</code>、<code>msg_srv</code> 功能包传输至虚拟机 <code>~/first_ws/src/</code> 目录。</p></section>
<section><h4>二、编写 <code>camera_node.py</code> 和 <code>detect_node.py</code>，在 <code>setup.py</code> 中注册节点<a href="#二编写-camera_nodepy-和-detect_nodepy在-setuppy-中注册节点"><span>#</span></a></h4><ul>
<li>
<p><strong><code>camera_node.py</code></strong>：实现等待目标检测服务、打开摄像头、读取图像帧、调用服务、显示图像的功能。</p>
</li>
<li>
<p><strong><code>detect_node.py</code></strong>：实现提供目标检测服务、接收图像请求、运行 MediaPipe 检测、返回结果的功能。</p>
</li>
<li>
<p><strong><code>setup.py</code> 配置 <code>entry_points</code></strong>：</p>
<div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span>entry_points</span><span>=</span><span>{</span></span></div></div><div><div><div>2</div></div><div><span>    </span><span>'console_scripts'</span><span>: [</span></div></div><div><div><div>3</div></div><div><span>        </span><span>'camera_node = object_detect_service.camera_node:main'</span><span>,</span></div></div><div><div><div>4</div></div><div><span>        </span><span>'detect_node = object_detect_service.detect_node:main'</span><span>,</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>],</span></div></div><div><div><div>6</div></div><div><span>},</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
</ul></section>
<section><h4>三、安装依赖<a href="#三安装依赖"><span>#</span></a></h4><p>在终端依次执行以下命令，安装指定版本依赖库：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>pip</span><span> </span><span>install</span><span> </span><span>"numpy&lt;2.0"</span></div></div><div><div><div>2</div></div><div><span>pip</span><span> </span><span>install</span><span> </span><span>"opencv-python==4.10.0.84"</span><span> </span><span>"opencv-contrib-python==4.10.0.84"</span></div></div><div><div><div>3</div></div><div><span>pip</span><span> </span><span>install</span><span> </span><span>mediapipe</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section>
<section><h4>四、安装摄像头测试工具<a href="#四安装摄像头测试工具"><span>#</span></a></h4><p>执行命令安装 <code>cheese</code> 摄像头硬件测试工具：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>sudo</span><span> </span><span>apt</span><span> </span><span>update</span></div></div><div><div><div>2</div></div><div><span>sudo</span><span> </span><span>apt</span><span> </span><span>install</span><span> </span><span>cheese</span><span> </span><span>-y</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section>
<section><h4>五、编译功能包<a href="#五编译功能包"><span>#</span></a></h4><p>进入工作空间根目录，先编译消息服务包，再编译目标检测功能包：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>cd</span><span> </span><span>~/first_ws</span></div></div><div><div><div>2</div></div><div><span>colcon</span><span> </span><span>build</span><span> </span><span>--packages-select</span><span> </span><span>msg_srv</span></div></div><div><div><div>3</div></div><div><span>colcon</span><span> </span><span>build</span><span> </span><span>--packages-select</span><span> </span><span>object_detect_service</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section>
<section><h4>六、加载环境变量<a href="#六加载环境变量"><span>#</span></a></h4><p>每次新开终端，均需执行以下命令加载编译后的环境变量：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>source</span><span> </span><span>install/setup.bash</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section>
<section><h4>七、配置虚拟机 USB 兼容性与摄像头连接<a href="#七配置虚拟机-usb-兼容性与摄像头连接"><span>#</span></a></h4><section><h5>7.1 初次测试摄像头（失败）<a href="#71-初次测试摄像头失败"><span>#</span></a></h5><p>连接摄像头后，授予权限：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>sudo</span><span> </span><span>chmod</span><span> </span><span>777</span><span> </span><span>/dev/video</span><span>*</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>使用 <code>cheese</code> 测试：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>source</span><span> </span><span>install/setup.bash</span></div></div><div><div><div>2</div></div><div><span>cheese</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>（此时 <code>cheese</code> 未成功弹出画面，且终端出现大量 <code>select() timeout</code> 警告）</p></section><section><h5>7.2 解决警告：修改 USB 兼容性<a href="#72-解决警告修改-usb-兼容性"><span>#</span></a></h5><p>因虚拟机摄像头兼容性问题导致终端警告，修改 USB 设置：</p><ol>
<li>关闭虚拟机</li>
<li>打开 VMware 虚拟机设置 → USB 控制器</li>
<li>将 USB 兼容性选择为 <strong>USB 3.1</strong>，保存设置后启动虚拟机</li>
<li>重新连接摄像头：虚拟机菜单栏 → 可移动设备 → 选择摄像头 → 连接</li>
</ol></section><section><h5>7.3 再次测试摄像头（意外成功）<a href="#73-再次测试摄像头意外成功"><span>#</span></a></h5><p>再次执行 <code>cheese</code> 测试：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>source</span><span> </span><span>install/setup.bash</span></div></div><div><div><div>2</div></div><div><span>cheese</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>（此时 <code>cheese</code> 成功弹出摄像头实时画面，硬件连接与警告问题解决）</p></section></section>
<section><h4>八、改进：修改 <code>camera_node.py</code> 代码适配虚拟机环境<a href="#八改进修改-camera_nodepy-代码适配虚拟机环境"><span>#</span></a></h4><section><h5>8.1 关键修改：指定 V4L 后端<a href="#81-关键修改指定-v4l-后端"><span>#</span></a></h5><p>在 <code>camera_node.py</code> 中修改摄像头初始化代码，指定 V4L 后端适配虚拟机：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span># 原代码：self.cap = cv2.VideoCapture(0)</span></div></div><div><div><div>2</div></div><div><span># 【关键改动】添加 cv2.CAP_V4L 后端，设备号根据实际情况修改</span></div></div><div><div><div>3</div></div><div><span>self</span><span><span>.cap </span><span>=</span><span> cv2.</span><span>VideoCapture</span><span>(</span></span><span>0</span><span><span> </span><span>+</span><span> cv2.</span><span>CAP_V4L</span><span>)</span></span></div></div><div><div><div>4</div></div><div><span>if</span><span> </span><span>not</span><span> </span><span>self</span><span><span>.cap.</span><span>isOpened</span><span>():</span></span></div></div><div><div><div>5</div></div><div><span>    </span><span>self</span><span><span>.</span><span>get_logger</span><span>().</span><span>error</span><span>(</span></span><span>"无法打开摄像头"</span><span>)</span></div></div><div><div><div>6</div></div><div><span>    </span><span>return</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h5>8.2 简化版自动遍历（可选，应对设备号变化）<a href="#82-简化版自动遍历可选应对设备号变化"><span>#</span></a></h5><p>若设备号频繁变化，在 <code>camera_node.py</code> 中添加简化遍历逻辑：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span># 【关键改动】自动遍历 /dev/video* 设备，配合 V4L 后端</span></div></div><div><div><div>2</div></div><div><span>import</span><span> glob</span></div></div><div><div><div>3</div></div><div><span>self</span><span><span>.cap </span><span>=</span><span> </span></span><span>None</span></div></div><div><div><div>4</div></div><div><span>for</span><span> dev </span><span>in</span><span><span> glob.</span><span>glob</span><span>(</span></span><span>"/dev/video*"</span><span>):</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>dev_id </span><span>=</span><span> </span><span>int</span><span><span>(dev.</span><span>replace</span><span>(</span></span><span>"/dev/video"</span><span>, </span><span>""</span><span>))</span></div></div><div><div><div>6</div></div><div><span>    </span><span>self</span><span><span>.cap </span><span>=</span><span> cv2.</span><span>VideoCapture</span><span>(dev_id </span><span>+</span><span> cv2.</span><span>CAP_V4L</span><span>)</span></span></div></div><div><div><div>7</div></div><div><span>    </span><span>if</span><span> </span><span>self</span><span><span>.cap.</span><span>isOpened</span><span>():</span></span></div></div><div><div><div>8</div></div><div><span>        </span><span>break</span></div></div><div><div><div>9</div></div><div><span>if</span><span> </span><span>not</span><span> </span><span>self</span><span>.cap </span><span>or</span><span> </span><span>not</span><span> </span><span>self</span><span><span>.cap.</span><span>isOpened</span><span>():</span></span></div></div><div><div><div>10</div></div><div><span>    </span><span>self</span><span><span>.</span><span>get_logger</span><span>().</span><span>error</span><span>(</span></span><span>"无法打开摄像头"</span><span>)</span></div></div><div><div><div>11</div></div><div><span>    </span><span>return</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>重新编译：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>colcon</span><span> </span><span>build</span><span> </span><span>--packages-select</span><span> </span><span>object_detect_service</span></div></div><div><div><div>2</div></div><div><span>source</span><span> </span><span>install/setup.bash</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section></section>
<section><h4>九、解决 Qt 平台插件报错<a href="#九解决-qt-平台插件报错"><span>#</span></a></h4><p>启动 <code>camera_node</code> 时出现 <code>qt.qpa.xcb: could not connect to display</code> 错误，可选择以下两种方式之一解决：</p><section><h5>方式一：终端临时设置环境变量（推荐，不修改代码）<a href="#方式一终端临时设置环境变量推荐不修改代码"><span>#</span></a></h5><p>在启动 <code>camera_node</code> 前执行：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>export</span><span> </span><span>DISPLAY</span><span><span>=</span><span>:</span></span><span>0</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>此方式仅对当前终端生效，新开终端需重新执行。</p></section><section><h5>方式二：代码层面禁用 GUI（永久解决，无需手动设置）<a href="#方式二代码层面禁用-gui永久解决无需手动设置"><span>#</span></a></h5><p>在 <code>camera_node.py</code> 文件最顶部添加代码，强制 Qt 运行在无头模式，避免图形界面依赖：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>import</span><span> os</span></div></div><div><div><div>2</div></div><div><span># 【关键改动】禁用 Qt GUI，彻底解决 display 连接问题</span></div></div><div><div><div>3</div></div><div><span>os.environ[</span><span>"QT_QPA_PLATFORM"</span><span><span>] </span><span>=</span><span> </span></span><span>"offscreen"</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>修改后重新编译：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>colcon</span><span> </span><span>build</span><span> </span><span>--packages-select</span><span> </span><span>object_detect_service</span></div></div><div><div><div>2</div></div><div><span>source</span><span> </span><span>install/setup.bash</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section></section>
<section><h4>十、节点启动顺序（关键）<a href="#十节点启动顺序关键"><span>#</span></a></h4><section><h5>10.1 启动 <code>detect_node</code>（服务端）<a href="#101-启动-detect_node服务端"><span>#</span></a></h5><p>新开终端，执行：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>source</span><span> </span><span>install/setup.bash</span></div></div><div><div><div>2</div></div><div><span>ros2</span><span> </span><span>run</span><span> </span><span>object_detect_service</span><span> </span><span>detect_node</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>服务端启动后无输出或打印「检测服务已启动」日志，代表服务正常运行。</p></section><section><h5>10.2 启动 <code>camera_node</code>（客户端）<a href="#102-启动-camera_node客户端"><span>#</span></a></h5><ul>
<li>
<p>若使用<strong>方式一</strong>：</p>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>source</span><span> </span><span>install/setup.bash</span></div></div><div><div><div>2</div></div><div><span>export</span><span> </span><span>DISPLAY</span><span><span>=</span><span>:</span></span><span>0</span></div></div><div><div><div>3</div></div><div><span>ros2</span><span> </span><span>run</span><span> </span><span>object_detect_service</span><span> </span><span>camera_node</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li>
<p>若使用<strong>方式二</strong>：</p>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>source</span><span> </span><span>install/setup.bash</span></div></div><div><div><div>2</div></div><div><span>ros2</span><span> </span><span>run</span><span> </span><span>object_detect_service</span><span> </span><span>camera_node</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
<p>客户端启动后：</p>
</li>
<li>
<p>若服务未上线，循环打印「服务未上线，正在等待…」</p>
</li>
<li>
<p>服务上线后，打开摄像头（使用 V4L 后端），弹出 <code>frame</code> 窗口显示实时画面，开始采集图像并调用检测服务</p>
</li>
</ul></section></section>
<section><h4>十一、结果<a href="#十一结果"><span>#</span></a></h4><p>（一开始 <code>cheese</code> 未成功，且终端出现 <code>select() timeout</code> 警告；修改 USB 兼容性为 3.1 后，再次用 <code>cheese</code> 测试意外成功弹出画面）</p><ul>
<li><code>detect_node</code> 服务后台稳定运行，<code>camera_node</code> 成功连接服务并打开摄像头</li>
<li>弹出 <code>frame</code> 窗口显示实时画面，完成「服务等待 → 图像采集 → 服务调用 → 图像显示」完整流程</li>
</ul></section>]]></content>
    </entry>
    <entry>
      <id>https://lycaonide.github.io/posts/%E5%AD%A6%E4%B9%A0%E7%94%A8hexo%E5%86%99%E5%8D%9A%E5%AE%A2/</id>
      <title type="text">学习用Hexo写博客</title>
      <published>2026-01-25T00:00:00.000Z</published>
      <updated>2026-01-25T00:00:00.000Z</updated>
      <author><name>lycaonide</name></author>
      <link rel="alternate" href="https://lycaonide.github.io/posts/%E5%AD%A6%E4%B9%A0%E7%94%A8hexo%E5%86%99%E5%8D%9A%E5%AE%A2/"/>
      <summary type="text"></summary>
      <content type="html"><![CDATA[<section><h4>一、前置工具安装<a href="#一前置工具安装"><span>#</span></a></h4><section><h5>1. 安装Node.js<a href="#1-安装nodejs"><span>#</span></a></h5><ul>
<li><strong>操作</strong>：
<ol>
<li>打开<a href="https://nodejs.org/" target="_blank">Node.js官网</a>，点击对应Windows版本的安装包（如“Windows Installer (.msi) 64-bit”）；</li>
<li>双击安装包，勾选“Accept the terms…”，点击“Next”；</li>
<li>安装路径保持默认（或自定义，需记住路径），点击“Next”；</li>
<li>勾选“Add to PATH”（自动配置环境变量），点击“Next”→“Install”→“Finish”。</li>
</ol>
</li>
<li><strong>验证</strong>：
右键桌面→选择“Git Bash Here”打开终端，输入<code>node -v</code>，我安装的是v.24.5.0版本。</li>
</ul></section><section><h5>2. 安装Git<a href="#2-安装git"><span>#</span></a></h5><ul>
<li>
<p><strong>操作</strong>：</p>
<ol>
<li>打开<a href="https://git-scm.com/" target="_blank">Git官网</a>，点击“Download for Windows”；</li>
<li>双击安装包，依次点击“Next”；</li>
<li>安装路径保持默认，点击“Next”；</li>
<li>组件选择默认（需包含“Git Bash Here”），点击“Next”；</li>
<li>开始菜单文件夹保持默认，点击“Next”；</li>
<li>选择“Use Visual Studio Code as Git’s default editor”（或默认编辑器），点击“Next”；</li>
<li>选择“Let Git decide”（换行符处理），点击“Next”→“Next”→“Next”；</li>
<li>选择“Use Windows’ default console window”，点击“Next”→“Install”→“Finish”。</li>
</ol>
</li>
<li>
<p><strong>验证</strong>：
右键桌面→选择“Git Bash Here”，输入<code>git -v</code>，若显示版本号（如<code>git version 2.43.0.windows.1</code>）则成功。</p>
</li>
<li>
<p><strong>必做配置</strong>：
在Git Bash中输入以下命令，绑定Git与GitHub的身份：</p>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>git</span><span> </span><span>config</span><span> </span><span>--global</span><span> </span><span>user.name</span><span> </span><span>"你的GitHub用户名"</span><span>  </span><span># 如"lycaonide"</span></div></div><div><div><div>2</div></div><div><span>git</span><span> </span><span>config</span><span> </span><span>--global</span><span> </span><span>user.email</span><span> </span><span>"你的GitHub注册邮箱"</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
</ul></section><section><h5>3. 注册并登录GitHub<a href="#3-注册并登录github"><span>#</span></a></h5><ul>
<li><strong>操作</strong>：
<ol>
<li>打开<a href="https://github.com/" target="_blank">GitHub官网</a>，点击“Sign up”；</li>
<li>输入邮箱→创建密码→输入用户名（需记住，后续仓库名要用）→完成验证；</li>
<li>登录后，进入GitHub主页。</li>
</ol>
</li>
</ul></section></section>
<section><h4>二、初始化Hexo博客（本地可预览）<a href="#二初始化hexo博客本地可预览"><span>#</span></a></h4><section><h5>1. 创建本地Hexo项目<a href="#1-创建本地hexo项目"><span>#</span></a></h5><ul>
<li>
<p><strong>操作</strong>：</p>
<ol>
<li>右键桌面→选择“Git Bash Here”；</li>
<li>输入命令安装Hexo脚手架（全局工具）：
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>npm</span><span> </span><span>install</span><span> </span><span>-g</span><span> </span><span>hexo-cli</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
（等待终端显示“added xx packages in xx s”即安装完成）</li>
<li>输入命令在桌面创建Hexo项目（项目名自定义，这里用<code>my-hexo-blog</code>）：
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>hexo</span><span> </span><span>init</span><span> </span><span>my-hexo-blog</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
（等待终端显示“Start blogging with Hexo!”即初始化完成）</li>
<li>进入项目目录并安装依赖：
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>cd</span><span> </span><span>my-hexo-blog</span><span>  </span><span># 进入项目文件夹</span></div></div><div><div><div>2</div></div><div><span>npm</span><span> </span><span>install</span><span>      </span><span># 安装项目依赖</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
</ol>
</li>
</ul></section><section><h5>2. 本地预览博客（确保本地能正常运行）<a href="#2-本地预览博客确保本地能正常运行"><span>#</span></a></h5><ul>
<li><strong>操作</strong>：
在Git Bash的<code>my-hexo-blog</code>目录下，输入：
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>hexo</span><span> </span><span>server</span><span>  </span><span># 可简写为 hexo s</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li><strong>反馈</strong>：
终端显示“Hexo is running at <a href="http://localhost:4000" target="_blank">http://localhost:4000</a> . Press Ctrl+C to stop.”。</li>
<li><strong>验证</strong>：
打开浏览器，输入<code>http://localhost:4000</code>，若显示Hexo默认博客页面（白色背景、“Hello World”文章）则本地运行成功。</li>
<li><strong>关闭预览</strong>：
在Git Bash中按<code>Ctrl+C</code>终止服务。</li>
</ul></section></section>
<section><h4>三、创建GitHub Pages专属仓库<a href="#三创建github-pages专属仓库"><span>#</span></a></h4><ul>
<li><strong>操作</strong>：
<ol>
<li>登录GitHub后，点击页面右上角“+”图标→选择“New repository”；</li>
<li>在“Repository name”输入框中，必须填写：<code>你的GitHub用户名.github.io</code>（例如你的用户名为<code>lycaonide</code>，则填写<code>lycaonide.github.io</code>）；</li>
<li>“Visibility”选择“Public”（GitHub Pages仅支持公开仓库，若为付费用户可选Private）；</li>
<li>不要勾选“Add a README file”“Add .gitignore”等选项（Hexo会自动生成文件）；</li>
<li>点击页面最下方的“Create repository”按钮。</li>
</ol>
</li>
<li><strong>验证</strong>：
仓库创建后，页面顶部会显示仓库名<code>lycaonide.github.io</code>，且代码区域为空（后续部署会自动上传文件）。</li>
</ul></section>
<section><h4>四、配置Hexo的部署信息（关联本地与GitHub）<a href="#四配置hexo的部署信息关联本地与github"><span>#</span></a></h4><section><h5>1. 打开Hexo的配置文件<a href="#1-打开hexo的配置文件"><span>#</span></a></h5><ul>
<li><strong>操作</strong>：
<ol>
<li>打开桌面的<code>my-hexo-blog</code>文件夹→找到<code>_config.yml</code>文件。</li>
<li>右键点击“用记事本编辑”。</li>
</ol>
</li>
</ul></section><section><h5>2. 修改部署配置<a href="#2-修改部署配置"><span>#</span></a></h5><ul>
<li>
<p><strong>操作</strong>：
滚动到<code>_config.yml</code>文件的<strong>末尾</strong>，找到<code>deploy</code>段落（默认可能是注释状态），修改为：</p>
<div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>deploy</span><span>:</span></div></div><div><div><div>2</div></div><div><span>  </span><span>type</span><span>: </span><span>git</span></div></div><div><div><div>3</div></div><div><span>  </span><span>repo</span><span>: </span><span>git@github.com:lycaonide/lycaonide.github.io.git</span><span>  </span><span># 替换为你的仓库SSH地址</span></div></div><div><div><div>4</div></div><div><span>  </span><span>branch</span><span>: </span><span>main</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li>
<p><strong>关键说明</strong>：</p>
<ul>
<li><code>repo</code>地址获取：进入GitHub仓库页面→点击“Code”按钮→选择“SSH”→复制地址（以<code>git@github.com:</code>开头）；</li>
<li><strong>缩进要求</strong>：<code>type</code>、<code>repo</code>、<code>branch</code>必须与<code>deploy</code>保持<strong>2个空格的缩进</strong>（YAML语法不支持Tab，必须用空格）。</li>
</ul>
</li>
</ul></section></section>
<section><h4>五、配置SSH密钥（解决GitHub访问权限问题）<a href="#五配置ssh密钥解决github访问权限问题"><span>#</span></a></h4><ul>
<li>
<p><strong>操作</strong>：</p>
<ol>
<li>在Git Bash的<code>my-hexo-blog</code>目录下，输入命令生成SSH密钥（替换为你的GitHub邮箱）：
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>ssh-keygen</span><span> </span><span>-t</span><span> </span><span>ed25519</span><span> </span><span>-C</span><span> </span><span>"你的GitHub注册邮箱"</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
（连续按3次回车，使用默认路径和空密码）</li>
<li>输入命令复制密钥内容：
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>cat</span><span> </span><span>~/.ssh/id_ed25519.pub</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
（终端会显示一长串以“ssh-ed25519”开头、你的邮箱结尾的字符串，全选复制）</li>
<li>登录GitHub→点击页面右上角“头像”→选择“Settings”；</li>
<li>左侧菜单选择“SSH and GPG keys”→点击“New SSH key”；</li>
<li>“Title”填写自定义名称（如“我的Windows电脑”），“Key”粘贴刚才复制的密钥字符串；</li>
<li>点击“Add SSH key”。</li>
</ol>
</li>
<li>
<p><strong>验证</strong>：
在Git Bash中输入：</p>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>ssh</span><span> </span><span>-T</span><span> </span><span>git@github.com</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
<p>终端显示“Hi lycaonide! You’ve successfully authenticated…”即密钥配置成功。</p>
</li>
</ul></section>
<section><h4>六、安装Hexo部署插件<a href="#六安装hexo部署插件"><span>#</span></a></h4><ul>
<li><strong>操作</strong>：
在Git Bash的<code>my-hexo-blog</code>目录下，输入：
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>npm</span><span> </span><span>install</span><span> </span><span>hexo-deployer-git</span><span> </span><span>--save</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li><strong>验证</strong>：
查看项目目录下的<code>node_modules</code>文件夹，若存在<code>hexo-deployer-git</code>文件夹则安装成功。</li>
</ul></section>
<section><h4>七、执行博客部署<a href="#七执行博客部署"><span>#</span></a></h4><ul>
<li>
<p><strong>操作1：清理本地缓存</strong>
在Git Bash中输入：</p>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>hexo</span><span> </span><span>clean</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
<p>（终端显示“INFO Deleted database.”“INFO Deleted public folder.”即清理完成）</p>
</li>
<li>
<p><strong>操作2：生成静态文件</strong>
输入：</p>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>hexo</span><span> </span><span>generate</span><span>  </span><span># 可简写为 hexo g</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
<p>（终端显示“INFO Generated: xxx.html”等信息，项目目录会生成<code>public</code>文件夹，里面是博客的静态文件）</p>
</li>
<li>
<p><strong>操作3：部署到GitHub</strong>
输入：</p>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>hexo</span><span> </span><span>deploy</span><span>  </span><span># 可简写为 hexo d</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li>
<p><strong>反馈</strong>：
终端显示“INFO Deploy done: git”，且中间会显示Git推送记录（如“To github.com/lycaonide.github.io.git”）。</p>
</li>
</ul></section>
<section><h4>八、验证部署结果（确认博客在线）<a href="#八验证部署结果确认博客在线"><span>#</span></a></h4><ol>
<li>
<p><strong>查看GitHub仓库文件</strong>：
进入<code>lycaonide.github.io</code>仓库页面，代码区域会显示<code>public</code>文件夹中的文件（如<code>index.html</code>、<code>css</code>文件夹），说明文件已成功上传。</p>
</li>
<li>
<p><strong>访问博客网址</strong>：
打开浏览器，输入<code>https://lycaonide.github.io</code>（注意：需等待1-3分钟，GitHub Pages需要同步文件），若显示与本地预览一致的博客页面，则部署成功。</p>
</li>
<li>
<p><strong>若页面无法访问</strong>：
进入仓库→点击“Settings”→左侧选择“Pages”→确认“Source”选择的是<code>main</code>分支 + <code>/(root)</code>目录，若显示“Your site is published at <a href="https://lycaonide.github.io">https://lycaonide.github.io</a>”则状态正常，重新等待同步即可。</p>
</li>
</ol></section>
<section><h4>九、博客发布步骤<a href="#九博客发布步骤"><span>#</span></a></h4><section><h5>1.  新建博客文章<a href="#1--新建博客文章"><span>#</span></a></h5><ul>
<li>
<p><strong>操作</strong>：
打开Git Bash，进入Hexo项目目录（如桌面的<code>my-hexo-blog</code>）：</p>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>cd</span><span> </span><span>~/Desktop/my-hexo-blog</span><span>  </span><span># 替换为你的Hexo项目路径</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
<p>输入命令新建文章，替换为你的博客标题：</p>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>hexo</span><span> </span><span>new</span><span> </span><span>"我的第一篇Hexo博客"</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li>
<p><strong>反馈</strong>：
终端显示“INFO Created: source/_posts/我的第一篇Hexo博客.md”，表示文章文件已生成。</p>
</li>
<li>
<p><strong>文件位置</strong>：
文章存放在Hexo项目的<code>source/_posts/</code>目录下，文件名是<code>我的第一篇Hexo博客.md</code>。</p>
</li>
</ul></section><section><h5>2. 编辑博客内容<a href="#2-编辑博客内容"><span>#</span></a></h5><ul>
<li><strong>操作</strong></li>
</ul><p>​	打开文章文件：用任意Markdown编辑器打开<code>source/_posts/我的第一篇Hexo博客.md</code>文件。</p><p>​	配置文章信息：文件开头的“Front-matter”是Hexo识别文章属性的区域（必须保留），示例说明：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>---</span></div></div><div><div><div>2</div></div><div><span>title</span><span>: </span><span>我的第一篇Hexo博客</span><span>  </span><span># 博客标题（会显示在页面顶部）</span></div></div><div><div><div>3</div></div><div><span>date</span><span>: </span><span>2026-01-25 10:00:00</span><span>  </span><span># 发布日期（自动生成，可修改）</span></div></div><div><div><div>4</div></div><div><span>tags</span><span>: [</span><span>Hexo</span><span>, </span><span>博客</span><span>]  </span><span># 文章标签（多个标签用数组包裹）</span></div></div><div><div><div>5</div></div><div><span>categories</span><span>: </span><span>技术笔记</span><span>  </span><span># 文章分类（可自定义分类名）</span></div></div><div><div><div>6</div></div><div><span>---</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>​	说明：格式必须严格（冒号后加空格），否则Hexo会解析失败。</p><p>​	编写正文内容（Markdown语法）：在<code>---</code>下方编写博客正文，示例：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span># 一级标题</span></div></div><div><div><div>2</div></div><div><span>这是我的第一篇Hexo博客，终于成功部署啦！</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span>## 二级标题：Hexo的优点</span></div></div><div><div><div>5</div></div><div><span><span>-</span><span> 轻量化，部署简单</span></span></div></div><div><div><div>6</div></div><div><span><span>-</span><span> 支持Markdown编辑，写作体验好</span></span></div></div><div><div><div>7</div></div><div><span><span>-</span><span> 可自定义主题（后续会分享主题更换方法）</span></span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span>### 三级标题：插入图片</span></div></div><div><div><div>10</div></div><div><span>把图片放到Hexo项目的</span><span><span>`</span><span>source/images/</span><span>`</span></span><span>目录下，引用方式：</span></div></div><div><div><div>11</div></div><div><span>![</span><span>示例图片</span><span>]</span><span><span>(</span><span>/images/我的图片.jpg</span><span>)</span></span><span>  # 路径从public目录根开始</span></div></div><div><div><div>12</div></div><div>
</div></div><div><div><div>13</div></div><div><span>### 三级标题：添加链接</span></div></div><div><div><div>14</div></div><div><span>推荐Hexo官网：</span><span>[</span><span>Hexo官方文档</span><span>]</span><span><span>(</span><span>https://hexo.io/zh-cn/docs/</span><span>)</span></span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h5>3. 本地预览博客效果<a href="#3-本地预览博客效果"><span>#</span></a></h5><ul>
<li>
<p><strong>操作</strong>：
在Git Bash的Hexo项目目录下，输入命令启动本地服务：</p>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>hexo</span><span> </span><span>clean</span><span>  </span><span># 先清理旧缓存（可选，但建议执行）</span></div></div><div><div><div>2</div></div><div><span>hexo</span><span> </span><span>s</span><span>      </span><span># 启动本地预览</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li>
<p><strong>验证</strong>：
打开浏览器访问<code>http://localhost:4000</code>，在“文章”列表中找到《我的第一篇Hexo博客》，点击进入查看格式、图片、链接是否正常显示。</p>
</li>
<li>
<p><strong>关闭预览</strong>：
在Git Bash中按<code>Ctrl+C</code>终止服务。</p>
</li>
</ul></section><section><h5>4. 发布新博客到线上<a href="#4-发布新博客到线上"><span>#</span></a></h5><ul>
<li>
<p><strong>操作</strong>：
在Git Bash的Hexo项目目录下，依次执行命令（更新线上博客）：</p>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>hexo</span><span> </span><span>clean</span><span>  </span><span># 清理本地缓存</span></div></div><div><div><div>2</div></div><div><span>hexo</span><span> </span><span>g</span><span>      </span><span># 重新生成包含新文章的静态文件</span></div></div><div><div><div>3</div></div><div><span>hexo</span><span> </span><span>d</span><span>      </span><span># 部署到GitHub仓库</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li>
<p><strong>反馈</strong>：
终端显示“INFO Deploy done: git”即部署完成。</p>
</li>
</ul></section><section><h5>五、验证线上效果<a href="#五验证线上效果"><span>#</span></a></h5><p>等待1-3分钟后，打开浏览器访问<code>https://lycaonide.github.io</code>，刷新页面后即可看到新发布的《我的第一篇Hexo博客》出现在文章列表中。</p></section><section><h5>补充注意事项<a href="#补充注意事项"><span>#</span></a></h5><ol>
<li><strong>图片存放</strong>：博客中用到的图片，需放到Hexo项目的<code>source/images/</code>目录下，引用路径写<code>/images/图片名.jpg</code>（Hexo会自动将<code>source/images</code>映射到网站根目录）；</li>
<li><strong>修改已发布文章</strong>：直接编辑<code>source/_posts/</code>下对应的MD文件，重复“本地预览→hexo clean→hexo g→hexo d”步骤即可更新线上内容；</li>
<li><strong>删除文章</strong>：删除<code>source/_posts/</code>下对应的MD文件，再执行部署命令，线上文章会同步删除。</li>
</ol></section></section>]]></content>
    </entry>
    <entry>
      <id>https://lycaonide.github.io/posts/worldmem%E9%A1%B9%E7%9B%AE%E9%83%A8%E7%BD%B2%E8%AE%B0%E5%BD%95/</id>
      <title type="text">WorldMem项目部署记录</title>
      <published>2026-01-24T00:00:00.000Z</published>
      <updated>2026-01-24T00:00:00.000Z</updated>
      <author><name>lycaonide</name></author>
      <link rel="alternate" href="https://lycaonide.github.io/posts/worldmem%E9%A1%B9%E7%9B%AE%E9%83%A8%E7%BD%B2%E8%AE%B0%E5%BD%95/"/>
      <summary type="text"></summary>
      <content type="html"><![CDATA[<section><h4>一、环境与工具准备<a href="#一环境与工具准备"><span>#</span></a></h4><ol>
<li>安装Anaconda/Miniconda：官网下载默认路径安装，自动配置环境变量。</li>
<li>安装Git：下载Git for Windows，勾选「Git Bash Here」选项（确保Git Bash支持<code>wget</code>命令，后续统一用Git Bash操作）。</li>
<li>创建Conda环境：打开Anaconda Prompt，执行以下命令创建专属环境（避免依赖冲突）：
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>conda</span><span> </span><span>create</span><span> </span><span>-n</span><span> </span><span>worldmem</span><span> </span><span>python=</span><span>3.10</span><span> </span><span>-y</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li>激活Conda环境（Anaconda Prompt中）：
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>conda</span><span> </span><span>activate</span><span> </span><span>worldmem</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li>安装带CUDA的PyTorch（核心依赖，GPU加速必备）：
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>pip</span><span> </span><span>uninstall</span><span> </span><span>torch</span><span> </span><span>torchvision</span><span> </span><span>torchaudio</span><span> </span><span>-y</span><span>  </span><span># 卸载可能存在的CPU版本</span></div></div><div><div><div>2</div></div><div><span>pip3</span><span> </span><span>install</span><span> </span><span>torch</span><span> </span><span>torchvision</span><span> </span><span>torchaudio</span><span> </span><span>--index-url</span><span> </span><span>https://download.pytorch.org/whl/cu118</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li>验证CUDA生效：执行以下命令，输出<code>True</code>说明GPU适配成功：
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>python</span><span> </span><span>-c</span><span> </span><span>"import torch; print(torch.cuda.is_available())"</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li>Git克隆项目代码：打开Git Bash（右键桌面→「Git Bash Here」），执行克隆命令：
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>cd</span><span> </span><span>/c/Users/13062/Desktop</span><span>  </span><span># 切换到桌面目录</span></div></div><div><div><div>2</div></div><div><span>git</span><span> </span><span>clone</span><span> </span><span>https://github.com/zeqixiao/worldmem-video-demo.git</span><span>  </span><span># 克隆项目</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
克隆后项目路径：<code>C:\Users\13062\Desktop\worldmem-video-demo\WorldMem</code>（后续所有操作均基于此路径）。</li>
</ol></section>
<section><h4>二、Git Bash配置Conda环境（统一终端+激活环境）<a href="#二git-bash配置conda环境统一终端激活环境"><span>#</span></a></h4><blockquote><p>提示：所有后续操作（安装依赖、下载资源、执行脚本）均需在<code>worldmem</code>环境中进行，Git Bash默认不支持Conda激活，必须先配置，否则依赖安装、命令执行都会失效。</p></blockquote><ol>
<li>配置Git Bash加载Conda脚本：
<ul>
<li>右键项目文件夹（<code>worldmem-video-demo\WorldMem</code>）→「Git Bash Here」，打开Git Bash终端；</li>
<li>执行以下命令创建并编辑配置文件：
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>touch</span><span> </span><span>~/.bashrc</span><span>  </span><span># 创建Conda配置文件</span></div></div><div><div><div>2</div></div><div><span>nano</span><span> </span><span>~/.bashrc</span><span>    </span><span># 打开编辑器</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li>在编辑器中粘贴以下内容（Conda脚本默认路径，若Anaconda安装路径修改需对应调整）：
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>source</span><span> </span><span>/c/Users/13062/anaconda3/etc/profile.d/conda.sh</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li>保存退出：按<code>Ctrl+O</code>→回车确认文件名→按<code>Ctrl+X</code>退出编辑器。</li>
</ul>
</li>
<li>生效配置并激活<code>worldmem</code>环境：
<ul>
<li>执行以下命令加载配置：
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>source</span><span> </span><span>~/.bashrc</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li>激活<code>worldmem</code>环境（终端开头显示<code>(worldmem)</code>即成功）：
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>conda</span><span> </span><span>activate</span><span> </span><span>worldmem</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li>验证环境：执行<code>python --version</code>，输出<code>Python 3.10.x</code>（与创建环境时指定版本一致），说明环境配置完成。</li>
</ul>
</li>
</ol></section>
<section><h4>三、项目依赖安装（Conda环境内统一执行）<a href="#三项目依赖安装conda环境内统一执行"><span>#</span></a></h4><blockquote><p>前置条件：已在Git Bash中激活<code>worldmem</code>环境，所有依赖均安装在该环境内，不影响系统Python。</p></blockquote><ol>
<li>
<p>切换到项目根目录：</p>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>cd</span><span> </span><span>/c/Users/13062/Desktop/worldmem-video-demo/WorldMem</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li>
<p>安装项目依赖：</p>
<ul>
<li>先安装<code>requirements.txt</code>（若项目包含该文件，一次性安装基础依赖）：</li>
</ul>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>pip</span><span> </span><span>install</span><span> </span><span>-r</span><span> </span><span>requirements.txt</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
<ul>
<li>按报错补充缺失依赖（运行项目时若提示「ModuleNotFoundError」，逐个安装以下核心依赖）：
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>pip</span><span> </span><span>install</span><span> </span><span>hydra-core</span><span> </span><span>lpips</span><span> </span><span>gradio</span><span> </span><span>wandb</span><span>  </span><span># 核心功能依赖</span></div></div><div><div><div>2</div></div><div><span>pip</span><span> </span><span>install</span><span> </span><span>torchvision</span><span> </span><span>pillow</span><span> </span><span>numpy</span><span> </span><span>scipy</span><span> </span><span>opencv-python</span><span>  </span><span># 数据处理依赖</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
</ul>
</li>
<li>
<p>验证依赖安装：执行<code>pip list | grep gradio</code>（或其他依赖名），能看到对应版本即安装成功。</p>
</li>
</ol></section>
<section><h4>四、本地资源准备+代码修改<a href="#四本地资源准备代码修改"><span>#</span></a></h4><section><h5>1. 镜像站下载案例文件（<code>case1.npz~case4.npz</code>）<a href="#1-镜像站下载案例文件case1npzcase4npz"><span>#</span></a></h5><p>在Git Bash（已激活<code>worldmem</code>环境）中执行以下命令，创建目录并下载文件：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 1. 创建案例文件目录（项目根目录下）</span></div></div><div><div><div>2</div></div><div><span>mkdir</span><span> </span><span>-p</span><span> </span><span>assets/examples</span><span> &amp;&amp; </span><span>cd</span><span> </span><span>assets/examples</span></div></div><div><div><div>3</div></div><div><span># 2. 镜像站下载</span></div></div><div><div><div>4</div></div><div><span>wget</span><span> </span><span>https://hf-mirror.com/yslan/worldmem/resolve/main/assets/examples/case1.npz</span></div></div><div><div><div>5</div></div><div><span>wget</span><span> </span><span>https://hf-mirror.com/yslan/worldmem/resolve/main/assets/examples/case2.npz</span></div></div><div><div><div>6</div></div><div><span>wget</span><span> </span><span>https://hf-mirror.com/yslan/worldmem/resolve/main/assets/examples/case3.npz</span></div></div><div><div><div>7</div></div><div><span>wget</span><span> </span><span>https://hf-mirror.com/yslan/worldmem/resolve/main/assets/examples/case4.npz</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>下载完成后，4个<code>.npz</code>文件存入<code>assets/examples</code>目录，终端显示下载进度条及完成提示。</p></section><section><h5>2. 修改<code>app.py</code>跳过自动下载<a href="#2-修改apppy跳过自动下载"><span>#</span></a></h5><p>打开项目根目录下的<code>app.py</code>文件，找到<code>download_assets_if_needed()</code>函数，修改如下（仅注释原下载逻辑，保留本地检查）：</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>import</span><span> os</span></div></div><div><div><div>2</div></div><div><span>import</span><span> requests</span></div></div><div><div><div>3</div></div><div><span>def</span><span> </span><span>download_assets_if_needed</span><span>():</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>asset_dir </span><span>=</span><span> </span><span>"assets/examples"</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>os.</span><span>makedirs</span><span>(asset_dir, </span><span>exist_ok</span><span>=</span><span>True</span><span>)</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>cases </span><span>=</span><span> [</span><span>"case1.npz"</span><span>, </span><span>"case2.npz"</span><span>, </span><span>"case3.npz"</span><span>, </span><span>"case4.npz"</span><span>]</span></div></div><div><div><div>7</div></div><div><span>    </span><span>for</span><span> case </span><span>in</span><span> cases:</span></div></div><div><div><div>8</div></div><div><span><span>        </span></span><span>local_path </span><span>=</span><span> os.path.</span><span>join</span><span>(asset_dir, case)</span></div></div><div><div><div>9</div></div><div><span>        </span><span>if</span><span><span> os.path.</span><span>exists</span><span>(local_path):</span></span></div></div><div><div><div>10</div></div><div><span>            </span><span>print</span><span>(</span><span>f</span><span>"✅ 本地已找到 </span><span>{</span><span>case</span><span>}</span><span>，跳过下载"</span><span>)</span></div></div><div><div><div>11</div></div><div><span>            </span><span>continue</span></div></div><div><div><div>12</div></div><div><span>        </span><span># 注释原下载逻辑（已手动下载，避免超时）</span></div></div><div><div><div>13</div></div><div><span>        </span><span># url = f"https://huggingface.co/spaces/yslan/worldmem/resolve/main/assets/examples/{case}"</span></div></div><div><div><div>14</div></div><div><span>        </span><span># resp = requests.get(url, timeout=30)</span></div></div><div><div><div>15</div></div><div><span>        </span><span># with open(local_path, "wb") as f:</span></div></div><div><div><div>16</div></div><div><span>        </span><span>#     f.write(resp.content)</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>保存文件即可生效，后续启动项目时会自动跳过下载步骤。</p></section><section><h5>3. 镜像站下载模型权重（<code>diffusion_only.ckpt</code>等3个文件）<a href="#3-镜像站下载模型权重diffusion_onlyckpt等3个文件"><span>#</span></a></h5><p>在Git Bash中切换到权重目录，执行下载命令（模型权重是核心，必须完整下载）：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 1. 回到项目根目录，创建权重目录</span></div></div><div><div><div>2</div></div><div><span>cd</span><span> </span><span>/c/Users/13062/Desktop/worldmem-video-demo/WorldMem</span></div></div><div><div><div>3</div></div><div><span>mkdir</span><span> </span><span>-p</span><span> </span><span>assets/checkpoints</span><span> &amp;&amp; </span><span>cd</span><span> </span><span>assets/checkpoints</span></div></div><div><div><div>4</div></div><div><span># 2. 镜像站下载权重文件</span></div></div><div><div><div>5</div></div><div><span>wget</span><span> </span><span>https://hf-mirror.com/zeqixiao/worldmem_checkpoints/resolve/main/diffusion_only.ckpt</span></div></div><div><div><div>6</div></div><div><span>wget</span><span> </span><span>https://hf-mirror.com/zeqixiao/worldmem_checkpoints/resolve/main/vae_only.ckpt</span></div></div><div><div><div>7</div></div><div><span>wget</span><span> </span><span>https://hf-mirror.com/zeqixiao/worldmem_checkpoints/resolve/main/pose_prediction_model_only.ckpt</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>下载完成后，3个<code>.ckpt</code>文件存入<code>assets/checkpoints</code>目录（总大小约5GB，确保磁盘空间充足）。</p></section><section><h5>4. 修改配置文件路径（指向本地权重）<a href="#4-修改配置文件路径指向本地权重"><span>#</span></a></h5><p>打开项目根目录下<code>configurations/huggingface.yaml</code>文件，将权重路径改为本地目录（确保项目能找到下载的权重）：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>diffusion_path</span><span>: </span><span>assets/checkpoints/diffusion_only.ckpt</span></div></div><div><div><div>2</div></div><div><span>vae_path</span><span>: </span><span>assets/checkpoints/vae_only.ckpt</span></div></div><div><div><div>3</div></div><div><span>pose_prediction_path</span><span>: </span><span>assets/checkpoints/pose_prediction_model_only.ckpt</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>保存文件，配置修改完成。</p></section></section>
<section><h4>五、首次启动app.py（界面成功，视频生成功能缺失）<a href="#五首次启动apppy界面成功视频生成功能缺失"><span>#</span></a></h4><ol>
<li>启动命令（Git Bash中，已激活<code>worldmem</code>环境，项目根目录下）：
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>python</span><span> </span><span>app.py</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li>运行现象：
<ul>
<li>终端日志正常输出「✅ 本地已找到 case1.npz」「🚀 初始化设备: cuda」「✅ 所有模型切换到eval模式」；</li>
<li>浏览器自动弹出<code>http://127.0.0.1:7860</code>，成功进入Gradio界面，可选择场景、输入动作序列；</li>
<li>点击「🎬 Generate!」按钮后，界面卡住无视频输出，终端无额外日志（无报错）。</li>
</ul>
</li>
<li>产生问题原因：视频生成依赖<code>ffmpeg</code>工具进行帧序列转MP4格式，本地未安装<code>ffmpeg</code>，项目无法调用该工具，导致视频生成功能加载失败。</li>
<li>关闭项目：按<code>Ctrl+C</code>终止终端进程，关闭浏览器。</li>
</ol></section>
<section><h4>六、ffmpeg下载与安装配置（补全视频生成依赖）<a href="#六ffmpeg下载与安装配置补全视频生成依赖"><span>#</span></a></h4><section><h5>1. 推荐安装路径（Windows系统必看）<a href="#1-推荐安装路径windows系统必看"><span>#</span></a></h5><ul>
<li>
<p>必须安装在「无中文、无空格」的目录，否则环境变量配置失败，项目无法调用。</p>
</li>
<li>
<p>首选路径：<code>C:\Program Files\ffmpeg</code>（解压后文件夹命名为<code>ffmpeg</code>，内部包含<code>bin</code>/<code>doc</code>等子目录）。</p>
</li>
</ul></section><section><h5>2. 安装与配置步骤<a href="#2-安装与配置步骤"><span>#</span></a></h5><ol>
<li>下载ffmpeg：
<ul>
<li>访问ffmpeg官网（<a href="https://ffmpeg.org/download.html%EF%BC%89%EF%BC%8C%E9%80%89%E6%8B%A9Windows%E3%80%8CFull" target="_blank">https://ffmpeg.org/download.html），选择Windows「Full</a> Build」版本；</li>
<li>或通过国内镜像站下载（避免境外超时），下载后得到压缩包（如<code>ffmpeg-7.0-full_build.7z</code>）。</li>
</ul>
</li>
<li>解压安装：用7-Zip等工具将压缩包解压到推荐路径（如<code>C:\Program Files\ffmpeg</code>）。</li>
<li>配置环境变量（关键步骤）：
<ul>
<li>右键「此电脑」→「属性」→「高级系统设置」→「环境变量」；</li>
<li>在「系统变量」中找到「Path」→「编辑」→「新建」，添加<code>ffmpeg</code>的<code>bin</code>目录路径（如<code>C:\Program Files\ffmpeg\bin</code>）；</li>
<li>点击「确定」保存，<strong>关闭所有Git Bash终端</strong>（环境变量需重启终端生效）。</li>
</ul>
</li>
<li>验证生效：打开新的Git Bash（自动激活<code>worldmem</code>环境），执行：
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>ffmpeg</span><span> </span><span>-version</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
终端输出ffmpeg版本信息（如「ffmpeg version 7.0 Copyright (c) 2000-2023」），说明安装配置成功。</li>
</ol></section></section>
<section><h4>七、重新启动app.py（视频生成加载成功，内存不足失败）<a href="#七重新启动apppy视频生成加载成功内存不足失败"><span>#</span></a></h4><ol>
<li>启动命令（新打开的Git Bash中，项目根目录下）：
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>python</span><span> </span><span>app.py</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li>运行现象：
<ul>
<li>终端日志正常初始化，视频生成组件加载成功（终端显示「ffmpeg相关初始化日志」）；</li>
<li>加载<code>diffusion_model</code>权重（3605MB）时，终端卡住，随后输出「Segmentation fault」，进程终止；</li>
<li>任务管理器显示：CPU内存占用飙升至15.0GB+（总物理内存15.22GB），剩余可用内存不足200MB，触发内存溢出。</li>
</ul>
</li>
<li>问题原因：<code>ffmpeg</code>安装后，视频生成组件初始化增加了内存占用，叠加3.6GB的模型权重加载，16GB物理内存不足以承载，导致段错误。</li>
</ol></section>
<section><h4>八、训练脚本执行<a href="#八训练脚本执行"><span>#</span></a></h4><ol>
<li>补充训练依赖（若之前未安装）：
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>pip</span><span> </span><span>install</span><span> </span><span>wandb</span><span>  </span><span># 训练日志监控依赖</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li>修复训练脚本配置：打开项目根目录下<code>train_stage_1.sh</code>文件，将<code>algorithm.metrics=[lpips,psnr]</code>改为<code>+algorithm.metrics=[lpips,psnr]</code>（适配Hydra配置语法，避免报错）。</li>
<li>执行训练脚本（Git Bash中，项目根目录下）：
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>sh</span><span> </span><span>train_stage_1.sh</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
（注：若内存充足，脚本会正常启动训练；若内存不足，会出现与启动app.py类似的内存溢出报错）</li>
</ol></section>
<section><h4>九、Git Bash环境常用命令速查表<a href="#九git-bash环境常用命令速查表"><span>#</span></a></h4>

<table><thead><tr><th>操作目的</th><th>执行命令</th></tr></thead><tbody><tr><td>激活Conda环境（Git Bash）</td><td>打开Git Bash自动激活（或<code>conda activate worldmem</code>）</td></tr><tr><td>切换到项目根目录</td><td><code>cd /c/Users/13062/Desktop/worldmem-video-demo/WorldMem</code></td></tr><tr><td>启动项目</td><td><code>python app.py</code></td></tr><tr><td>执行训练脚本</td><td><code>sh train_stage_1.sh</code></td></tr><tr><td>安装缺失依赖</td><td><code>pip install [依赖名]</code>（如<code>pip install gradio</code>）</td></tr><tr><td>验证CUDA生效</td><td><code>python -c "import torch; print(torch.cuda.is_available())"</code></td></tr><tr><td>验证ffmpeg生效</td><td><code>ffmpeg -version</code></td></tr><tr><td>克隆项目代码</td><td><code>git clone https://github.com/zeqixiao/worldmem-video-demo.git</code></td></tr><tr><td>镜像站下载文件（通用）</td><td><code>wget [镜像站链接]</code>（需在对应目录下执行）</td></tr></tbody></table></section>
<section><h4>十、核心问题与解决方案汇总（按遇到顺序排列）<a href="#十核心问题与解决方案汇总按遇到顺序排列"><span>#</span></a></h4>

<table><thead><tr><th>问题现象</th><th>根本原因</th><th>解决方案</th></tr></thead><tbody><tr><td>Git Bash无法激活Conda环境</td><td>Git Bash默认不加载Conda脚本</td><td>配置<code>.bashrc</code>文件，添加Conda脚本路径，生效后自动激活</td></tr><tr><td>项目依赖安装失败/缺失</td><td>未在<code>worldmem</code>环境中执行安装命令</td><td>切换到项目根目录，在激活环境的Git Bash中执行<code>pip install</code>命令</td></tr><tr><td>境外资源下载超时</td><td>GitHub/ Hugging Face境外链接访问不稳定</td><td>使用镜像站链接下载案例文件和模型权重</td></tr><tr><td>首次启动视频生成功能加载失败</td><td>未安装<code>ffmpeg</code>，视频格式转换依赖该工具</td><td>按指定路径安装<code>ffmpeg</code>，配置环境变量并验证生效</td></tr><tr><td>训练脚本Hydra配置报错</td><td><code>algorithm.metrics</code>参数语法不符合Hydra要求</td><td>在参数前加<code>+</code>，改为<code>+algorithm.metrics=[lpips,psnr]</code></td></tr><tr><td>重新启动app.py内存溢出</td><td>16GB物理内存不足以承载模型权重（3.6GB）+视频处理组件</td><td>扩展虚拟内存（20-40GB）或升级物理内存（≥32GB）</td></tr></tbody></table></section>
<section><h4>十一、项目核心用途总结<a href="#十一项目核心用途总结"><span>#</span></a></h4><p>WorldMem 是一个「基于动作交互的3D世界模拟与长视频生成工具」，核心价值是解决“单张场景图→上下文连贯长视频”的创作痛点，具体功能与场景如下：</p><ol>
<li>核心功能：
<ul>
<li>6种预设场景（向日葵平原、沙漠、冰原等），支持任意场景作为初始帧；</li>
<li>动作交互（W/A/S/D/Q/E等按键组合），可实现转向、移动、使用物品等操作；</li>
<li>长视频生成：连续点击「Generate」扩展视频长度，自动维护场景3D结构、物体位置的一致性（新帧用红框标记）；</li>
<li>模型训练：通过<code>train_stage_1.sh</code>脚本训练自定义模型，优化生成效果。</li>
</ul>
</li>
<li>应用场景：
<ul>
<li>游戏开发：快速生成开放世界视频片段，无需手动建模动画；</li>
<li>虚拟模拟：基于简单指令模拟虚拟环境视角移动与交互；</li>
<li>内容创作：为动画、影视领域提供低成本场景扩展工具。</li>
</ul>
</li>
</ol></section>
<section><h4>关键注意事项<a href="#关键注意事项"><span>#</span></a></h4><ol>
<li>流程逻辑优先级：必须先配置Git Bash的Conda环境，再安装依赖、下载资源——无环境则所有依赖安装、命令执行都会失效，这是最关键的前置步骤。</li>
<li><code>ffmpeg</code>安装红线：路径必须无中文、无空格，环境变量必须指向<code>bin</code>目录，否则视频生成功能始终加载失败。</li>
<li>内存是核心瓶颈：16GB物理内存仅能满足基础界面启动，视频生成+模型权重加载需≥32GB物理内存，或扩展20-40GB虚拟内存。</li>
<li>终端统一原则：全程使用Git Bash操作，避免切换Anaconda Prompt/CMD导致环境不一致，减少报错概率。</li>
<li>资源完整性：案例文件（4个<code>.npz</code>）和模型权重（3个<code>.ckpt</code>）必须完整下载，缺失任一文件会导致项目启动失败。</li>
</ol></section>]]></content>
    </entry>
</feed>
