# N8N 内容转化流水线工作流设计（v4 → v5 升级）

> 用于：AI 英文文章 → 中文公众号/X/视频 内容转化
> 工作流ID：`iOf32aOKvTjfTDSM`（v4基础）
> 触发方式：OpenClaw 通过 Webhook 调用
> 管理平台：Mac mini 上的 n8n (`https://n8n.ishenwei.online`)

---

## 📋 核心需求更新（v5）

### 输出要求（重要！）

**必须同时输出两个版本：**

| 输出文件 | 路径 | 格式 | 用途 |
|---------|------|------|------|
| **Markdown 源文件** | `content-output/{原文件名}.md` | 中文 Markdown | Obsidian 留存、溯源 |
| **公众号 HTML** | `content-output/{原文件名}.html` | 带样式的 HTML | 直接复制到公众号编辑器 |

### Obsidian 目录结构

```
~/Workspace/nexus/openclaw/
├── content-queue/                              # 原始英文文章（输入）
│   └── 2026-03-29-ai-solopreneur.md
│
└── content-output/                            # 成品（输出）
    ├── 2026-03-29-ai-solopreneur.md           # 翻译后 Markdown
    └── 2026-03-29-ai-solopreneur.html         # 公众号 HTML（新增）
```

---

## 📋 工作流概述

```
OpenClaw (发现文章)
       ↓ (保存文件到 n8n-files 目录)
       ↓ (触发 Webhook)

┌─────────────────────────────────────────────────────────────┐
│  N8N 工作流 (v5): content-translation-pipeline-v5          │
│                                                              │
│  [Webhook] → [Read File] → [Extract Text] → [AI Agent]     │
│       ↓                              ↑ (DeepSeek)            │
│  [Build Markdown] → [Write .md] → [Build HTML] → [Write .html] │
│       ↓                                                          │
│  [Send Telegram]                                               │
└─────────────────────────────────────────────────────────────┘
```

---

## 🔌 节点详细设计（v5）

### 节点 1️⃣：Webhook Trigger

**类型：** Webhook
**名称：** `Webhook Trigger`
**Path：** `/content-translation-v5`（新建 path）
**Method：** POST

**接收数据格式：**
```json
{
  "note_name": "2026-03-29-ai-solopreneur.md",
  "source_path": "/Users/weishen/Workspace/nexus/openclaw/content-queue/2026-03-29-ai-solopreneur.md",
  "callback_url": "http://192.168.3.189:18789/webhook/yunce"
}
```

---

### 节点 2️⃣：Read Obsidian Note

**类型：** Read Binary File
**名称：** `Read Obsidian Note`

**配置：**
- File Path: `=/home/node/.n8n-files/{{ $json.body.note_name }}`

---

### 节点 3️⃣：Extract from File

**类型：** Extract from File
**名称：** `Extract from File`
**Operation：** `text`

**输出：**
```json
{
  "original_content": "...",
  "note_name": "2026-03-29-ai-solopreneur.md",
  "source_path": "/Users/weishen/Workspace/nexus/openclaw/content-queue/..."
}
```

---

### 节点 4️⃣：AI Agent（翻译+改写）

**类型：** LangChain Agent
**名称：** `AI Agent`
**Version：** 3.1
**Model：** DeepSeek Chat Model

**Prompt 模板：**
```
你是一个专业的中文内容编辑，擅长将英文文章转化为适合中国读者的高质量内容。

## 你的任务

将以下英文原文转化为：
1. 公众号风格的深度文章（2000-3000字）
2. X/Twitter 风格的短文案（280字内，带钩子）
3. 视频口播脚本（3-5分钟，适合抖音/YouTube）

## 内容要求

- 语言：地道中文，无翻译腔
- 风格：专业、有干货、适合中国读者
- 调性：公众号大V风格，有观点有案例
- 商业化：可自然植入 AI Agent / 知识管理相关内容（软性，不硬广）

## 输出格式（严格按此 JSON 返回）

{
  "wechat_title": "中文标题",
  "wechat_excerpt": "公众号摘要（100字内）",
  "wechat_content": "完整公众号文章（Markdown格式）",
  "twitter_copy": "X/Twitter文案（280字内，带emoji）",
  "video_title": "视频标题",
  "video_script": "口播脚本（含时间戳和字幕）",
  "cover_keywords": ["关键词1", "关键词2", "关键词3"]
}

## 原文内容
{{ $json.data }}
```

