Z User commited on
Commit
290db07
·
1 Parent(s): da88712

add /deploy route - deployment overview page

Browse files

- entry.py: add /deploy GET route serving deploy.html
- Dockerfile: COPY deploy.html to container
- deploy.html: full deployment overview with architecture, changelog,
masked .env/config.yaml preview, FAQ, SOUL.md summary

Files changed (3) hide show
  1. Dockerfile +1 -0
  2. deploy.html +287 -0
  3. entry.py +5 -0
Dockerfile CHANGED
@@ -34,6 +34,7 @@ COPY SOUL.md /root/.hermes/SOUL.md
34
  COPY .env /root/.hermes/.env
35
  COPY entry.py /app/entry.py
36
  COPY dashboard.html /app/dashboard.html
 
37
  COPY plugins/pollinations/ /root/.hermes/plugins/image_gen/pollinations/
38
 
39
  RUN chmod 600 /root/.hermes/.env
 
34
  COPY .env /root/.hermes/.env
35
  COPY entry.py /app/entry.py
36
  COPY dashboard.html /app/dashboard.html
37
+ COPY deploy.html /app/deploy.html
38
  COPY plugins/pollinations/ /root/.hermes/plugins/image_gen/pollinations/
39
 
40
  RUN chmod 600 /root/.hermes/.env
