拓冰建站拓冰建站
首页 / 资讯中心 / 正文

OMI 语音 Slack 消息发送实战:omi-slack-app 插件的触发短语、分段收集、OAuth 集成与 Railway 部署全解析

OMI 语音 Slack 消息发送实战omi-slack-app 插件的触发短语、分段收集、OAuth 集成与 Railway 部署全解析【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/Friend这篇技术指南围绕开源仓库 FriendOMI中的 plugins/omi-slack-app 插件展开它实现了「对着 OMI 设备说话自动把消息发到指定 Slack 频道」的完整闭环语音触发短语识别、分段收集与超时处理、AI 频道匹配与消息清洗、Slack OAuth 2.0 授权以及 Railway 云部署。读完本文你将掌握该插件的全部配置参数、API 端点、源码级工作机制并能够独立完成本地开发、端到端测试与生产部署。一、插件定位与核心特性omi-slack-app 是一个面向 OMIFriend 项目中的可穿戴 AI 设备的语音 Slack 消息发送插件。用户只需说出Send message to [channel]并跟上消息内容AI 便会自动将消息投递到正确的工作区频道。原文档列出的核心特性如下其中每一项都在源码中有对应实现语音激活说出触发短语后自然讲话即可无需任何手动操作AI 频道匹配AI 将口述的频道名与工作区真实频道做模糊匹配容忍不完美发音与转写误差OAuth 认证基于 Slack OAuth 2.0 的授权码流程安全接入工作区频道选择可在语音命令中指定频道也可在首页设置默认频道作为兜底灵活设置随时通过移动端优先的首页更换默认频道智能消息提取AI 自动清理「um、uh、like」等填充词修正语法并规范化格式静默收集收集语音分段期间不打扰用户只在消息真正发送成功后推送一次通知移动端优先 UI内嵌 Slack 风格深色主题的响应式页面源码见 main.py 中get_mobile_css()采用 Slack 官方配色 #007a5a、#1d9bd1、#e01e5a。二、快速开始OMI 端三步启用对普通 OMI 用户而言启用流程非常简单在 OMI 手机 App 中安装本插件一次性完成 Slack 工作区认证OAuth可选设置默认频道也可以在语音里指定开始用语音发消息。触发短语仅有 3 个为保证激活精准、避免误触发插件只支持以下三个触发短语定义于 message_detector.py 的TRIGGER_PHRASES常量触发短语使用示例Send Slack messageSend Slack message to general saying...Post Slack messagePost Slack message in marketing that...Post in SlackPost in Slack to random saying...源码层面detect_trigger()会先将文本lower().strip()归一化再对三条短语做子串匹配extract_message_content()则定位命中短语的位置截取其后的文本作为待发送内容——这也是为什么 README 明确「ONLY these 3」的原因多短语会显著提高误触发概率。工作原理一次完整的语音发消息流程检测到触发短语 → 进入收集recording状态最多收集 5 个语音分段或检测到 5 秒以上的停顿立即结束AI 提取两项关键信息频道名与工作区频道列表模糊匹配消息内容清洗并格式化自动拉取最新频道列表新频道立即可用无需手动刷新将消息投递到 Slack发送成功后推送确认通知。原文档给出的端到端示例You: Send Slack message to general saying hello team [collecting segment 1/5...] You: hope everyone is having a great day [collecting segment 2/5...] [5 second pause - timeout!] → AI processes 2 segments AI Extracted: Channel: #general Message: Hello team, hope everyone is having a great day. → Message sent! 三、OMI App 配置参数在 OMI 开发者设置中需要把插件部署地址填入以下四个字段下表为生产环境模板your-app替换为实际部署域名字段值Webhook URLhttps://your-app.up.railway.app/webhookApp Home URLhttps://your-app.up.railway.app/Auth URLhttps://your-app.up.railway.app/authSetup Completed URLhttps://your-app.up.railway.app/setup-completed这四个端点分别对应 main.py 中的/webhook实时转写回调、/首页/设置页、/authOAuth 起始、/setup-completed认证状态检查。OMI 设备会将实时语音转写分段 POST 到/webhook这是整个插件的入口。四、开发环境搭建前置条件Python 3.10runtime.txt指定 3.10.17见 runtime.txt具备管理员权限的 Slack 工作区OpenAI API Key用于频道匹配与消息提取OMI 设备及 App用于端到端验证。安装步骤# 克隆仓库并进入插件目录 git clone https://gitcode.com/GitHub_Trending/fr/Friend cd Friend/plugins/omi-slack-app # 创建虚拟环境 python3 -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate # 安装依赖 pip install -r requirements.txt # 配置环境 cp .env.example .env # Edit .env with your API keys依赖清单requirements.txt锁定版本如下其中fastapi提供 Web 框架、uvicorn作为 ASGI 服务器、openai驱动 AI 处理、slack-sdk封装 Slack APIfastapi0.104.1 uvicorn0.24.0 python-dotenv1.2.2 pydantic2.5.0 httpx0.25.2 openai1.3.7 requests2.34.2 slack-sdk3.27.1环境变量配置创建.env文件# Slack OAuth Credentials (from api.slack.com/apps) SLACK_CLIENT_IDyour_client_id SLACK_CLIENT_SECRETyour_client_secret # OAuth Redirect URL OAUTH_REDIRECT_URLhttp://localhost:8000/auth/callback # OpenAI API Key (for AI channel matching message extraction) OPENAI_API_KEYyour_openai_key # App Settings APP_HOST0.0.0.0 APP_PORT8000各变量作用结合 slack_client.py 与 main.py 源码SLACK_CLIENT_ID/SLACK_CLIENT_SECRETSlack App 的 OAuth 凭证用于生成授权 URL 与换取 access tokenOAUTH_REDIRECT_URLOAuth 回调地址必须与 Slack App 中配置的 Redirect URL 完全一致否则授权会失败OPENAI_API_KEY异步 OpenAI 客户端AsyncOpenAI的密钥见 message_detector.py 第 8 行APP_HOST/APP_PORTuvicorn 监听地址与端口默认0.0.0.0:8000见 main.py 末尾__main__段。五、Slack App 创建与 OAuth 配置创建 Slack App 并配置权限登录 Slack API 的 Apps 管理页面api.slack.com/apps点击 Create New App → From scratch填写应用名称并选择目标工作区进入 OAuth Permissions 页面添加以下 scopes用户令牌作用域channels:read— 查看公开频道chat:write— 发送消息groups:read— 查看私有频道users:read— 查看用户信息设置 Redirect URLhttp://localhost:8000/auth/callback本地测试将 Client ID 和 Client Secret 复制到.env。源码解析为什么消息以「用户」身份发出很多类似插件发消息显示为机器人bot而本插件特意让消息以用户本人身份发出。关键在 slack_client.pyget_authorization_url()生成授权链接时使用的是user_scope而非scope并在注释中明确 Uses USER token scopes so messages appear as sent by the user, not a bot。实际申请的作用域比 README 基础四件套多了channels:history读取频道历史与search:read搜索消息支撑插件的搜索能力user_scopes channels:read,channels:history,chat:write,groups:read,users:read,search:readexchange_code_for_token()换取令牌时优先取authed_user.access_token即 xoxp- 开头的用户令牌若拿不到则回退到 bot token并打印显式告警 Using BOT token (messages will post as BOT, not as USER)send_message()中通过前缀判断令牌类型xoxp-为用户令牌、xoxb-为机器人令牌发完还会检查返回的bot_id字段确认消息归属。关于此处的常见坑仓库内 TOKEN_DEBUG.md 记录了完整排障过程若 Slack App 同时配置了 Bot Token Scopes尤其包含chat:write即使请求用户作用域也可能默认下发 bot token解决方式是清空 Bot Token Scopes、在 App Manifest 中只保留oauth_config.scopes.user并让已认证用户执行「Logout Clear Data → 重新认证」。六、本地运行与测试source venv/bin/activate python main.py启动后访问http://localhost:8000/test?devtrue打开开发测试界面。该页面源码位于 main.py 的/test端点未带devtrue参数时返回 404提供认证区输入任意 UID → 打开 Slack 认证 → 检查认证状态 → 登出语音命令测试区把想对 OMI 说的话直接输入文本框模拟 OMI 实时转写分段 POST 到/webhook内置示例点击即可填充三条经典指令实时活动日志展示请求处理全过程的运行日志。测试模式的特殊性值得注意会话 ID 以test_session前缀开头见 main.py 的process_segments()一旦检测到触发短语且内容超过 10 个字符会跳过分段收集、立即整段处理方便快速验证 AI 提取与 Slack 投递链路。七、Railway 云端部署部署步骤推送到代码仓库将本插件目录或整个仓库提交并推送到你自己的 Git 远程仓库git init git add . git commit -m Initial commit git branch -M main git push -u origin mainRailway 建项目登录 Railway 控制台New Project → Deploy from GitHub选择包含本插件的仓库添加环境变量来自.env见下方清单获取公网域名Settings → Networking → Generate Domain得到形如your-app.up.railway.app的地址更新 OAuth 回调Railway 变量中设置OAUTH_REDIRECT_URLhttps://your-app.up.railway.app/auth/callback同时在 Slack App 的 OAuth Permissions 页面把 Redirect URL 改为同一地址配置 OMI将四个 URL见第三节填入 OMI App 设置。Railway 环境变量清单在 Railway 控制台添加以下变量SLACK_CLIENT_ID SLACK_CLIENT_SECRET OPENAI_API_KEY OAUTH_REDIRECT_URLhttps://your-app.up.railway.app/auth/callback APP_HOST0.0.0.0 APP_PORT8000 PYTHONUNBUFFERED1注意PYTHONUNBUFFERED1确保日志即时输出无缓冲延迟对排查线上问题至关重要。部署配置源码解读railway.toml 是 Railway 的部署描述文件[deploy] startCommand uvicorn main:app --host 0.0.0.0 --port $PORT # Persistent storage for user tokens and sessions [[deploy.volumes]] mountPath /app/datastartCommand使用$PORT环境变量Railway 动态分配端口不能写死 8000挂载持久卷/app/data这与 simple_storage.py 的存储策略呼应代码检测到/app/data目录存在时会把用户令牌与会话数据 JSON 文件users_data.json、sessions_data.json写入该目录保证服务重启后 OAuth 令牌不丢失本地开发时则回退到插件目录本身。八、核心机制深度解析分段收集与超时处理这是本插件区别于普通「一条指令一次动作」插件的关键设计——它处理的是流式语音转写。OMI 设备在用户说话过程中会不断把新的转写分段推送到/webhook因此服务端需要一个会话状态机来聚合这些分段。会话状态机simple_storage.py 定义了每个会话SimpleSessionStorage的三个状态idle空闲监听等待触发短语recording已命中触发短语正在聚合语音分段processingAI 正在提取频道与消息、投递 Slack此期间新到达的分段被忽略防止重复发送。会话还记录segments_count、accumulated_text、last_segment_at最后活动时间戳等字段。分段聚合逻辑main.py 的process_segments()是核心函数命中触发且处于 idle截取触发短语后的内容存入accumulated_text置segments_count1状态切到recording处于 recording追加新分段文本segments_count加一当计数达到 5 时立即处理置为 processing拉取最新频道列表调用 AI 提取发送消息未达 5 段等待后续分段或等待后台超时监控触发。5 秒超时后台任务monitor_session_timeouts()是应用启动时创建的后台 asyncio 任务见 main.py 的startup_event每秒扫描所有 recording 会话通过SimpleSessionStorage.get_session_idle_time()计算距最后分段的时间若空闲超过 5 秒无论已有几段都立即处理idle_time 5处理完成后调用reset_session()将会话复位到 idle。收集参数速查参数值说明最大分段数5含触发段达到即强制处理防止无限收集超时时间5 秒静默停顿超过 5 秒立即处理已有内容最少分段2触发 内容但超时路径对 1 段也处理典型时长约 5–20 秒取决于说话长度与停顿频道自动刷新每次发送前新频道立即可用README 中的“收集过程中静默无打扰、完成后只发一条通知”也由源码保证/webhook仅在返回内容包含✅ Message sent或❌时才向 OMI 回传用户可见通知其余阶段一律返回{status: ok}。九、AI 处理频道匹配与消息提取AI 层位于 message_detector.py基于 OpenAI GPT-4omodelgpt-4o通过AsyncOpenAI异步调用。原文档的 AI 处理三步流程与源码一一对应频道匹配将口述频道名模糊匹配到工作区真实频道消息提取从语音分段中提取干净的消息正文清理删除填充词、修正语法、规范格式。Prompt 设计结构化输出系统提示词把工作区全部频道名拼接进上下文并要求按固定两行格式输出CHANNEL: channel_name or UNKNOWN MESSAGE: cleaned message content同时给出 4 组示例如 to general saying hello team how are you doing today →CHANNEL: general并明确规则频道名可能不完整如 gen 对应 general、可能带或不带 #、需要匹配最接近的频道无明确频道时输出UNKNOWN。调用参数temperature0.3, max_tokens200兼顾确定性输出与足够的消息长度。解析与两级匹配响应按行解析出channel_name与message后进行两级匹配精确匹配与频道映射表做大小写不敏感比对模糊匹配若精确失败尝试「口述名包含真实名」或「真实名包含口述名」的互含判断源码注释示例random stuff → #random。两级都未命中时返回(None, channel_name, message)由调用方/webhook处理链回退到用户设置的默认频道若默认频道也未设置则返回❌ No channel specified and no default channel set。此外还有独立的ai_match_channel()方法temperature0.1, max_tokens20专门做单频道名匹配异常时自动降级为简单字符串比对。消息清洗示例Input (3 segments): to general saying um hello team hope youre all um doing great today AI Output: Channel: #general (matched from general) Message: Hello team, hope youre all doing great today作为 AI 调用失败时的兜底clean_content()实现了基于正则与词表的本地清洗合并多余空格、剔除um/uh/like/you know/so/yeah等填充词、首字母大写。十、频道管理在语音中指定频道任何时候都可以在语音命令中显式指定频道AI 会做模糊匹配Send message togeneralsaying helloPost inmarketingthat campaign is liveMessage toengineeringabout the bug fix使用默认频道在首页设置默认频道后可以省略频道名Send message saying quick update for everyone消息将投递到默认频道频道列表自动刷新插件在每次发送前都会调用slack_client.list_channels()拉取最新频道列表源码见process_segments()与超时监控中的channels slack_client.list_channels(...)因此新建的频道无需手动刷新即可使用。list_channels()底层调用 Slackconversations.list参数typespublic_channel,private_channel、exclude_archivedTrue、limit200并做了完整的分页游标处理与重复游标防死循环保护。同时支持手动刷新首页点击 Refresh Channels 按钮对应/refresh-channels端点或重新认证。切换工作区点击 Switch Workspace 可连接不同的 Slack 工作区重新认证新团队、在多个工作区之间轻松切换每个工作区的 OAuth 令牌按 UID 隔离存储。十一、API 端点总览Web 端点原文档表格完整保留EndpointMethodDescription/GETHomepage with channel selection (mobile-first)/authGETStart Slack OAuth flow/auth/callbackGETOAuth callback handler/setup-completedGETCheck if user authenticated/webhookPOSTReal-time transcript processor/update-channelPOSTUpdate selected default channel/refresh-channelsPOSTRefresh channel list/testGETWeb testing interface/healthGETHealth check除上述外源码还实现了/logoutPOST清除用户数据与会话以及以下 OMI App Store 使用的Chat Tools 端点EndpointMethod功能/api/send_messagePOST以指定channelmessage直接发送参数缺失返回 400未认证返回 401/api/search_messagesPOST按query搜索消息可带可选channel限定范围/api/search_channelsPOST按query检索频道空查询返回全部频道以/api/send_message为例期望的载荷格式为{ uid: user_id, app_id: slack_app_id, tool_name: send_slack_message, channel: #general, message: Hello from Omi! }服务端会先把频道名含#前缀处理解析为频道 ID再复用与语音链路相同的slack_client.send_message()投递。十二、安全与隐私原文档的安全声明与源码实现对应如下OAuth 2.0 认证不存储任何密码仅保存授权换取的用户令牌令牌安全持久化令牌以 JSON 文件落盘simple_storage.pyRailway 上落于持久卷/app/data按用户隔离令牌、默认频道等均以uid为键存储互不可见生产环境强制 HTTPS部署在 Railway 公网域名上由平台自动启用 TLSCSRF 防护/auth用secrets.token_urlsafe(32)生成随机 state 参数main.py回调时校验 state 与 uid 的映射不匹配即拒绝最小权限原则申请 scopes 均为完成功能所需的最小集合。十三、故障排查User not authenticated完成 Slack OAuth 全流程查看 Railway 日志中的认证错误必要时重新认证。No channel specified and no default channel set访问插件首页设置一个默认频道或在语音命令中显式指定频道。Message not sending检查 Railway 日志定位错误确认频道存在且应用有访问权限确认 Slack App 配置了正确的 scopes留意 Slack API 的限流rate limit。Channel not found检查频道名的发音是否清晰AI 会做模糊匹配但清晰的发音能显著提升命中率使用 Refresh Channels 刷新频道列表在设置中将其设为默认频道。Railway deployment fails确认所有环境变量已正确设置查看构建日志中的具体报错确保OAUTH_REDIRECT_URL与 Slack App 中配置的回调地址完全一致。消息以机器人身份发出而不是用户本人参照 TOKEN_DEBUG.md 的完整排障流程确认日志中输出的是✅ Using USER tokenxoxp-而非 BOT tokenxoxb-若为后者需清空 Slack App 的 Bot Token Scopes或移除 bot scopes 中的chat:write让已认证用户执行「Logout Clear Data」后重新认证。十四、项目结构与源码导览原文档的项目结构路径在本仓库内对应plugins/omi-slack-app/slack/ → plugins/omi-slack-app/ ├── main.py # FastAPI application with mobile-first UI ├── slack_client.py # Slack API integration ├── message_detector.py # AI-powered message channel detection ├── simple_storage.py # File-based storage (users sessions) ├── requirements.txt # Python dependencies ├── railway.toml # Railway deployment config ├── runtime.txt # Python version ├── Procfile # Alternative deployment platforms ├── .env.example # Environment template ├── .gitignore # Git ignore rules ├── LICENSE # MIT License └── README.md # This file仓库内还提供了两篇补充文档SETUP.md从零搭建的完整记录含架构流程图与 OMI_SETUP.mdngrok 本地联调配置说明免费 ngrok 域名重启会变化、生产建议用 Railway。十五、搜索消息时的频道范围控制与离线回归测试README 末尾补充了搜索功能的范围保护语义这也是一个值得注意的工程细节当用户显式指定了频道时频道名必须先解析成功消息搜索才会继续。若频道列表获取失败或该名称无匹配搜索直接返回channel_not_found_or_unavailableChat Tool 对应 HTTP 400绝不退化为全工作区搜索现有频道列表 API 在查询出错时返回空列表因此该错误有意不区分「查询不可用」与「频道不存在」两种情况直接传入频道 ID 仍然可用省略频道参数则允许工作区范围搜索近期消息历史today/recent/latest 等关键词走conversations.history及其搜索回退均保持已解析的频道范围。源码实现见 slack_client.py 的search_messages()显式频道解析失败返回{success: False, error: channel_not_found_or_unavailable}近期查询用conversations_history默认近 1 天、100 条*/all则近 7 天、200 条带日期过滤after:/before:时才走 search API且搜索词会带上in:{channel_id}限定范围。仓库为此提供了密封hermetic回归测试从仓库根目录直接运行python3 plugins/omi-slack-app/test_slack_search.py该测试test_slack_search.py通过importlib加载完整生产模块slack_client.py与main.py仅替换 SDK、存储与框架边界为 Mock无需 Slack 凭据或任何第三方包也不涉及真实 HTTP 传输或线上工作区它验证「显式频道不可达时不降级为全局搜索」这一关键不变量并已登记在仓库的 checks-manifest 中用于本地 preflight 与 CI。许可证本插件以 MIT 许可证发布详见 LICENSE。【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/Friend创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门