---

### 节点 5️⃣：Build Markdown（新增）

**类型：** Code
**名称：** `Build Markdown`

**功能：** 将 AI 输出组装成 Markdown 文件

```javascript
const aiResult = $input.first().json.message;
const data = typeof aiResult === 'string' ? JSON.parse(aiResult) : aiResult;

const noteName = $('Webhook Trigger').first().json.body.note_name;
// 去掉 .md 后缀，输出到 content-output
const outputName = noteName.replace('.md', '.md');
const outputPath = '/Users/weishen/Workspace/nexus/openclaw/content-output/' + outputName;

const markdown = `# ${data.wechat_title}

${data.wechat_content}

---

## X/Twitter 文案

${data.twitter_copy}

---

## 视频信息

**标题：** ${data.video_title}

**口播脚本：**

${data.video_script}

---

*封面图关键词：${data.cover_keywords?.join(', ')}*
`;

return {
  json: {
    output_path: outputPath,
    output_content: markdown,
    source_path: $('Webhook Trigger').first().json.body.source_path
  }
};
```

---

### 节点 6️⃣：Write .md File（新增）

**类型：** Write Binary File / ReadWriteFile
**名称：** `Write Markdown Note`

**配置：**
- Operation: `write`
- File Path: `=/home/node/.n8n-files/{{ $json.body.output_name }}_output.md`
- Content: `={{ $json.output_content }}`

**注意：** 输出到 n8n-files/ 目录，由 OpenClaw 负责复制回 Obsidian。

---

### 节点 7️⃣：Build HTML（新增，核心）

**类型：** Code
**名称：** `Build WeChat HTML`

**功能：** 将 Markdown 转为带样式的公众号 HTML

```javascript
const aiResult = $input.first().json.message;
const data = typeof aiResult === 'string' ? JSON.parse(aiResult) : aiResult;

const outputName = $('Webhook Trigger').first().json.body.output_name;
const htmlPath = '/home/node/.n8n-files/' + outputName + '_output.html';

// 公众号 HTML 模板
const html = `<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <style>
    body {
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
      font-size: 16px;
      line-height: 1.8;
      color: #333;
      max-width: 100%;
      padding: 20px;
    }
    h1 {
      font-size: 24px;
      text-align: center;
      color: #1a1a1a;
      margin-bottom: 30px;
      font-weight: 600;
    }
    h2 {
      font-size: 20px;
      color: #1a1a1a;
      margin-top: 30px;
      margin-bottom: 15px;
      font-weight: 600;
      border-left: 4px solid #007aff;
      padding-left: 12px;
    }
    p {
      text-align: justify;
      margin-bottom: 16px;
      text-indent: 2em;
    }
    .twitter-copy {
      background: #f5f5f5;
      padding: 15px;
      border-radius: 8px;
      margin: 20px 0;
      font-size: 15px;
    }
    .video-info {
      background: #f0f7ff;
      padding: 15px;
      border-radius: 8px;
      margin: 20px 0;
    }
    .video-title {
      font-size: 18px;
      font-weight: 600;
      color: #007aff;
      margin-bottom: 10px;
    }
    .script {
      font-size: 14px;
      line-height: 1.6;
      color: #555;
    }
    .cover-keywords {
      color: #999;
      font-size: 12px;
      text-align: center;
      margin-top: 30px;
      padding-top: 20px;
      border-top: 1px solid #eee;
    }
  </style>
</head>
<body>

<h1>${data.wechat_title}</h1>

