内容
# BlogCaster
基于 CLI 的代理,从基于 Hugo 的博客平台通过 RSS 源获取博客帖子,使用 LLM 将其格式化为特定于平台的社交媒体帖子,并发布到 LinkedIn、X(Twitter)和 Facebook。
该代理由平台驱动 - 每个博客平台都注册在 JSON 注册表中,代理可以独立地针对每个平台运行。添加新的博客平台只需要注册文件中的新条目,无需更改代码。
## 工作原理
```
RSS 源 ──> 记录检查 ──> 帖子选择 ──> LLM 格式化 ──> LinkedIn + X + Facebook 帖子 ──> 记录保存
```
五个 FastMCP 服务器处理核心操作,由中央协调器协调:
| MCP 服务器 | 角色 |
|---|---|
| **rss-fetcher** | 获取并解析 Hugo RSS 源和单个博客帖子 |
| **record-keeper** | 跟踪已发布的帖子以 JSON 格式,防止重复 |
| **linkedin-poster** | 将格式化内容发布到 LinkedIn 个人资料 |
| **x-poster** | 通过 tweepy 将格式化推文发布到 X(Twitter) |
| **facebook-poster** | 通过 Graph API 将格式化内容发布到 Facebook 页面 |
## 两种操作模式
### 手动模式
提供特定的博客帖子 URL。代理自动检测平台,获取内容,格式化,发布到 LinkedIn、X 和 Facebook,并记录结果。也用于重试以前发布的 URL 的失败平台。
```bash
python -m agent_engine.social_agent.main --url "https://blog.aspose.com/some-post"
```
### 自动模式
指定平台 ID。代理获取 RSS 源,选择最新的未发布的帖子,格式化,发布到 LinkedIn、X 和 Facebook,并记录结果。
```bash
python -m agent_engine.social_agent.main --auto --platform aspose
python -m agent_engine.social_agent.main --auto --platform groupdocs
python -m agent_engine.social_agent.main --auto --platform conholdate
```
## 先决条件
- Python 3.10+
- 自托管的 GPT-OSS LLM 端点(兼容 OpenAI API)
- 具有 `w_member_social` 作用域的 LinkedIn OAuth 2.0 访问令牌
- 具有读取和写入权限的 X(Twitter)OAuth 1.0a 凭证
- 具有 `pages_read_engagement` 和 `pages_manage_posts` 权限的 Facebook 页面访问令牌
## 设置
### 1. 克隆并导航到项目
```bash
cd socialAgent
```
### 2. 安装依赖项
```bash
pip install mcp feedparser httpx beautifulsoup4 aiofiles pydantic-settings openai tweepy
```
### 3. 配置环境变量
复制示例文件并填写您的凭证:
```bash
cp .env.example .env
```
编辑 `.env` 文件并填写您的值:
```
# LLM 配置(GPT-OSS)
PROFESSIONALIZE_BASE_URL=https://your-gpt-oss-endpoint.com/v1
PROFESSIONALIZE_API_KEY_2=your-api-key
PROFESSIONALIZE_LLM_MODEL=your-model-name
# LinkedIn 配置
LINKEDIN_ACCESS_TOKEN=your-linkedin-oauth-token
# X(Twitter)配置
X_API_KEY=your-x-api-key
X_API_SECRET=your-x-api-secret
X_ACCESS_TOKEN=your-x-access-token
X_ACCESS_TOKEN_SECRET=your-x-access-token-secret
# Facebook 页面配置(默认 - 由 aspose-cloud 使用)
FACEBOOK_PAGE_ID=your-facebook-page-id
FACEBOOK_PAGE_ACCESS_TOKEN=your-facebook-page-access-token
# Facebook 页面配置(特定于平台的重写)
FACEBOOK_GROUPDOCS_PAGE_ID=your-groupdocs-facebook-page-id
FACEBOOK_GROUPDOCS_PAGE_ACCESS_TOKEN=your-groupdocs-facebook-page-access-token
FACEBOOK_CONHOLDATE_PAGE_ID=your-conholdate-facebook-page-id
FACEBOOK_CONHOLDATE_PAGE_ACCESS_TOKEN=your-conholdate-facebook-page-access-token
```
| 变量 | 描述 |
|---|---|
| `PROFESSIONALIZE_BASE_URL` | 您的 OpenAI 兼容 LLM 端点的基 URL |
| `PROFESSIONALIZE_API_KEY_2` | LLM 端点的 API 密钥 |
| `PROFESSIONALIZE_LLM_MODEL` | 用于文本生成的模型名称 |
| `LINKEDIN_ACCESS_TOKEN` | 预生成的 LinkedIn OAuth 2.0 访问令牌 |
| `X_API_KEY` | X(Twitter)API 消费者密钥 |
| `X_API_SECRET` | X(Twitter)API 消费者密钥 |
| `X_ACCESS_TOKEN` | X(Twitter)OAuth 1.0a 访问令牌 |
| `X_ACCESS_TOKEN_SECRET` | X(Twitter)OAuth 1.0a 访问令牌秘密 |
| `FACEBOOK_PAGE_ID` | Facebook 页面数字 ID(默认,由 aspose-cloud 使用) |
| `FACEBOOK_PAGE_ACCESS_TOKEN` | Facebook 页面访问令牌(默认,由 aspose-cloud 使用) |
| `FACEBOOK_{BRAND}_PAGE_ID` | 特定于平台的 Facebook 页面 ID(例如 `FACEBOOK_GROUPDOCS_PAGE_ID`) |
| `FACEBOOK_{BRAND}_PAGE_ACCESS_TOKEN` | 特定于平台的 Facebook 页面访问令牌 |
## LinkedIn 令牌更新
LinkedIn OAuth 令牌每 **60 天** 过期一次。当代理记录 `LinkedIn 令牌无效或过期` 时,请按照以下步骤更新:
### 步骤 1:生成新令牌
1. 访问 [LinkedIn 开发者应用](https://www.linkedin.com/developers/apps)
2. 选择您的应用
3. 进入 **Auth** 标签
4. 在 **OAuth 2.0 工具**下,单击 **生成令牌**
5. 选择作用域:`w_member_social`、`openid`、`profile`
6. 授权并复制新令牌
> **注意:**令牌生成在 **Safari** 上有效,但在 Google Chrome 上可能会失败。如果在 Chrome 上出现错误,请切换到 Safari。
### 步骤 2:更新凭证
1. 在本地 `.env` 文件中更新 `LINKEDIN_ACCESS_TOKEN`
2. 在 GitHub 仓库 **设置 > 机密和变量 > 操作** 中更新 `LINKEDIN_ACCESS_TOKEN`(适用于 GitHub 操作)
3. 更新 `LINKEDIN_TOKEN_EXPIRES_AT` 为新的过期日期(今天 + 60 天):
```
LINKEDIN_TOKEN_EXPIRES_AT=2026-07-19
```
代理在令牌过期前 7 天打印控制台警告,以便您可以主动更新。
## Facebook 页面设置
Facebook 需要 **页面访问令牌**(而非用户访问令牌)来发布到页面。请按照以下步骤:
### 步骤 1:创建 Facebook 应用
1. 访问 [Facebook 开发者](https://developers.facebook.com/) 并创建应用(类型:商业)
2. 将“适用于商业的 Facebook 登录”产品添加到您的应用中
### 步骤 2:获取用户访问令牌
1. 访问 [Graph API 资源管理器](https://developers.facebook.com/tools/explorer/)
2. 从下拉菜单中选择您的应用
3. 点击“生成访问令牌”
4. 授予这些权限:`pages_read_engagement`、`pages_manage_posts`
### 步骤 3:交换为页面访问令牌
用户令牌允许您访问您的页面,但您需要 **页面的令牌** 来发布。运行:
```bash
curl "https://graph.facebook.com/v21.0/me/accounts?access_token=YOUR_USER_TOKEN"
```
这将返回您管理的页面列表:
```json
{
"data": [
{
"access_token": "EAAxxxxx_PAGE_TOKEN_xxxxx",
"name": "您的页面名称",
"id": "123456789012345"
}
]
}
```
复制 `access_token` 和 `id` 来自页面条目。
### 步骤 4:验证页面令牌
```bash
curl "https://graph.facebook.com/v21.0/me?access_token=YOUR_PAGE_TOKEN"
```
这应该返回 **页面** 的名称和 ID(而非您的个人姓名)。如果它显示页面名称,则令牌是正确的。
### 步骤 5:更新 `.env`
```
FACEBOOK_PAGE_ID=123456789012345
FACEBOOK_PAGE_ACCESS_TOKEN=EAAxxxxx_PAGE_TOKEN_xxxxx
```
### 步骤 6:测试
```bash
python -m agent_engine.social_agent.main --url "https://blog.aspose.com/some-post" --target facebook
```
### 常见错误:使用用户令牌而非页面令牌
如果您看到此错误:
```
权限不足以发布:(#200)如果发布到组,需要应用已安装在组中...
```
您正在使用 **用户访问令牌** 而非 **页面访问令牌**。返回步骤 3 并使用 `me/accounts` 端点获取页面的令牌。
### 令牌过期和长期令牌
Graph API 资源管理器中的令牌在 ~1 小时内过期。对于生产使用,请交换为 **长期令牌**(~60 天):
**1. 将短期用户令牌交换为长期用户令牌:**
```bash
curl -G "https://graph.facebook.com/v19.0/oauth/access_token" \
--data-urlencode "grant_type=fb_exchange_token" \
--data-urlencode "client_id=YOUR_APP_ID" \
--data-urlencode "client_secret=YOUR_APP_SECRET" \
--data-urlencode "fb_exchange_token=YOUR_SHORT_LIVED_USER_TOKEN"
```
响应:
```json
{
"access_token": "LONG_LIVED_USER_TOKEN",
"token_type": "bearer",
"expires_in": 5183423
}
```
`expires_in` 为秒数(~60 天)。
**2. 将长期用户令牌交换为页面令牌:**
```bash
curl "https://graph.facebook.com/v19.0/me/accounts?access_token=LONG_LIVED_USER_TOKEN"
```
长期用户令牌返回的页面令牌 **不会过期**。复制 `access_token` 和 `id` 来自您的页面条目并更新 `.env` / GitHub 操作机密。
**3. 验证您的令牌:**
```bash
curl "https://graph.facebook.com/v19.0/debug_token?input_token=YOUR_PAGE_TOKEN&access_token=YOUR_APP_ID|YOUR_APP_SECRET"
```
检查 `expires_at` - 值为 `0` 表示令牌永不过期。
**安全注意事项:**
- 永远不要在前端代码中公开 `client_secret`
- 将令牌存储在环境变量或 GitHub 操作机密中
- 如果令牌暴露,请立即轮换凭据
## 用法
所有命令必须从项目根目录运行。
### 发布特定博客网址(手动模式)
```bash
python -m agent_engine.social_agent.main --url "https://blog.aspose.com/some-post"
```
### 发布来自平台的最新未发布博客(自动模式)
```bash
python -m agent_engine.social_agent.main --auto --platform aspose
```
### 针对特定社交媒体平台
```bash
# 仅发布到 Facebook
python -m agent_engine.social_agent.main --url "https://blog.aspose.com/some-post" --target facebook
# 仅发布到 LinkedIn
python -m agent_engine.social_agent.main --url "https://blog.aspose.com/some-post" --target linkedin
# 仅发布到 X
python -m agent_engine.social_agent.main --url "https://blog.aspose.com/some-post" --target x
# 发布到所有平台(默认)
python -m agent_engine.social_agent.main --url "https://blog.aspose.com/some-post" --target all
```
### 列出可用平台
```bash
python -m agent_engine.social_agent.main --auto
```
输出:
```
错误:--platform 与 --auto 一起使用是必需的
可用平台:
- aspose (Aspose 博客)
- groupdocs (GroupDocs 博客)
- conholdate (Conholdate 博客)
```
### 显示用法帮助
```bash
python -m agent_engine.social_agent.main
```
## 添加新博客平台
添加新品牌需要 **无需代码更改** - 只需配置:
### 1. 添加到平台注册表
编辑 `registry/platforms_registry.json` 并添加新条目:
```json
{
"id": "conholdate",
"name": "Conholdate 博客",
"url": "https://blog.conholdate.com",
"rss_feed": "https://blog.conholdate.com/index.xml",
"active": true
}
```
### 2. 添加特定于平台的 Facebook 凭证
Facebook 凭证根据平台名称动态解析。命名约定:
```
FACEBOOK_{BRAND}_PAGE_ID
FACEBOOK_{BRAND}_PAGE_ACCESS_TOKEN
```
其中 `{BRAND}` 是平台 ID 的第一部分(在 `-` 之前,大写)。
| 平台 ID | Facebook 环境变量 |
|---|---|
| `aspose-cloud` | `FACEBOOK_PAGE_ID` + `FACEBOOK_PAGE_ACCESS_TOKEN`(默认) |
| `groupdocs-cloud` | `FACEBOOK_GROUPDOCS_PAGE_ID` + `FACEBOOK_GROUPDOCS_PAGE_ACCESS_TOKEN` |
| `conholdate-cloud` | `FACEBOOK_CONHOLDATE_PAGE_ID` + `FACEBOOK_CONHOLDATE_PAGE_ACCESS_TOKEN` |
将这些添加到您的 `.env` 文件中本地和 GitHub Actions 机密中。
如果找不到特定于平台的凭证,则使用默认的 `FACEBOOK_PAGE_ID` / `FACEBOOK_PAGE_ACCESS_TOKEN`。
LinkedIn 和 X 凭证在所有品牌之间共享。
### 3. 创建 GitHub Actions 工作流
复制现有工作流文件(例如 `.github/workflows/blogcaster-groupdocs-cloud.yml`)并更改:
- `name`: `BlogCaster — 您的品牌`
- `schedule`: 选择不与其他工作流重叠的日子
- `platform default`: 您的平台 ID(例如 `conholdate-cloud`)
- Facebook 环境变量:使用您的品牌特定机密名称
当前计划:
| 工作流 | 天数 | Cron |
|---|---|---|
| BlogCaster — Aspose Cloud | 星期一和星期五 | `0 5 * * 1,5` |
| BlogCaster — GroupDocs Cloud | 星期二和星期四 | `0 5 * * 2,4` |
### 4. 在本地测试
```bash
python -m agent_engine.social_agent.main --auto --platform conholdate-cloud --target facebook
```
### 5. 在 GitHub Actions 上测试
在操作选项卡中手动触发 `workflow_dispatch`,然后确认计划运行在预期日期触发。
## 项目结构
```
socialAgent/
├── agent_engine/
│ └── social_agent/
│ ├── main.py # CLI 入口点
│ ├── config.py # Pydantic BaseSettings 配置
│ ├── agent_logic/
│ │ └── orchestrator.py # 核心工作流(手动 + 自动模式)
│ ├── tools/
│ │ └── mcp_tools.py # MCP 服务器包装器
│ └── utils/
│ ├── helpers.py # 日记设置 + 注册表帮助程序
│ ├── llm_service.py # 通过 OpenAI SDK 进行 LLM 格式化
│ └── prompts.py # 特定于平台的提示模板
├── mcp-servers/
│ ├── rss-fetcher/server.py # RSS 源解析(feedparser + httpx + bs4)
│ ├── linkedin-poster/server.py # LinkedIn API 发布(httpx)
│ ├── x-poster/server.py # X(Twitter)API 发布(tweepy)
│ ├── facebook-poster/server.py # Facebook 页面发布(httpx + Graph API)
│ └── record-keeper/server.py # 基于 JSON 的记录存储(aiofiles)
├── registry/
│ └── platforms_registry.json # 博客平台注册表
├── content/
│ └── records/
│ └── published_record.json # 已发布记录
├── logs/
│ └── logs.txt # 应用日志
├── .env # 凭证(不提交)
├── .env.example # 凭证模板
└-- .gitignore
```