deploy.html ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <title>Hermes Bot · HF Spaces 部署总览</title>
7
+ <style>
8
+ *{margin:0;padding:0;box-sizing:border-box}
9
+ body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;background:#0a0a0a;color:#e0e0e0;min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:24px}
10
+ .container{max-width:720px;width:100%}
11
+ .logo{text-align:center;margin-bottom:36px}
12
+ .logo h1{font-size:2.4rem;font-weight:700;background:linear-gradient(135deg,#ff6b35,#ffa500);-webkit-background-clip:text;-webkit-text-fill-color:transparent;letter-spacing:-0.5px}
13
+ .logo p{color:#666;margin-top:8px;font-size:0.95rem}
14
+ .logo .ver{display:inline-block;margin-top:6px;padding:2px 10px;border-radius:20px;background:#111;border:1px solid #222;color:#ff6b35;font-size:0.75rem;font-weight:600}
15
+ .card{background:#111;border:1px solid #222;border-radius:16px;padding:28px 32px;margin-bottom:20px}
16
+ .card h2{font-size:1.05rem;color:#ff6b35;margin-bottom:14px;display:flex;align-items:center;gap:8px}
17
+ .card h2 span{font-size:1.2rem}
18
+ .card pre{background:#0a0a0a;border:1px solid #1a1a1a;border-radius:10px;padding:14px 16px;overflow-x:auto;font-size:0.8rem;line-height:1.7;color:#b0b0b0;font-family:"SF Mono",Monaco,"Cascadia Code",monospace}
19
+ .cmd{color:#ff6b35}.cmt{color:#444}.ok{color:#00d4aa}.fix{color:#ff9900}.new{color:#88ccff}.hl{color:#ffc864}.rm{color:#ff6b6b}
20
+ .warn{background:#1a1208;border:1px solid #332a10;border-radius:12px;padding:18px 22px;margin-bottom:20px;display:flex;gap:12px;align-items:flex-start}
21
+ .warn .icon{font-size:1.3rem;flex-shrink:0;margin-top:2px}
22
+ .warn .text{font-size:0.88rem;line-height:1.6}
23
+ .warn .text strong{color:#ff9900}
24
+ .arch{background:#0d1117;border:1px solid #21262d;border-radius:12px;padding:18px 22px;margin-bottom:20px}
25
+ .arch h3{font-size:0.9rem;color:#58a6ff;margin-bottom:12px}
26
+ .arch pre{font-size:0.78rem;line-height:1.6;color:#8b949e;font-family:"SF Mono",Monaco,"Cascadia Code",monospace}
27
+ .steps{list-style:none;counter-reset:step}
28
+ .steps li{counter-increment:step;padding:10px 0 10px 44px;position:relative;font-size:0.92rem;line-height:1.6;color:#999;border-bottom:1px solid #1a1a1a}
29
+ .steps li:last-child{border-bottom:none}
30
+ .steps li::before{content:counter(step);position:absolute;left:0;top:8px;width:30px;height:30px;background:#111;border:1px solid #222;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:0.8rem;color:#ff6b35;font-weight:600}
31
+ .steps li strong{color:#e0e0e0}
32
+ .tag{display:inline-block;padding:1px 7px;border-radius:4px;font-size:0.7rem;font-weight:600;margin-left:4px;vertical-align:middle}
33
+ .tag-new{background:#2a1a00;color:#ff6b35}.tag-ok{background:#0a2a1a;color:#00d4aa}.tag-fix{background:#2a1a00;color:#ff9900}.tag-rm{background:#2a0a0a;color:#ff6b6b}
34
+ .badge{display:inline-block;padding:3px 10px;border-radius:6px;font-size:0.72rem;font-weight:600;margin-bottom:14px}
35
+ .footer{text-align:center;margin-top:12px;color:#333;font-size:0.78rem}
36
+ .cost{text-align:center;padding:16px;margin-bottom:20px;border-radius:12px;background:linear-gradient(135deg,#1a0a00,#2a1a0a);border:1px solid #3a2a1a}
37
+ .cost .big{font-size:1.8rem;font-weight:700;color:#ff6b35}
38
+ .cost .sub{font-size:0.82rem;color:#666;margin-top:4px}
39
+ a{color:#ffc864;text-decoration:none}
40
+ a:hover{text-decoration:underline}
41
+ .section{display:flex;gap:12px;margin-bottom:20px}
42
+ .section>div{flex:1}
43
+ .stat{text-align:center;padding:20px 12px;border-radius:12px;background:#111;border:1px solid #222}
44
+ .stat .label{color:#555;font-size:0.75rem;text-transform:uppercase;letter-spacing:0.5px;margin-bottom:6px}
45
+ .stat .value{font-size:1.5rem;font-weight:700}
46
+ .stat .value.orange{color:#ff6b35}
47
+ .stat .value.green{color:#00d4aa}
48
+ .stat .value.blue{color:#58a6ff}
49
+ .stat .value.purple{color:#d2a8ff}
50
+ .stat .note{color:#444;font-size:0.72rem;margin-top:4px}
51
+ </style>
52
+ </head>
53
+ <body>
54
+ <div class="container">
55
+
56
+ <div class="logo">
57
+ <h1>Hermes Bot</h1>
58
+ <p>HuggingFace Spaces · 飞书 AI Agent · 7x24 在线</p>
59
+ <span class="ver">v3.0 HF Spaces · 2026.04</span>
60
+ </div>
61
+
62
+ <div class="cost">
63
+ <div class="big">Free (免费)</div>
64
+ <div class="sub">HuggingFace Spaces 免费 CPU 实例 · OpenRouter 免费模型 · 零成本运行</div>
65
+ </div>
66
+
67
+ <div class="section">
68
+ <div class="stat">
69
+ <div class="label">主模型</div>
70
+ <div class="value orange">Gemma 4 31B</div>
71
+ <div class="note">google/gemma-4-31b-it</div>
72
+ </div>
73
+ <div class="stat">
74
+ <div class="label">备用模型</div>
75
+ <div class="value blue">Qwen3 Coder</div>
76
+ <div class="note">qwen/qwen3-coder</div>
77
+ </div>
78
+ <div class="stat">
79
+ <div class="label">记忆系统</div>
80
+ <div class="value purple">Holographic</div>
81
+ <div class="note">SQLite + FTS5</div>
82
+ </div>
83
+ <div class="stat">
84
+ <div class="label">图片生成</div>
85
+ <div class="value green">Pollinations</div>
86
+ <div class="note">Flux · 免费</div>
87
+ </div>
88
+ </div>
89
+
90
+ <div class="warn">
91
+ <div class="icon">&#128274;</div>
92
+ <div class="text">
93
+ <strong>API 密钥已脱敏</strong> — 共计 5 个敏感值在预览中全部打码。<br>
94
+ 完整版仅存储在 HF Space 容器内(.env),不对外暴露。
95
+ </div>
96
+ </div>
97
+
98
+ <div class="card">
99
+ <h2><span>&#127959;</span> 部署架构 <span class="tag tag-new">HF Spaces</span></h2>
100
+ <div class="arch">
101
+ <pre><span class="hl">HuggingFace Spaces (Docker SDK)</span>
102
+ ├── <span class="hl">Space: Jackken/hermes-bot</span>
103
+ │ ├── <span class="hl">Dockerfile</span> ← Python 3.12-slim 基础镜像
104
+ │ ├── <span class="hl">entry.py</span> ← 入口:Dashboard(:7860) + Gateway 子进程
105
+ │ ├── <span class="hl">dashboard.html</span> ← 实时监控面板(SSE 日志流)
106
+ │ ├── <span class="hl">start.sh</span> ← 启动脚本
107
+ │ │
108
+ │ ├── <span class="hl">config.yaml</span> ← 模型/平台/记忆/插件配置
109
+ │ ├── <span class="hl">SOUL.md</span> ← 人格定义(12 章节 · 全中文)
110
+ │ ├── <span class="hl">.env</span> ← API 密钥(chmod 600)
111
+ │ │
112
+ │ └── <span class="hl">plugins/pollinations/</span> ← 图片生成插件(免费·无需 Key)
113
+ │ ├── plugin.yaml
114
+ │ └── __init__.py ← PollinationsImageGenProvider
115
+
116
+ ├── <span class="hl">Persistent Storage (/data)</span> ← HF 持久化存储(重启不丢)
117
+ │ ├── sessions/ ← 会话数据(每 24h 自动清理上下文)
118
+ │ ├── memories/ ← Holographic 长期记忆(SQLite + FTS5)
119
+ │ ├── uploads/ ← 用户上传文件缓存
120
+ │ └── logs/ ← Gateway 运行日志
121
+
122
+ └── <span class="hl">Free CPU Instance</span> ← 2 vCPU · 16GB RAM · 50GB 存储
123
+
124
+ <span class="hl">OpenRouter</span> ← 大模型 API(免费模型)
125
+ ├── google/gemma-4-31b-it ← 主模型(推理 + 工具调用)
126
+ └── qwen/qwen3-coder ← 备用模型(主模型失败自动切换)
127
+
128
+ <span class="hl">Pollinations.ai</span> ← 免费图片生成
129
+ └── Flux 模型 ← landscape / square / portrait
130
+
131
+ <span class="hl">飞书</span> ← WebSocket 长连接
132
+ └── App: Hermes ← 7x24 在线 · 流式回复 · 工具透明</pre>
133
+ </div>
134
+ </div>
135
+
136
+ <div class="card">
137
+ <h2><span>&#128296;</span> 修复与变更 <span class="tag tag-new">v3.0</span></h2>
138
+ <pre><span class="new">&#9733; 新增</span> <span class="hl">Pollinations.ai 图片生成</span>
139
+ 插件框架实现 ImageGenProvider,Flux 模型免费生成图片
140
+ plugins.enabled 显式启用 image_gen/pollinations
141
+ SOUL.md 添加图片生成使用指南 + MEDIA 标签发送
142
+
143
+ <span class="new">&#9733; 新增</span> <span class="hl">Firecrawl 网页抓取</span>
144
+ FIRECRAWL_API_KEY 注入 .env,headless 浏览器 + stealth 反爬
145
+ 用于 JS 渲染页面抓取(微信公众号除外)
146
+
147
+ <span class="new">&#9733; 新增</span> <span class="hl">中文字体支持</span>
148
+ Dockerfile 下载 NotoSansSC-Regular.otf + Bold.otf (~16MB)
149
+ 解决 PDF/图片中文渲染乱码问题
150
+
151
+ <span class="new">&#9733; 新增</span> <span class="hl">微信公众号文章处理策略</span>
152
+ SOUL.md 五级降级链:Firecrawl → Jina Reader → 搜狗 → 转载搜索 → 用户截图
153
+ 禁止直接 curl mp.weixin.qq.com(验证码拦截)
154
+
155
+ <span class="fix">&#10003; 修复</span> <span class="hl">飞书文件发送机制</span>
156
+ SOUL.md 从错误的"手动调 send_document"改为 MEDIA:&lt;path&gt; 标签机制
157
+ 网关自动扫描标签 → adapter.send_document() 上传
158
+
159
+ <span class="rm">&#10007; 移除</span> <span class="hl">MemPalace 记忆系统</span>
160
+ chromadb + onnxruntime 吃 1-2GB 内存 → OOM 风险
161
+ 改用 Holographic(SQLite + FTS5),内存占用几乎为零
162
+ .env / Dockerfile / config.yaml / entry.py 同步清理
163
+
164
+ <span class="ok">&#8730; 正常</span> <span class="hl">Holographic 记忆</span>
165
+ 持久化存储 /data/hermes/memories/,重启/reset 均不丢失
166
+ auto_extract: true 自动提取关键信息存入记忆
167
+
168
+ <span class="ok">&#8730; 正常</span> <span class="hl">上下文压缩</span>
169
+ 50 条消息触发,压缩至 20 条,保护最近 20 条不压缩
170
+
171
+ <span class="ok">&#8730; 正常</span> <span class="hl">全部 5 个 API 密钥</span>
172
+ *** 已脱敏 *** · 仅容器内可见</pre>
173
+ </div>
174
+
175
+ <div class="card">
176
+ <h2><span>&#128196;</span> 脱敏预览 (.env)</h2>
177
+ <pre><span class="hl">OPENROUTER_API_KEY</span> = <span class="cmt">"***MASKED***"</span> <span class="cmt"># OpenRouter 大模型接口</span>
178
+ <span class="hl">OPENAI_API_KEY</span> = <span class="cmt">"***MASKED***"</span> <span class="cmt"># 同 OpenRouter Key</span>
179
+ <span class="hl">OPENAI_BASE_URL</span> = <span class="ok">"https://openrouter.ai/api/v1"</span>
180
+ <span class="hl">FEISHU_APP_ID</span> = <span class="cmt">"***MASKED***"</span> <span class="cmt"># 飞书应用 App ID</span>
181
+ <span class="hl">FEISHU_APP_SECRET</span> = <span class="cmt">"***MASKED***"</span> <span class="cmt"># 飞书应用 App Secret</span>
182
+ <span class="hl">FIRECRAWL_API_KEY</span> = <span class="cmt">"***MASKED***"</span> <span class="cmt"># Firecrawl 网页抓取</span>
183
+ <span class="hl">GATEWAY_ALLOW_ALL_USERS</span> = <span class="ok">true</span>
184
+ <span class="hl">HERMES_ACCEPT_HOOKS</span> = <span class="ok">1</span>
185
+
186
+ <span class="cmt"># 共计 5 个密钥已脱敏 · config.yaml: model = google/gemma-4-31b-it</span></pre>
187
+ </div>
188
+
189
+ <div class="card">
190
+ <h2><span>&#128203;</span> 脱敏预览 (config.yaml)</h2>
191
+ <pre><span class="hl">model</span>: <span class="ok">google/gemma-4-31b-it</span> <span class="cmt"># 主模型</span>
192
+ <span class="hl">provider</span>: <span class="ok">openrouter</span>
193
+ <span class="hl">fallback_model</span>:
194
+ <span class="hl">provider</span>: <span class="ok">openrouter</span>
195
+ <span class="hl">model</span>: <span class="ok">qwen/qwen3-coder</span> <span class="cmt"># 备用模型</span>
196
+ <span class="hl">max_turns</span>: <span class="ok">90</span> <span class="cmt"># 单轮最大工具调用轮数</span>
197
+ <span class="hl">platforms</span>.feishu:
198
+ <span class="hl">enabled</span>: <span class="ok">true</span>
199
+ <span class="hl">connection_mode</span>: <span class="ok">websocket</span> <span class="cmt"># 长连接</span>
200
+ <span class="hl">memory</span>:
201
+ <span class="hl">provider</span>: <span class="ok">holographic</span> <span class="cmt"># 持久记忆</span>
202
+ <span class="hl">auto_extract</span>: <span class="ok">true</span>
203
+ <span class="hl">compress</span>:
204
+ <span class="hl">enabled</span>: <span class="ok">true</span> <span class="cmt"># 长对话自动压缩</span>
205
+ <span class="hl">threshold</span>: <span class="ok">50</span> <span class="cmt"># 50条触发</span>
206
+ <span class="hl">target_ratio</span>: <span class="ok">20</span> <span class="cmt"># 压缩至20条</span>
207
+ <span class="hl">image_gen</span>:
208
+ <span class="hl">provider</span>: <span class="ok">pollinations</span> <span class="cmt"># 免费图片生成</span>
209
+ <span class="hl">plugins</span>:
210
+ <span class="hl">enabled</span>: <span class="ok">[image_gen/pollinations]</span>
211
+ <span class="hl">no_mcp</span>: <span class="ok">true</span> <span class="cmt"># 禁用 MCP 节省内存</span>
212
+ <span class="hl">terminal</span>:
213
+ <span class="hl">backend</span>: <span class="ok">local</span>
214
+ <span class="hl">timeout</span>: <span class="ok">180</span>
215
+ <span class="hl">timezone</span>: <span class="ok">Asia/Shanghai</span></pre>
216
+ </div>
217
+
218
+ <div class="card">
219
+ <h2><span>&#127919;</span> 部署管理</h2>
220
+ <pre><span class="cmt"># Space 地址</span>
221
+ <span class="hl">https://huggingface.co/spaces/Jackken/hermes-bot</span>
222
+
223
+ <span class="cmt"># 本地克隆(修改配置后 git push 自动重建)</span>
224
+ <span class="cmd">git</span> clone https://huggingface.co/spaces/Jackken/hermes-bot
225
+ <span class="cmd">cd</span> hermes-bot
226
+ <span class="cmt"># 修改 SOUL.md / config.yaml / .env 后...</span>
227
+ <span class="cmd">git</span> add -A && <span class="cmd">git</span> commit -m "update" && <span class="cmd">git</span> push
228
+
229
+ <span class="cmt"># 监控面板(实时日志 + 会话 + 重启)</span>
230
+ <span class="hl">https://jackken-hermes-bot.hf.space/</span>
231
+
232
+ <span class="cmt"># 手动重启 Space(Factory Rebuild 会清空持久化存储!)</span>
233
+ <span class="hl">在 Space 页面点击 "Factory Rebuild" 按钮</span></pre>
234
+ </div>
235
+
236
+ <div class="card">
237
+ <h2><span>&#128161;</span> 常见问题</h2>
238
+ <pre><span class="cmt">Q: 免费实例会休眠吗?</span>
239
+ <span class="ok">A:</span> HF 免费 CPU 实例在 48 小时无请求后休眠,下次请求自动唤醒(1-2 分钟)
240
+ 飞书 WebSocket 长连接会保持活跃,通常不会休眠
241
+
242
+ <span class="cmt">Q: 内存够用吗?</span>
243
+ <span class="ok">A:</span> 16GB RAM 当前使用约 84%。已移除 MemPalace(省 1-2GB)。
244
+ 如果频繁 OOM:减少 max_turns / 禁用浏览器工具 / 清理日志
245
+
246
+ <span class="cmt">Q: Factory Rebuild 会丢数据吗?</span>
247
+ <span class="ok">A:</span> 是的!Rebuild 会清空 /data 持久化存储(记忆/会话/日志全丢)。
248
+ 正常 git push 只重建容器不丢数据,尽量用 git push 而非 Rebuild
249
+
250
+ <span class="cmt">Q: 如何修改人格/记忆?</span>
251
+ <span class="ok">A:</span> SOUL.md 控制人格(12 章节),克隆仓库编辑后 git push
252
+ 记忆系统自动运行,也可在飞书中发 /reset 清理上下文(记忆不丢)
253
+
254
+ <span class="cmt">Q: 图片生成失败怎么办?</span>
255
+ <span class="ok">A:</span> 检查 config.yaml 中 plugins.enabled 是否包含 image_gen/pollinations
256
+ Pollinations.ai 偶尔不稳定,生成需 10-20 秒,耐心等待
257
+
258
+ <span class="cmt">Q: 微信公众号文章抓不到?</span>
259
+ <span class="ok">A:</span> 微信反爬极强(验证码),Firecrawl/Jina/curl 均无法突破
260
+ 使用 SOUL.md 五级降级链:Firecrawl → Jina → 搜狗 → 搜索转载 → 截图</pre>
261
+ </div>
262
+
263
+ <div class="card">
264
+ <h2><span>&#128268;</span> SOUL.md 人格概览</h2>
265
+ <pre><span class="cmt"># 12 章节完整人格定义</span>
266
+ <span class="hl">一</span>、记忆系统(Holographic) <span class="cmt"># SQLite + FTS5 持久记忆</span>
267
+ <span class="hl">二</span>、任务分类与响应策略 <span class="cmt"># 8 种消息类型自动判断</span>
268
+ <span class="hl">三</span>、工具编排策略 <span class="cmt"># 4 条常用工具链</span>
269
+ <span class="hl">四</span>、错误恢复机制 <span class="cmt"># 8 种失败场景恢复链</span>
270
+ <span class="hl">五</span>、回复格式标准 <span class="cmt"># 飞书 Markdown + 篇幅控制</span>
271
+ <span class="hl">六</span>、上下文感知 <span class="cmt"># 时间 + 对话 + 跨会话</span>
272
+ <span class="hl">七</span>、主动行为 <span class="cmt"># 4 种主动触发场景</span>
273
+ <span class="hl">八</span>、飞书特化 <span class="cmt"># MEDIA 标签 / 文档 / 卡片</span>
274
+ <span class="hl">九</span>、图片生成 <span class="cmt"># Pollinations.ai + MEDIA 发送</span>
275
+ <span class="hl">十</span>、独有能力清单 <span class="cmt"># 14 项飞书独有能力</span>
276
+ <span class="hl">十一</span>、边界与诚实 <span class="cmt"># 不编造 / 不越界</span>
277
+ <span class="hl">十二</span>、效率原则 <span class="cmt"># 最少工具调用 / 并行执行</span></pre>
278
+ </div>
279
+
280
+ <div class="footer">
281
+ Hermes Bot · HuggingFace Spaces · 飞书 AI Agent<br>
282
+ Nous Research hermes-agent · OpenRouter · Pollinations.ai · Firecrawl
283
+ </div>
284
+
285
+ </div>
286
+ </body>
287
+ </html>
entry.py CHANGED
@@ -37,6 +37,7 @@ LOG_FILE = os.path.join(LOG_DIR, "gateway.log")
37
  CONFIG_FILE = os.path.join(HERMES_HOME, "config.yaml")
38
  ENV_FILE = os.path.join(HERMES_HOME, ".env")
39
  DASHBOARD_HTML = "/app/dashboard.html"
 
40
 
41
  # ---------------------------------------------------------------------------
42
  # Logging
@@ -271,6 +272,10 @@ class DashboardHandler(BaseHTTPRequestHandler):
271
  if parsed.path in ("/", "/index.html"):
272
  return self._send_html(DASHBOARD_HTML)
273
 
 
 
 
 
274
  # SSE log stream
275
  if parsed.path == "/api/logs/stream":
276
  return self._handle_sse()
 
37
  CONFIG_FILE = os.path.join(HERMES_HOME, "config.yaml")
38
  ENV_FILE = os.path.join(HERMES_HOME, ".env")
39
  DASHBOARD_HTML = "/app/dashboard.html"
40
+ DEPLOY_HTML = "/app/deploy.html"
41
 
42
  # ---------------------------------------------------------------------------
43
  # Logging
 
272
  if parsed.path in ("/", "/index.html"):
273
  return self._send_html(DASHBOARD_HTML)
274
 
275
+ # Deploy overview
276
+ if parsed.path == "/deploy":
277
+ return self._send_html(DEPLOY_HTML)
278
+
279
  # SSE log stream
280
  if parsed.path == "/api/logs/stream":
281
  return self._handle_sse()