${data.wechat_content.split('\n').map(line => {
  if (line.startsWith('# ')) return `<h1 style="text-align:center;font-size:24px;margin:30px 0;">${line.slice(2)}</h1>`;
  if (line.startsWith('## ')) return `<h2>${line.slice(3)}</h2>`;
  if (line.startsWith('### ')) return `<h3 style="font-size:17px;color:#333;margin:20px 0 10px;">${line.slice(4)}</h3>`;
  if (line.trim() === '---') return '<hr style="border:none;border-top:1px solid #eee;margin:30px 0;">';
  if (line.startsWith('- ') || line.startsWith('* ')) return `<li style="margin:8px 0;">${line.slice(2)}</li>`;
  if (line.trim() === '') return '';
  return `<p>${line}</p>`;
}).join('\n')}

<div class="twitter-copy">
  <strong>📱 X/Twitter 文案：</strong><br>
  ${data.twitter_copy.replace(/\n/g, '<br>')}
</div>

<div class="video-info">
  <div class="video-title">🎬 视频标题：${data.video_title}</div>
  <div class="script">
    <strong>口播脚本：</strong><br>
    ${data.video_script.replace(/\n/g, '<br>')}
  </div>
</div>

<div class="cover-keywords">
  封面图关键词：${data.cover_keywords?.join(' | ')}<br>
  原文路径：${$('Webhook Trigger').first().json.body.source_path}
</div>

</body>
</html>`;

return {
  json: {
    html_path: htmlPath,
    html_content: html
  }
};
```

---

### 节点 8️⃣：Write .html File（新增）

**类型：** Write Binary File / ReadWriteFile
**名称：** `Write WeChat HTML`

**配置：**
- Operation: `write`
- File Path: `=/home/node/.n8n-files/{{ $json.body.output_name }}_output.html`
- Content: `={{ $json.html_content }}`

**注意：** 输出到 n8n-files/ 目录，由 OpenClaw 负责复制回 Obsidian。

---

### 节点 9️⃣：Send Telegram Message

**类型：** Telegram
**名称：** `Send Telegram Message`

**配置：**
- Chat ID: `5038825565`
- Text:
```
✅ 文章转换完成！

📝 标题：{{ $json.wechat_title }}
📁 Markdown：/home/node/.n8n-files/{{ $json.body.output_name }}_output.md
🌐 HTML：/home/node/.n8n-files/{{ $json.body.output_name }}_output.html
🐦 Twitter 文案：{{ $json.twitter_copy }}
```
- Credentials: `Telegram XingJiang Bot`

**注意：** Telegram 只通知完成，OpenClaw 收到通知后负责将文件复制回 Obsidian。

---

## 🔗 完整节点连接图（v5）

```
┌─────────────────────────────────┐
│  Webhook Trigger                │
│  POST /content-translation-v5  │
└──────────────┬──────────────────┘
               │
               ▼
┌─────────────────────────────────┐
│  Read Obsidian Note             │
│  (Read Binary File)            │
└──────────────┬──────────────────┘
               │
               ▼
┌─────────────────────────────────┐
│  Extract from File              │
│  (text operation)               │
└──────────────┬──────────────────┘
               │
    ┌──────────┴──────────┐
    │                      │
    │              ┌───────┴────────┐
    │              │ DeepSeek       │
    │              │ Chat Model     │
    │              └───────┬────────┘
    │                      │
    ▼                      ▼
┌─────────────────────────────────┐
│  AI Agent (LangChain)           │
│  - system prompt               │
│  - original content            │
└──────────────┬──────────────────┘
               │
               ▼
┌─────────────────────────────────┐
│  Build Markdown (NEW)           │
│  组装中文 Markdown 文件         │
└──────────────┬──────────────────┘
               │
               ▼
┌─────────────────────────────────┐
│  Write Markdown Note (NEW)     │
│  → content-output/*.md         │
└──────────────┬──────────────────┘
               │
               ▼
┌─────────────────────────────────┐
│  Build WeChat HTML (NEW)        │
│  Markdown → 带样式 HTML         │
└──────────────┬──────────────────┘
               │
               ▼
┌─────────────────────────────────┐
│  Write WeChat HTML (NEW)        │
│  → content-output/*.html        │
└──────────────┬──────────────────┘
               │
               ▼
┌─────────────────────────────────┐
│  Send Telegram Message          │
│  文章转换完成通知               │
└─────────────────────────────────┘
```

