基于Claude与Edge TTS构建私有AI播客摘要系统
1. 项目概述打造你的私人AI播客摘要系统每天早上当我的手机闹钟响起我做的第一件事不是关掉闹钟而是戴上耳机点开播客应用。一个温和的AI声音开始为我播报过去24小时我收藏的几篇长文的核心摘要。这听起来像是某个付费订阅服务对吧但实际上这是我用Morsel为自己搭建的一个完全私有的、自动化运行的“文章转播客”系统。整个项目的核心逻辑非常简单你只需要像平时收藏文章一样把链接转发到一个指定的邮箱第二天早上系统就会自动将这些文章汇总、提炼并生成一个可以订阅的播客节目。这个项目的价值在于它完美解决了信息过载时代的一个核心痛点收藏了太多“稍后读”的文章却永远没时间去看。Morsel通过Claude AI将文章浓缩成精华再用Edge TTS转换成语音最终通过一个标准的RSS订阅源推送到你常用的任何播客App里。你可以在通勤路上、健身时、做家务时“听”完那些原本需要静坐阅读的长文。更重要的是整个系统是自托管的你的阅读数据、摘要内容完全掌握在自己手里运行成本极低——根据我的实测每天处理3-4篇中等长度的文章Claude API的费用大约在3-5美分。2. 核心架构与工具选型解析2.1 为什么选择“邮箱转发”作为输入接口在构思一个自动化内容收集系统时输入方式的选择至关重要。Morsel选择了邮箱转发这背后有几个非常务实的考量。首先跨平台与零学习成本几乎任何设备、任何应用都能发送邮件。无论是在手机浏览器、电脑上的阅读插件还是其他App里看到的好文章分享到邮箱是所有平台都支持的最通用操作用户无需安装任何新软件或学习新流程。其次异步与队列管理邮件本身就是一个天然的异步任务队列。你可以随时转发链接系统按固定周期如每天凌晨批量处理这比实时API调用更简单、更稳定也更容易处理失败重试。最后权限与过滤通过配置allowed_senders白名单你可以严格控制哪些邮箱地址有权向你的播客队列投稿有效防止垃圾信息。这里我补充一个关键细节项目推荐使用AgentMail服务作为邮件接收端而不是直接架设一个邮件服务器。对于个人开发者和小型项目来说自己维护一个能稳定接收、解析邮件的服务包括处理SPF、DKIM、垃圾邮件过滤等是件非常头疼的事。AgentMail提供了一个免费的Webhook转发服务每月3000封免费额度它替你搞定所有邮件协议的脏活累活直接将邮件正文以结构化的JSON格式通过API推送给你的应用极大地简化了开发复杂度。这是项目设计中一个非常聪明的“外包”决策。2.2 技术栈深度剖析每一环的选型理由Morsel的技术栈看起来简单但每个组件的选择都经过了权衡目标是在效果、成本、易用性和可控性之间取得最佳平衡。摘要生成引擎Claude API为什么是Claude而不是其他大模型核心原因在于摘要任务对“忠实度”和“连贯性”的极高要求。根据我的使用经验Claude系列模型特别是Haiku在长文本理解、要点提炼和生成连贯、口语化摘要方面表现非常稳定且“幻觉”编造原文没有的内容的概率相对较低。这对于播客内容来说是底线——你不能让AI曲解文章原意。此外Anthropic的API定价清晰Haiku模型性价比极高处理一篇3000字文章的成本不到1美分使得日更播客在经济上完全可行。文本转语音引擎Edge TTS这是一个关键的成本与质量平衡点。市面上有大量高质量的TTS服务如OpenAI的TTS、ElevenLabs但它们通常是按字符收费长期使用成本不菲。Edge TTS是微软Edge浏览器朗读功能的开源实现完全免费且提供了多种自然度不错的语音支持中文、英文等多国语言。虽然其音质和自然度与顶级付费服务有差距但对于播客摘要这种以信息传递为核心的应用来说它“足够好”。更重要的是它离线运行没有网络延迟和调用限制稳定性极高。存储与分发S3兼容存储 RSS选择S3兼容对象存储如Cloudflare R2来托管音频文件和RSS源是出于可靠性、可扩展性和成本的考虑。对象存储专为存储和分发大量文件设计价格低廉R2有10GB免费额度并且能轻松处理音频文件这类静态资源。通过设置存储桶为公开访问每个音频文件和RSS源XML文件都会获得一个固定的公开URL。RSSReally Simple Syndication是播客行业的通用标准协议任何一个播客App都支持通过RSS URL进行订阅。这意味着你无需自己开发一个播客App而是直接利用了成熟、通用的生态。注意整个架构是松散耦合的。理论上你可以替换其中任何一个组件。例如如果你对摘要质量有更高要求可以将Claude换成GPT-4如果你追求极致音质可以将Edge TTS换成付费服务。Morsel提供了一个可插拔的框架。3. 从零开始的详细部署与配置指南3.1 基础环境与项目初始化假设你有一台始终在线的Linux服务器VPS、一台树莓派或者是一台长期开机的Mac/PC。以下步骤将引导你完成手动部署这比一键脚本更能让你理解系统脉络。首先获取代码并创建独立的Python环境这是避免依赖冲突的最佳实践。# 克隆项目仓库 git clone https://github.com/rdyson/morsel.git cd morsel # 创建Python虚拟环境强烈推荐避免污染系统Python python3 -m venv venv # 激活虚拟环境 # Linux/macOS: source venv/bin/activate # Windows: # venv\Scripts\activate # 安装项目依赖 pip install -r requirements.txt依赖主要包括requests用于API调用、boto3用于S3操作、edge-tts等。安装过程通常很顺利。接下来复制配置文件模板并进行核心配置cp config.example.json config.json现在打开config.json文件这是整个系统的大脑。一个配置好的示例如下{ agentmail: { api_key: am_sk_xxxxxxxxxxxx, // 你的AgentMail API密钥 inbox_email: your-inboxinbox.agentmail.to // 你的AgentMail收件箱地址 }, anthropic: { api_key: sk-ant-xxxxxxxxxxxx // 你的Anthropic API密钥 }, storage: { provider: r2, bucket_name: my-morsel-podcast, endpoint_url: https://xxxxxxxxx.r2.cloudflarestorage.com, access_key_id: xxxxxxxxxxxxxxxx, secret_access_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, region: auto }, podcast: { title: Leo的每日阅读摘要, description: 由AI为我精选和播报的每日必读文章。, language: zh, // 支持中文 author: Leo, image_url: https://pub-xxxxxx.r2.dev/cover.png, feed_url_base: https://pub-xxxxxx.r2.dev }, tts: { voice: zh-CN-XiaoxiaoNeural // Edge TTS中文语音 }, allowed_senders: [my-personal-emailgmail.com, my-work-emailcompany.com], retention_days: 30 }3.2 关键外部服务配置实战获取AgentMail收件箱访问 AgentMail官网 注册账号。在Dashboard中创建一个新的“Inbox”收件箱。你会获得一个形如xxxinbox.agentmail.to的邮箱地址这就是你未来转发文章的地址。在Inbox设置中找到“API Key”将其填入配置文件的agentmail.api_key字段。同时将邮箱地址填入agentmail.inbox_email。配置Anthropic API前往 Anthropic控制台 注册并创建API Key。建议从claude-3-haiku-20240307这个模型开始它速度最快、成本最低且摘要能力足够强。将生成的API Key填入anthropic.api_key。设置Cloudflare R2存储桶推荐登录Cloudflare Dashboard进入“R2”页面。点击“创建存储桶”输入一个全局唯一的名称如my-morsel-podcast。创建后进入存储桶设置找到“公开访问”选项并启用它。这会生成一个公共访问域名如pub-xxxxxx.r2.dev。接下来需要创建API令牌在R2页面侧边栏找到“API令牌” - “创建令牌”。权限选择“编辑”并指定可访问的存储桶。创建成功后你会得到Access Key ID和Secret Access Key将它们与endpoint_url、bucket_name一起填入配置文件的storage部分。重要步骤你需要手动将项目根目录下的cover.png播客封面图上传到这个存储桶并记下它的完整公开URL如https://pub-xxxxxx.r2.dev/cover.png填入podcast.image_url。封面图建议尺寸不小于1400x1400像素。3.3 自动化任务与订阅设置系统通过Linux的cron定时任务来驱动。我们需要创建一个执行脚本run_daily.sh#!/bin/bash cd /path/to/your/morsel source venv/bin/activate python poll_inbox.py python generate_digest.py记得给脚本加上执行权限chmod x run_daily.sh。然后编辑当前用户的crontabcrontab -e在打开的编辑器中添加一行例如设定每天凌晨4点运行0 4 * * * /path/to/your/morsel/run_daily.sh /path/to/your/morsel/data/cron.log 21这行配置的意思是每天4:00 AM切换到Morsel目录激活虚拟环境依次执行poll_inbox.py拉取新邮件并缓存文章和generate_digest.py生成摘要和音频并更新RSS。所有输出日志会被追加到data/cron.log文件中方便排查问题。最后获取你的播客订阅链接。它的格式是你的存储桶公开URL/feed.xml。例如https://pub-xxxxxx.r2.dev/feed.xml。将这个URL添加到你手机或电脑上的任何播客应用如Apple Podcasts, Pocket Casts, Castro等中就像订阅普通播客一样。至此你的私人AI播客系统就搭建完成了。现在尝试向你的AgentMail收件箱地址转发一篇任意文章链接等待下一个凌晨4点检查你的播客App是否出现了新节目。4. 核心工作流程与源码逻辑剖析4.1 邮件抓取与文章内容提取当poll_inbox.py脚本运行时它首先会调用AgentMail的API检查指定收件箱是否有新邮件。AgentMail的API设计得很简洁返回的JSON数据中包含了邮件正文。脚本的核心任务是从邮件正文中提取出纯文本的URL链接。这里有一个实操心得网络上的文章链接分享形式五花八门。用户可能转发的是邮件简报里面一堆链接也可能在链接前后加了个人评论。Morsel的提取逻辑相对直接主要使用正则表达式匹配http://或https://开头的字符串。但这并不完美。我建议在配置文件的allowed_senders里只添加你信任的、自己常用的邮箱这样可以避免解析过于混乱的邮件内容。提取到URL后脚本会将其存入一个本地队列文件如data/queue.json中等待摘要任务处理。接下来是关键一步获取文章正文。项目使用了免费的 Jina Reader API。这是一个专门用于提取网页主体内容的服务它能智能地去除导航栏、侧边栏、广告等噪音只返回文章的核心文本。调用方式非常简单只需向https://r.jina.ai/{url}发起GET请求即可。例如https://r.jina.ai/https://example.com/article。这一步的质量直接决定了后续摘要的准确性Jina Reader在此类任务上的表现远好于自己写正则表达式去解析HTML。4.2 AI摘要生成与播客脚本编排generate_digest.py脚本是系统的核心。它会读取data/queue.json中所有待处理的文章URL依次通过Jina Reader获取纯净文本然后打包发送给Claude API。摘要提示词工程是影响最终播客质量的重中之重。Morsel内置的提示词Prompt大致是这样的你是一个专业的播客主持人。以下是用户今天收藏的几篇文章的完整内容。 请为每一篇文章撰写一个简洁、口语化的摘要时长控制在1-2分钟。 摘要需突出文章的核心论点、关键证据和主要结论。 然后将这些摘要串联起来形成一个连贯的播客节目开场白例如“欢迎收听今日阅读摘要今天我们有X篇文章...”。 请使用适合收听的口语化语言避免复杂的专业术语。 文章内容如下[此处插入所有文章文本]这个提示词有几个设计亮点1)设定角色播客主持人让AI的语态更合适2)明确格式和时长控制输出结构3)强调口语化这是文本转语音的前提4)要求串联使最终输出是一个完整的节目脚本而不是孤立的段落。Claude API返回一个完整的播客脚本后脚本会为其生成一个基于日期的唯一文件名如2025-03-28.md并保存到data/transcripts/目录下。同时队列文件会被清空为第二天的文章做准备。4.3 文本转语音与播客RSS源生成拿到播客脚本文本后generate_digest.py会调用edge-tts库将其转换为音频文件。import edge_tts tts edge_tts.Communicate(textpodcast_script, voiceconfig[tts][voice]) await tts.save(fdata/audio/{date}.mp3)config[tts][voice]决定了语音的音色。Edge TTS支持多种语言和音色例如zh-CN-XiaoxiaoNeural晓晓年轻女声、en-US-GuyNeural男声等。你可以根据喜好配置。转换完成后脚本会使用boto3库将MP3文件上传到预先配置好的S3存储桶中。最精妙的一环是RSS feed的生成与更新。播客本质上就是一个带有音频附件链接的RSS 2.0格式的XML文件。generate_digest.py会维护一个feed.xml文件它位于存储桶的根目录。每次生成新节目后脚本会读取现有的feed.xml如果存在。在channel节点下插入一个新的item条目。这个条目包含新节目的标题如“每日摘要 - 2025-03-28”、描述通常是脚本的前几句话、发布时间、唯一的GUID标识符以及最重要的——音频文件的公开URLenclosure标签。根据config.json中设置的retention_days默认30天清理掉超过保留期限的旧节目条目避免feed无限膨胀。将更新后的XML内容重新上传到存储桶覆盖旧的feed.xml。当你的播客App定期抓取这个feed.xml时就能自动发现并下载最新的节目。整个流程完全遵循开放标准没有任何私有协议这是项目能无缝接入现有生态的根本原因。5. 高级用法与OpenClaw集成实现跨平台快捷收藏Morsel的基础用法是邮件转发但如果你像我一样大量阅读场景发生在手机上的Telegram、微信、浏览器共享菜单里频繁切换去发邮件还是很麻烦。这时与 OpenClaw 的集成功能就派上大用场了。OpenClaw是一个开源的AI助手框架它可以通过各种技能Skills连接不同的服务。Morsel项目提供了一个OpenClaw技能使得你可以在任何已连接OpenClaw的聊天界面如Telegram、Discord、甚至短信中直接粘贴一个链接它就会自动被送入Morsel的待处理队列。5.1 OpenClaw与Morsel技能集成步骤首先确保你已经在服务器或本地机器上安装并运行了OpenClaw。然后按照以下步骤集成Morsel技能# 1. 进入你的OpenClaw工作空间目录 cd ~/.openclaw/workspace # 2. 从Morsel项目复制技能文件 cp -r /path/to/morsel/skills/morsel ./skills/ # 3. 编辑OpenClaw主配置文件 nano ~/.openclaw/openclaw.json在openclaw.json文件的skills.entries部分添加Morsel技能的配置{ skills: { entries: { morsel: { enabled: true, env: { MORSEL_FROM: your-openclaw-inboxagentmail.to, MORSEL_INBOX: your-morsel-main-inboxagentmail.to } } } } }这里需要理解两个邮箱地址的作用MORSEL_INBOX这是你的主Morsel收件箱地址即config.json里配置的那个。所有文章最终都会发往这里。MORSEL_FROM这是你需要额外创建的一个AgentMail收件箱专门给OpenClaw使用。OpenClaw技能会模拟从这个邮箱发送邮件到主收件箱。关键配置你必须在Morsel的config.json文件的allowed_senders列表中加入这个MORSEL_FROM邮箱地址。否则Morsel会拒收来自OpenClaw的链接。配置完成后重启OpenClaw服务。现在当你在与OpenClaw绑定的Telegram聊天中发送一个链接时OpenClaw的Morsel技能会被触发。它背后的工作原理是技能代码会调用AgentMail的“发送邮件”API以MORSEL_FROM邮箱的身份向MORSEL_INBOX邮箱发送一封正文只有该链接的邮件。这封邮件会被AgentMail接收并像普通转发邮件一样通过Webhook推送给你的Morsel服务。这样一来收藏文章的操作就简化成了“在任何聊天App里复制粘贴”。5.2 自定义技能与扩展思路Morsel提供的OpenClaw技能是一个很好的起点但你可以根据自己的工作流进行扩展。例如添加标签或分类修改技能代码在发送链接的同时可以在邮件主题或正文特定格式中加入标签如[tech] https://example.com。然后在Morsel的摘要生成环节解析这个标签让AI在播报时说“今天的第一篇科技类文章是...”。优先级队列可以定义不同的关键词来实现优先级。比如发送链接时加上urgent让这篇文章在下次生成摘要时被优先处理甚至触发一次即时生成而非等到第二天。多播客源你可以部署多套Morsel配置不同的config.json例如一个用于科技新闻一个用于个人博客。然后创建多个OpenClaw技能分别指向不同的收件箱。通过发送不同的命令如/save_tech [链接]和/save_blog [链接]来将文章分类收藏。这种集成模式展示了自托管工具的灵活性——你可以像搭积木一样将不同的自动化工具组合起来创造出完全贴合个人习惯的工作流。6. 日常运维、问题排查与优化经验6.1 日志监控与健康检查系统通过cron在后台静默运行因此建立简单的监控机制很重要。项目脚本的输出会重定向到data/cron.log文件。你应该定期检查这个日志看看有无错误信息。一个健康的日志在每天运行后应该类似这样[INFO] 开始检查收件箱... [INFO] 发现2封新邮件成功提取3个链接。 [INFO] 开始为3篇文章生成摘要... [INFO] 成功调用Claude API生成播客脚本。 [INFO] 文本转语音完成音频文件已保存。 [INFO] 成功上传音频文件至S3。 [INFO] RSS feed已更新。 [INFO] 清理了30天前的旧节目数据。如果看到[ERROR]字样就需要介入排查。更自动化的方法是在服务器上配置一个简单的邮件或Telegram通知当cron任务退出码非零时表示执行失败发送警报。可以在run_daily.sh脚本末尾添加if [ $? -ne 0 ]; then # 调用一个发送警报的脚本例如使用curl调用Telegram Bot API curl -s -X POST https://api.telegram.org/botYOUR_BOT_TOKEN/sendMessage -d chat_idYOUR_CHAT_IDtextMorsel每日任务执行失败请检查日志 fi6.2 常见问题与解决方案速查表以下是我在长期运行中遇到的一些典型问题及解决方法问题现象可能原因排查步骤与解决方案收不到新节目1. Cron任务未执行2. AgentMail配置错误3. S3上传失败1. 检查cron.log是否有最新记录。执行crontab -l确认任务存在。检查脚本路径和权限。2. 在config.json中核对agentmail的API Key和邮箱地址。去AgentMail Dashboard查看收件箱是否有邮件到达。3. 检查storage配置尤其是endpoint_url和密钥。手动运行python generate_digest.py看是否有权限错误。播客App显示“无法更新”RSS feed.xml格式错误或无法访问1. 直接浏览器访问你的feed.xmlURL看是否能正常显示XML内容。2. 检查XML格式是否良好标签是否闭合。可能是脚本更新feed时出错手动检查data/feed.xml文件内容。3. 确认S3存储桶的feed.xml文件具有公开读取权限。摘要内容质量差1. 文章正文提取失败2. Claude提示词或模型不合适1. 检查data/transcripts/下的脚本文件看原始文章文本是否完整。可能是Jina Reader对某些网站支持不好可以尝试手动访问https://r.jina.ai/目标URL测试。2. 可以尝试修改generate_digest.py中的提示词让它更符合你的需求如更简短、更深入等。或者尝试更换Claude模型如claude-3-sonnet。音频生成失败或无声1. Edge TTS语音配置错误2. 文本包含TTS不支持的字符1. 检查config.json中tts.voice的值是否有效。可运行edge-tts --list-voices查看所有可用语音。2. 播客脚本中可能包含特殊字符或emojiEdge TTS无法处理。可以在生成脚本后添加一个文本清洗步骤过滤掉非常规字符。存储空间增长过快音频文件积累1. 确认config.json中的retention_days已设置如30。脚本会自动清理旧音频文件和feed条目。2. 可以定期登录S3控制台确认旧文件是否已被删除。6.3 性能优化与成本控制技巧成本控制最大的可变成本是Claude API调用。如果你每天转发很多长文费用会增加。优化策略可以在poll_inbox.py中增加一个过滤逻辑比如只处理来自特定发件人或包含特定关键词的邮件。或者在generate_digest.py中限制每天最多处理N篇文章例如5篇多余的留到第二天。处理失败重试网络请求Jina Reader, Claude API可能偶尔失败。目前的脚本缺乏重试机制。改进方案可以在调用API的代码块外包裹一个重试循环例如使用tenacity库并记录失败的文章URL下次运行时优先重试。音频生成加速Edge TTS生成较长音频超过10分钟可能较慢。折中方案修改提示词要求Claude生成更精炼的摘要将单期节目时长控制在5-8分钟内。或者可以考虑将generate_digest.py中的TTS部分改为异步执行不阻塞主流程。Feed访问加速如果你的听众不止你一人或者你通过公开链接分享播客可以考虑为S3存储桶配置CDN如Cloudflare的CDN这样全球听众都能快速下载音频。运行这样一个系统近半年最大的体会是“自动化带来的宁静”。我不再为“收藏了却没读”而感到焦虑因为我知道这些信息会在第二天早上以最便捷的方式送达我的耳朵。它从一个有趣的技术项目变成了我信息消化流程中一个无声却可靠的基础设施。如果你也苦于信息囤积不妨花上一个下午亲手搭建这个属于你自己的“耳朵图书馆”。