Friend 仓库中的 Twitter/X Omi 插件实战:OAuth2 授权、Railway 部署与对话式推文管理
【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/Friend
本文围绕 Friend 开源仓库中的omi-twitter-chat-tools-app插件(文档见 README.md),完整讲解如何把 Twitter/X 账号接入 Omi 对话助手:从创建 Twitter Developer App、通过 PKCE OAuth2 完成用户授权,到在 Railway 上部署 FastAPI 服务、配置 Omi App 的三个关键 URL,再到对话中发推、刷时间线、搜索、点赞、转发等十大 Chat Tools 的调用方式。读完本文,你将掌握一套可直接复制上线的"OAuth 授权 + Chat Tools Manifest + 对话式操作"插件实现方案,并理解其底层源码的运行原理。
插件定位与功能总览
omi-twitter-chat-tools-app是 plugins 目录下 28 个独立部署的omi-*-app插件服务之一。与依赖plugins/main.py单体入口的旧插件不同,它拥有独立的main.py、依赖清单与部署描述文件(Procfile / railway.toml),可独立于单体和其他插件部署与扩容。
该插件通过 Omi 对话完成以下 Twitter/X 账号管理能力:
- 发推(Post Tweets):向粉丝发布更新,支持指定回复目标推文
- 查看时间线(View Timeline):读取用户首页 feed
- 查看我的推文(Get Your Tweets):查看最近发布记录
- 查看提及(Get Mentions):查看谁提到了你
- 搜索推文(Search Tweets):按关键词检索任何话题
- 点赞 / 取消点赞(Like / Unlike):与内容互动
- 转发(Retweet):把推文分享给粉丝
- 删除推文(Delete Tweets):移除自己的推文
- 查看资料(View Profiles):查询任意 Twitter 用户信息
这些能力在源码中一一对应为 10 个 Chat Tool 端点,全部声明在/.well-known/omi-tools.json清单中(见下文"Chat Tools Manifest"小节)。
整体架构:一条对话请求的完整链路
从用户对话到推文落地的数据流如下:
- 用户在 Omi 对话中说"发一条推文:xxx",Omi 客户端根据应用的Chat Tools Manifest URL拉取工具清单;
- Omi 匹配到
post_tweet工具,向插件的/tools/post_tweet端点发起 POST 请求,body 中携带uid(Omi 用户 ID)与参数text; - 插件从存储中取出该用户的 Twitter OAuth2 token,必要时自动刷新,然后调用 Twitter API v2;
- 插件将 Twitter 返回结果格式化为可读文本,通过
ChatToolResponse模型返回给 Omi,由对话助手展示给用户。
整条链路的核心实现在 main.py(FastAPI 应用,约 1300 行)、db.py(token 与状态存储)、models.py(响应模型)三个文件中。
第一步:创建 Twitter Developer App
1. 进入 Twitter Developer Portal
在 Twitter Developer Portal 的 Projects & Apps 页面新建 Project 与 App(或复用现有应用),然后进入User authentication settings配置:
- App permissions(应用权限):选择Read and write。该权限组合与源码中申请的 OAuth scopes 对应——见 main.py 中
TWITTER_SCOPES:
TWITTER_SCOPES = [ "tweet.read", "tweet.write", "users.read", "follows.read", "like.read", "like.write", "offline.access" ]其中tweet.write支撑发推/回复/转发/删除,like.write支撑点赞,follows.read支撑时间线,offline.access用于换取 refresh token(支撑后续的 token 自动刷新)。
- Type of App(应用类型):选择Web App
- Callback URI / Redirect URI:填写你的回调地址(生产环境为 Railway 域名,本地开发为
http://localhost:8080/auth/twitter/callback,详见下文) - Website URL:填写应用官网地址
完成后复制Client ID与Client Secret(Client Secret 仅显示一次,务必妥善保存)。
2. 可选:Twitter API v2 访问层级说明
该插件依赖Twitter API v2,不同 Developer 账号层级的能力与配额不同(以 Twitter 官方当前政策为准,仓库 README 中给出的参考数值如下):
- Free tier(免费层):每月约 1,500 条推文额度,基础读权限
- Basic tier(基础层):每月约 3,000 条推文额度,更多读权限
- Pro tier(专业层):更高额度与更多功能
部分功能(如查看时间线)可能需要更高层级的访问权限。如果调用时报权限错误,应先在 Developer Portal 确认账号层级与 App 权限配置。
第二步:部署到 Railway
Railway 是官方 README 推荐的部署方式,仓库内已备齐部署所需的所有文件:
- railway.toml:声明 nixpacks 构建器、启动命令、健康检查与重启策略
- Procfile:等价启动命令
uvicorn main:app --host 0.0.0.0 --port $PORT - requirements.txt:依赖清单
部署步骤
- 在 Railway 新建项目,连接包含本插件目录的 GitHub 仓库(或直接从
plugins/omi-twitter-chat-tools-app/目录部署); - 为项目添加一个Redis服务(插件用它持久化 token 与 OAuth state);
- 设置如下环境变量:
TWITTER_CLIENT_ID=your_client_id TWITTER_CLIENT_SECRET=your_client_secret TWITTER_REDIRECT_URI=https://your-app.up.railway.app/auth/twitter/callback- 触发部署。Railway 会自动完成:从
requirements.txt安装依赖、按 railway.toml 的startCommand启动服务,并注入PORT、REDIS_URL环境变量。
部署完成后,回到 Twitter Developer App 的User authentication settings,把回调地址更新为:
https://your-app.up.railway.app/auth/twitter/callback注意回调地址必须与TWITTER_REDIRECT_URI完全一致,否则 OAuth 授权会失败。
部署配置解读
railway.toml 的关键配置:
[build] builder = "nixpacks" [deploy] startCommand = "uvicorn main:app --host 0.0.0.0 --port $PORT" healthcheckPath = "/health" healthcheckTimeout = 100 restartPolicyType = "on_failure" restartPolicyMaxRetries = 3healthcheckPath = "/health"对应 main.py 中的健康检查端点,返回{"status": "healthy", "service": "twitter-omi"};startCommand读取 Railway 注入的$PORT;main.py 的入口同样支持PORT(默认 8080)与HOST(默认0.0.0.0)环境变量,本地直接python main.py也能以相同方式启动。
第三步:Omi App 配置
在 Omi 平台创建或更新该集成应用时,将以下三个 URL 填入对应字段({{uid}}是 Omi 在跳转时自动替换的用户 ID 占位符):
| 字段 | 值 |
|---|---|
| Setup URL | https://your-app.up.railway.app/?uid={{uid}} |
| Setup Completed URL | https://your-app.up.railway.app/setup/twitter?uid={{uid}} |
| Chat Tools Manifest URL | https://your-app.up.railway.app/.well-known/omi-tools.json |
三个 URL 各自的作用
- Setup URL:Omi 引导用户进入插件的设置页。带
uid访问/时,若该用户尚未连接 Twitter,页面会渲染"Connect Twitter"按钮;已连接则显示账号状态与"Disconnect"入口(main.py)。 - Setup Completed URL:Omi 用来轮询/判定用户是否完成授权。对应
/setup/twitter端点,返回{"is_setup_completed": true|false}——true表示该uid已存在有效 token。 - Chat Tools Manifest URL:Omi 发现可用对话工具的关键。对应
/.well-known/omi-tools.json端点,返回完整的工具声明 JSON。
API 端点总览
Chat Tools 端点(POST)
| 端点 | 功能 | 必需参数 |
|---|---|---|
/tools/post_tweet | 发布新推文 | text(≤280 字符),可选reply_to |
/tools/get_timeline | 获取首页时间线 | 可选max_results(默认 10,上限 100) |
/tools/get_my_tweets | 获取自己的推文 | 可选max_results |
/tools/get_mentions | 获取提及我的推文 | 可选max_results |
/tools/search_tweets | 搜索推文 | query,可选max_results |
/tools/like_tweet | 点赞推文 | tweet_id |
/tools/unlike_tweet | 取消点赞 | tweet_id |
/tools/retweet | 转发推文 | tweet_id |
/tools/delete_tweet | 删除推文 | tweet_id |
/tools/get_user_profile | 获取用户资料 | 可选username(缺省返回本人资料) |
所有 Chat Tool 请求的 body 都需携带uid字段。若用户未授权,端点统一返回错误提示Please connect your Twitter account first in the app settings.;max_results在服务端通过min(body.get("max_results", 10), 100)钳制上限。
OAuth 与设置端点(GET)
| 端点 | 功能 |
|---|---|
/ | 首页 / 设置 UI(支持?uid=<uid>) |
/auth/twitter?uid=<uid> | 发起 OAuth2 授权流程 |
/auth/twitter/callback | OAuth 回调(交换 code 为 token) |
/setup/twitter?uid=<uid> | 查询设置状态 |
/disconnect?uid=<uid> | 解绑账号(删除 token) |
/health | 健康检查 |
/.well-known/omi-tools.json | Chat Tools 工具清单 |
核心源码原理剖析
1. PKCE OAuth2 授权流程
插件采用OAuth2 Authorization Code + PKCE(S256)流程,实现在 main.py 的/auth/twitter与回调端点中:
- 生成 128 位随机
code_verifier(generate_code_verifier),并以其 SHA-256 摘要生成code_challenge(generate_code_challenge); - 构造
state = f"{uid}:{secrets.token_urlsafe(32)}",把 state 写入存储(CSRF 防护),把code_verifier写入用户设置; - 重定向到
https://twitter.com/i/oauth2/authorize,携带response_type=code、scope、state、code_challenge、code_challenge_method=S256; - 回调端点校验
state与存储值一致后,用code_verifier到https://api.twitter.com/2/oauth2/token换 token(main.py); - 换到 token 后调用
/users/me获取 username 与用户 ID,一并存入存储(main.py)。
2. Token 自动刷新机制
Twitter access token 约 2 小时过期(expires_in默认按 7200 秒处理)。插件在每次请求前通过 get_valid_access_token 检查过期时间:若expires_at距当前不足5 分钟,则调用 refresh_access_token 用 refresh token 换取新 token,并回写存储。这一机制让用户授权一次即可长期使用,无需反复重新授权。
3. 统一 API 请求封装
twitter_api_request 是所有 Twitter API 调用的统一入口:注入Authorization: Bearer <token>请求头,按 GET / POST / DELETE 分发请求;204 No Content视为成功(点赞取消、删除等操作),其他非 2xx 状态码会把响应文本原样返回,供上层生成错误信息。
4. 推文展示格式化
format_tweet 把 Twitter 返回的推文对象格式化为对话友好文本:作者(@username (显示名))、正文、时间戳(%b %d, %Y %I:%M %p格式)、互动数据(Likes / Retweets / Replies)与推文 ID。时间线、提及、搜索结果均复用该函数。
5. 双模式存储:Redis 与文件回退
db.py 提供 Redis 优先、JSON 文件回退的双模式存储:
- Redis 模式:从
REDIS_URL(兼容REDIS_PRIVATE_URL/REDIS_PUBLIC_URL)建立连接,token 以twitter:tokens:{uid}为 key 存储,TTL 90 天;OAuth state 以twitter:oauth_state:{uid}存储,TTL 10 分钟;用户设置以twitter:settings:{uid}存储(db.py); - 文件模式:本地未配置 Redis 时,自动回退到
data/tokens.json、data/oauth_states.json、data/user_settings.json三个 JSON 文件(db.py)。这解释了 README 中REDIS_URL标注"可选(未设置时使用文件存储)"的原因——本地开发无需 Redis 即可运行。
6. 响应模型
所有 Chat Tool 端点统一返回 ChatToolResponse 模型:成功时填充result(Markdown 文本),失败时填充error(人类可读的错误说明),Omi 对话层据此呈现结果或提示。
环境变量总览
| 变量 | 说明 | 必填 |
|---|---|---|
TWITTER_CLIENT_ID | Twitter OAuth2 Client ID | 是 |
TWITTER_CLIENT_SECRET | Twitter OAuth2 Client Secret | 是 |
TWITTER_REDIRECT_URI | OAuth 回调 URL | 是 |
PORT | 服务端口(默认 8080) | 否 |
REDIS_URL | Redis 连接 URL(未设置时回退文件存储) | 否 |
补充说明:TWITTER_REDIRECT_URI在源码中的默认值是http://localhost:8080/auth/twitter/callback(main.py),因此未配置时本地开发开箱即用;HOST环境变量可控制监听地址(默认0.0.0.0)。此外,Twitter 端配置的回调地址必须与此变量一致。
本地开发
- 复制环境变量模板为
.env并填入凭据(模板见.env.example,其中包含TWITTER_CLIENT_ID、TWITTER_CLIENT_SECRET等键); - 设置
TWITTER_REDIRECT_URI=http://localhost:8080/auth/twitter/callback; - 将该回调地址加入 Twitter App 的 Callback URIs 列表;
- 安装依赖:
pip install -r requirements.txt(依赖版本见 requirements.txt,含 fastapi、uvicorn、python-dotenv、requests、pydantic、redis); - 启动服务:
python main.py(内部以uvicorn main:app --host 0.0.0.0 --port 8080 --reload运行)。
本地环境未配置 Redis 时会自动使用文件存储,适合快速联调 OAuth 流程与 Chat Tools 端点。
对话使用示例
以下自然语言指令可直接在 Omi 对话中触发对应工具:
- "Tweet: Just discovered this amazing AI assistant!" →
post_tweet - "Show my Twitter timeline" →
get_timeline - "Search Twitter for AI news" →
search_tweets - "Like the last tweet" →
like_tweet - "Who mentioned me on Twitter?" →
get_mentions - "Show @elonmusk's profile" →
get_user_profile - "Delete my last tweet" →
delete_tweet
这些示例与插件首页(/带uid时)渲染的示例命令一致(main.py),可作为设置页面向用户展示的引导文案。
限流与错误处理
Twitter API 存在严格的速率限制,官方 README 给出的参考值如下:
- 每 24 小时发推数:随账号类型变化
- 读操作:每 15 分钟 300–900 次请求
- 搜索:每 15 分钟 180 次请求
插件对限流与错误做了如下处理(可从源码确认):
- twitter_api_request 对非 2xx 响应返回
{"error": <响应体>, "status_code": <状态码>},由各工具端点包装为ChatToolResponse(error=...)返回给用户; - token 过期或缺失时给出明确的引导性错误(如"请先在应用设置中连接 Twitter 账号");
- 发推长度超限在服务端即被拦截(main.py),返回 280 字符上限提示,避免白白消耗 API 配额。
故障排查速查
| 现象 | 排查方向 |
|---|---|
| 授权页报 500 / "credentials not configured" | TWITTER_CLIENT_ID未设置,检查环境变量(main.py) |
| 回调报 "State mismatch" | OAuth state 过期(10 分钟 TTL)或 uid 不一致,重新发起授权 |
| 回调报 "Token exchange failed" | 回调地址与 Twitter App 配置不一致,或 Client Secret 错误 |
| 工具调用报 "Please connect your Twitter account first" | 用户未完成授权,或 token 已删除 |
| 工具调用偶发失败后自动恢复 | 大概率是 token 刷新或限流触顶,查看服务日志中的Twitter API error/Token expired ... refreshing输出 |
本文所涉及的全部源码均位于 plugins/omi-twitter-chat-tools-app/ 目录,读者可按需深入阅读 main.py、db.py、models.py、railway.toml 与 Procfile,将该插件的部署与开发模式复用到其他社交平台集成场景。
【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/Friend
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考