---

## 🔄 调用方式（OpenClaw 侧）

**重要说明：n8n 只能读写 `/home/node/.n8n-files/` 目录，无法直接访问 Obsidian 目录。因此 OpenClaw 负责文件搬运，n8n 专注处理。**

### OpenClaw 完整流程：

```bash
# =============================================
# 步骤 1：OpenClaw 复制原文到 n8n-files 目录
# =============================================
# SSH 到 MacMini，将源文件复制到 n8n 容器可访问的目录
scp /Users/weishen/Workspace/nexus/openclaw/content-queue/article-2026-03-29.md \
    macmini:/home/node/.n8n-files/article-2026-03-29.md

# =============================================
# 步骤 2：OpenClaw 触发 n8n Webhook
# =============================================
curl -X POST "https://n8n.ishenwei.online/webhook/content-translation-v5" \
  -H "Content-Type: application/json" \
  -d '{
    "note_name": "article-2026-03-29.md",
    "source_path": "/Users/weishen/Workspace/nexus/openclaw/content-queue/article-2026-03-29.md",
    "output_name": "article-2026-03-29",
    "callback_url": "http://192.168.3.189:18789/webhook/yunce"
  }'

# =============================================
# 步骤 3：n8n 流程执行中...
# =============================================
# n8n 读取 /home/node/.n8n-files/article-2026-03-29.md
# 处理（翻译、改写）
# 输出到 /home/node/.n8n-files/article-2026-03-29_output.md
# 输出到 /home/node/.n8n-files/article-2026-03-29_output.html
# 发送 Telegram 通知

# =============================================
# 步骤 4：OpenClaw 复制输出文件回 Obsidian（工作流完成后）
# =============================================
# 复制 Markdown 成品
scp macmini:/home/node/.n8n-files/article-2026-03-29_output.md \
    /Users/weishen/Workspace/nexus/openclaw/content-output/article-2026-03-29.md

# 复制 HTML 成品
scp macmini:/home/node/.n8n-files/article-2026-03-29_output.html \
    /Users/weishen/Workspace/nexus/openclaw/content-output/article-2026-03-29.html

# =============================================
# 步骤 5：清理 n8n-files 临时文件（可选）
# =============================================
ssh macmini "rm /home/node/.n8n-files/article-2026-03-29.md \
                  /home/node/.n8n-files/article-2026-03-29_output.md \
                  /home/node/.n8n-files/article-2026-03-29_output.html"
```

### 简化版 OpenClaw 代码流程：

```python
import subprocess

note_name = "article-2026-03-29.md"
source_path = "/Users/weishen/Workspace/nexus/openclaw/content-queue/" + note_name
output_name = note_name.replace('.md', '')
n8n_files = "/home/node/.n8n-files"

# 1. 复制原文到 n8n-files
subprocess.run(['scp', source_path, f'macmini:{n8n_files}/{note_name}'])

# 2. 触发 Webhook
subprocess.run(['curl', '-X', 'POST',
    'https://n8n.ishenwei.online/webhook/content-translation-v5',
    '-H', 'Content-Type: application/json',
    '-d', f'{{"note_name": "{note_name}", "output_name": "{output_name}", ...}}'
])

# 3. 等待 Telegram 通知（工作流完成）

# 4. 复制输出回 Obsidian
subprocess.run(['scp',
    f'macmini:{n8n_files}/{output_name}_output.md',
    f'/Users/weishen/Workspace/nexus/openclaw/content-output/{output_name}.md'])
subprocess.run(['scp',
    f'macmini:{n8n_files}/{output_name}_output.html',
    f'/Users/weishen/Workspace/nexus/openclaw/content-output/{output_name}.html'])
```

---

## 📁 最终 Obsidian 目录结构

```
~/Workspace/nexus/openclaw/
├── content-queue/                                      # 原始英文（输入，OpenClaw 放置）
│   └── article-2026-03-29.md
│
└── content-output/                                    # 成品（OpenClaw 从 n8n-files/ 复制回来）
    ├── article-2026-03-29.md                          # 中文 Markdown ✅
    └── article-2026-03-29.html                        # 公众号 HTML ✅
```

**文件来源说明：**
- n8n 工作流只读写 `/home/node/.n8n-files/` 目录
- OpenClaw 在工作流完成后负责将输出文件复制到 Obsidian 目录

---

## ✅ 验收标准

1. 触发后自动完成整个流程，无需人工干预
2. `content-output/` 目录同时生成 `.md` 和 `.html` 两个文件
3. HTML 文件可直接复制粘贴到微信公众号编辑器，格式基本正确
4. Telegram 收到完成通知（含标题和文件路径）
5. 错误时 n8n 记录错误节点并停止流程

---

## 📝 备注

- **Markdown 源文件**：保留中文原文，方便后续修改和溯源
- **HTML 文件**：带内联样式，兼容微信公众号编辑器，复制后格式不走形
- **文件路径**：写入 Obsidian vault 的 `content-output/` 子目录，需确保 n8n 容器有对应目录的写权限
- **API Key**：DeepSeek API 通过 n8n credential 配置，无需在代码中硬编码
# 📖 附录：OpenClaw ↔ N8N 通用工作流调用规范（v1.0）

> 本规范旨在为 OpenClaw 与 N8N 之间的每次交互建立统一标准，使星辉（XingHui）或其他 Agent 能够通过标准化步骤执行任意 N8N 工作流。
>
> **适用范围**：任何由 OpenClaw 触发、N8N 执行的工作流（不仅限于内容转化流水线）
>
> **核心约束**：N8N 容器只读写 `/home/node/.n8n-files/` 目录，无法直接访问 Obsidian 或其他宿主机路径。OpenClaw 负责所有文件搬运。

---

## 🏗️ 架构总览

```
OpenClaw                          N8N 容器                    其他存储
  Agent                          (/home/node/.n8n-files/)      位置
    │                                    │                       │
    │ ── ① 复制输入文件 ─────────────────→│                       │
    │                                    │                       │
    │ ── ② POST webhook ─────────────────→│                       │
    │                                    │                       │
    │                            [N8N 执行工作流]                  │
    │                                    │                       │
    │ ←── ③ Telegram / callback 通知 ───│                       │
    │                                    │                       │
    │ ←── ④ 复制输出文件 ─────────────────│──→ Obsidian 目录      │
    │                                    │                       │
    │ ── ⑤ 清理 n8n-files ───────────────→│                       │
```

---

## 📋 标准化执行步骤（星辉操作指南）

### 步骤 ①：准备输入文件

**规则**：所有传递给 N8N 的文件，必须先复制到 N8N 容器可访问的路径。

**源路径**（由具体任务决定）× → **目标路径**：`macmini:/home/node/.n8n-files/{文件名}`

**示例（内容转化流水线 v5）**：
```bash
scp /Users/weishen/Workspace/nexus/openclaw/content-queue/article-2026-03-29.md \
    macmini:/home/node/.n8n-files/article-2026-03-29.md
```

---

### 步骤 ②：触发 Webhook

**规则**：通过 `curl` 向 N8N Webhook 端点发送 POST 请求，JSON 数据包含工作流所需的所有元数据。

**通用格式**：
```bash
curl -X POST "<N8N_BASE_URL>/webhook/<webhook-path>" \
  -H "Content-Type: application/json" \
  -d '{
    "note_name": "<文件名>",
    "source_path": "<原始文件路径>",
    "output_name": "<输出文件名（不含扩展名）>",
    "callback_url": "<完成后通知地址（可选）>"
  }'
```

**具体示例（内容转化流水线 v5）**：
```bash
curl -X POST "https://n8n.ishenwei.online/webhook/content-translation-v5" \
  -H "Content-Type: application/json" \
  -d '{
    "note_name": "article-2026-03-29.md",
    "source_path": "/Users/weishen/Workspace/nexus/openclaw/content-queue/article-2026-03-29.md",
    "output_name": "article-2026-03-29",
    "callback_url": "http://192.168.3.189:18789/webhook/yunce"
  }'
```

**Webhook Path 查询方式**：
如不知道目标工作流的 Webhook path，可通过以下方式确认：
1. 在 n8n 管理界面（https://n8n.ishenwei.online）打开对应工作流
2. 点击 Webhook 节点，查看右侧 Path 字段
3. 或参考本文档相关章节的「Webhook Trigger」配置

---

### 步骤 ③：等待执行完成

**规则**：N8N 工作流完成后会发送通知，OpenClaw 需等待此信号后再执行后续复制操作。

**通知方式**（由具体工作流决定，优先级如下）：

| 方式 | 说明 | 适用场景 |
|------|------|---------|
| **Telegram Bot** | N8N 通过 Telegram 节点发送消息到指定 Chat ID | 推荐，已知用户 Chat ID |
| **Callback URL** | N8N POST 到指定 URL（OpenClaw Webhook） | 需要 OpenClaw 监听端口 |
| **轮询 n8n API** | 定期查询工作流执行状态 | 无通知配置时兜底 |

**Telegram 通知格式（示例）**：
```
✅ [工作流名称] 执行完成！

📝 标题：<title>
📁 输出文件：/home/node/.n8n-files/<output_name>_output.md
🌐 HTML：/home/node/.n8n-files/<output_name>_output.html
```

---

### 步骤 ④：复制输出文件

**规则**：收到完成通知后，从 N8N 容器的 `n8n-files/` 目录复制输出文件到目标存储位置。

**通用格式**：
```bash
# 单文件
scp macmini:/home/node/.n8n-files/<输出文件名> <目标完整路径>

# 多文件（循环）
for file in <输出文件1> <输出文件2>; do
    scp macmini:/home/node/.n8n-files/$file <目标目录>/$file
done
```

**具体示例（内容转化流水线 v5）**：
```bash
# 复制 Markdown 成品
scp macmini:/home/node/.n8n-files/article-2026-03-29_output.md \
    /Users/weishen/Workspace/nexus/openclaw/content-output/article-2026-03-29.md

# 复制 HTML 成品
scp macmini:/home/node/.n8n-files/article-2026-03-29_output.html \
    /Users/weishen/Workspace/nexus/openclaw/content-output/article-2026-03-29.html
```

---

### 步骤 ⑤：清理临时文件

**规则**：工作流完成后，删除 `n8n-files/` 下的临时文件，保持容器目录整洁。

**通用格式**：
```bash
ssh macmini "rm /home/node/.n8n-files/<输入文件> /home/node/.n8n-files/<输出文件1> /home/node/.n8n-files/<输出文件2>"
```

**具体示例（内容转化流水线 v5）**：
```bash
ssh macmini "rm /home/node/.n8n-files/article-2026-03-29.md \
                  /home/node/.n8n-files/article-2026-03-29_output.md \
                  /home/node/.n8n-files/article-2026-03-29_output.html"
```

---

## 🔧 OpenClaw 自动化脚本模板（Python）

以下为通用 Python 模板，适用于任何 OpenClaw → N8N 的文件处理工作流。星辉可直接复制修改使用。

```python
import subprocess
import time
import sys

# ========== 配置区（每个工作流需修改） ==========
N8N_BASE_URL = "https://n8n.ishenwei.online"
WEBHOOK_PATH = "content-translation-v5"   # <-- 修改为实际 webhook path
SOURCE_FILE = "/path/to/source/file.md"   # <-- 修改为实际源文件路径
N8N_FILES = "/home/node/.n8n-files"
NOTE_NAME = "source-file.md"              # <-- 修改为实际文件名
OUTPUT_NAME = "source-file"              # <-- 修改为输出文件名（无扩展名）
OUTPUT_DIR = "/Users/weishen/Workspace/nexus/openclaw/content-output"
# ============================================

source_path = SOURCE_FILE
n8n_input_path = f"{N8N_FILES}/{NOTE_NAME}"

print(f"[Step 1/5] 复制输入文件到 N8N 容器: {NOTE_NAME}")
result = subprocess.run(
    ['scp', source_path, f'macmini:{n8n_input_path}'],
    capture_output=True, text=True
)
if result.returncode != 0:
    print(f"X 文件复制失败: {result.stderr}")
    sys.exit(1)
print(f"V 已复制到 {n8n_input_path}")

print(f"[Step 2/5] 触发 N8N Webhook: {WEBHOOK_PATH}")
webhook_url = f"{N8N_BASE_URL}/webhook/{WEBHOOK_PATH}"
payload = ("{"
           "\"note_name\": \"" + NOTE_NAME + "\", "
           "\"source_path\": \"" + source_path + "\", "
           "\"output_name\": \"" + OUTPUT_NAME + "\""
           "}")
result = subprocess.run(
    ['curl', '-X', 'POST', webhook_url,
     '-H', 'Content-Type: application/json',
     '-d', payload],
    capture_output=True, text=True
)
print(f"Webhook 触发响应: {result.stdout[:200]}")

print("[Step 3/5] 等待 N8N 执行完成（Telegram 通知将发送到本会话）...")
print("请等待 Telegram 通知，收到后继续执行步骤 4。")
print("如需手动检查状态，请访问: https://n8n.ishenwei.online")
sys.exit(0)  # <-- 此处退出，等待 Telegram 通知后再手动执行步骤 4

# ---- 以下为步骤 4 和 5，需在收到 Telegram 通知后执行 ----

output_files = [f"{OUTPUT_NAME}_output.md", f"{OUTPUT_NAME}_output.html"]

print(f"[Step 4/5] 复制输出文件回 Obsidian...")
for file in output_files:
    src = f"macmini:{N8N_FILES}/{file}"
    dst = f"{OUTPUT_DIR}/{file}"
    result = subprocess.run(['scp', src, dst], capture_output=True, text=True)
    if result.returncode == 0:
        print(f"  V {file}")
    else:
        print(f"  X {file}: {result.stderr}")

print(f"[Step 5/5] 清理 N8N 容器临时文件...")
files_to_clean = [NOTE_NAME] + output_files
result = subprocess.run(
    ['ssh', 'macmini', 'rm'] + [f"{N8N_FILES}/{f}" for f in files_to_clean],
    capture_output=True, text=True
)
if result.returncode == 0:
    print("  V 清理完成")
else:
    print(f"  ! 清理失败（不影响结果）: {result.stderr}")

print("🎉 工作流执行完毕！")
```

---

## 📦 速查表：常见工作流配置

| 工作流 | Webhook Path | 输入文件规则 | 输出文件规则 | 通知方式 |
|--------|-------------|-------------|-------------|---------|
| 内容转化 v5 | `content-translation-v5` | `content-queue/*.md` | `content-output/*_output.md` + `*_output.html` | Telegram |
| （待补充） | | | | |

> **添加新工作流时**：在此表新增一行，注明 Webhook Path 和文件路径规则，星辉即可照此执行。

---

## ⚠️ 异常处理规范

| 异常情况 | 处理方式 |
|---------|---------|
| `scp` 文件复制失败 | 检查源文件是否存在、检查目标目录权限 |
| `curl` Webhook 请求超时 | 重试 1 次（间隔 5 秒），仍失败则中止并通知用户 |
| Telegram 未收到完成通知 | 登录 n8n 管理界面 → 查看对应工作流执行记录 |
| 输出文件复制失败 | 检查 n8n-files 中是否已生成文件，确认文件名是否匹配 |
| N8N 工作流报错 | 登录 n8n 管理界面 → 打开对应工作流 → 查看错误节点日志 |

---

## 🔑 关键约束汇总

1. **N8N 容器路径**：`/home/node/.n8n-files/`（只读/写此目录）
2. **文件传输方式**：`scp` via `macmini` 主机名
3. **Webhook 触发**：统一使用 `curl -X POST`，Content-Type 为 `application/json`
4. **通知等待**：必须等待 Telegram/callback 通知后再复制输出文件，不得跳过
5. **清理时机**：步骤 4 成功后再执行清理，步骤 4 失败时不清理（保留现场）
6. **配置文件**：`~/.openclaw/.env` 中的 `N8N_API_KEY` 和 `N8N_BASE_URL` 供脚本读取
