我把一套 18 节的文字课做成了能听的有声书,全程只花 ¥40,关键是别买那个订阅

把 18 节文字课做成能读能听的有声书

哈喽,我是飞飞。

先说个事。我手里一直攥着一套自己写的成长课,18 节纯文字,加起来快 4763 行。东西是好东西,但它就那么躺在仓库里,是一堆灰扑扑的 Markdown。说实话,这种长文没人会主动点进去读,我自己写完都懒得再翻第二遍。

后来我想,能不能把它做成一个像样的作品。一个能像电子书那样沉浸读、又能戴上耳机在通勤路上听的东西。于是就有了现在这个站:change-your-life.vance.xin,古籍质感的在线阅读页,配上 18 节 AI 朗读的有声书,沉稳男声,加起来大概 205 分钟。

先给你看一眼它在手机上的样子,深色模式,朱砂红配暖色标题,底部那条是常驻播放台。

有声书阅读站手机版深色模式首页

这套打法我也还在摸,不一定全对,但既然踩过的坑都热乎着,我就把怎么做的、花了多少钱、在哪几个地方翻了车,一次性都掏给你。

一开始我只定了两条死规矩

技术选型这种事,越往后越容易乱。所以动手前我先给自己立了两条规矩,后面所有选择都照着它来。

一个是静态优先。不搞后端、不碰数据库。生成出来的就是一个 HTML 文件,能双击离线打开,也能随手丢到任何托管上。另一个是可增量。这套课我以后还会持续打磨,所以「改了某一节、只重做这一节」的成本必须压到极低,绝不能改一个字就得整本重跑。

有了这两条,后面就好办了。阅读页我没引任何第三方库,课程的 Markdown 语法本来就很克制,我用 Python 标准库自己写了个轻量转换器,几百行搞定,零依赖,跑起来稳,换个人也能直接用。

至于托管,我做了一个现在看来很值的决定:拆开放。阅读页很小,几百 KB,丢 Cloudflare Pages;音频很大,差不多 200MB,放七牛云的对象存储走 CDN。两边各走各的,改文字只更新 HTML,改音频只动七牛,互不拖累。

电脑上打开是下面这样,左边是能跟着滚动高亮的章节目录,右边正文,底部那条常驻播放台随时能播放、暂停、切上下节、调倍速。

有声书阅读站电脑版深色模式正在播放

配音用哪家,我对比了四家最后选了 MiniMax

这是有声书旁白,我要的就一个标准:像真人在念书,不能有那股机器腔。

我把市面上主流的几家中文语音合成都拉出来比了一遍。阿里云的 CosyVoice 很自然,和阿里云账号打通、人民币计费,适合图省事的;火山引擎的豆包音色库最全;Azure 的 SSML 能精细控停顿语速,适合批量长文。最后我选了 MiniMax 的 speech-2.8-hd,它的音色在有声书这个场景里是第一梯队,最接近真人主播那种娓娓道来的感觉。

选哪家其实不太纠结,听几句小样心里就有数了。真正让我差点踩坑的,是它后面那套计费。

别被那个 ¥49 月订阅勾走,一次性任务就该按量付费

MiniMax 有两套完全不同的计费体系,刚上手很容易搞混。

一套是按量付费,用标准的 API Key,按你实际用了多少扣账户余额,语音是按字符算的,hd 是 ¥3.5 一万字符。另一套是 Token Plan 订阅,比如 Plus 是 ¥49 一个月,文本、图像、语音、音乐共享一份 token 额度,用的是另一把订阅密钥。

我一开始是被那个 ¥49 勾住的,第一反应是「看起来啥都包了,更划算」。但冷静想了想就放弃了。它那把订阅密钥是不是能直接喂给语音 API,我心里没底,那种额度常常只在它自家的 Agent 产品里能用。再说它主打的卖点,什么多 Agent 并发、编程工具、百万上下文,全是冲着编程和 Agent 产品去的,跟我「给课程配音」八竿子打不着。最要命的是它按月续费,而我这是个一次性活,跑完就完了,订阅天然不划算。

后来我给自己总结了一条法则:一次性任务用按量付费,只有你会长期、大量地用,订阅才值。这条放别的地方也通用。

真正给我上了一课的,是那笔账

这笔账我得掰开揉碎讲,因为我自己就在这上面栽过。

18 节课清洗成纯朗读文本之后,大概 6.8 万字。我当时拿 hd 的单价一乘,估了个 ¥24 出头,心想这点钱无所谓,直接全量跑吧。

结果账单不对。实际扣的钱比我估的高出一大截,全程花了 ¥40 多。我查了半天才搞明白这个坑:TTS 不是按你原文的字数计费,是按它实际朗读的内容计费。问题就出在数字和符号上。文里写「100万」「35%」这种,模型念出来是「一百万」「百分之三十五」,字符一下就膨胀了。说白了,实际计费差不多是原文字数的 1.7 倍。

所以你要估这种活的成本,记住乘个 1.7,别像我一样按原始字数估,会算少接近一半。

还有个更省心的建议:先用几毛钱跑个小样。我后面专门留了个只合成某一节开头的命令,几毛钱听一耳朵,音色对了再全量铺开。要是音色没定好就把 18 节全跑了,发现不对再重来,那又是几十块打水漂。

这一路真正让我记住的,是几个坑

技术选型听着挺顺,真动起手来全是坑。挑几个我印象最深的说说。

最离谱的是充值那次。我余额估得不够,合成跑到第 10 节,啪一下报了个 1008 insufficient balance,余额只够撑 9 节就见底了。根子还是那个 1.7 倍没算进去。所以备余额这件事,也得按字数乘 1.7 来准备,别卡着估算值充。

更阴险的是音色那个坑。MiniMax 的音色 ID 长这样:Chinese (Mandarin)_Reliable_Executive,里头带空格还带括号。我图省事把它写进密钥文件,让 shell 用 source 去读,结果那个括号直接把 shell 的解析搞崩了,音色变量根本没设上,脚本默默用了默认音色。我前几节合成出来一听,不对劲,全白做了。后来我老老实实让脚本自己去解析 .env.local,彻底不依赖 shell 那一套,才算稳住。

还有一个坑,是花钱的活才会让你格外肉疼的那种。我那个记账的清单文件,一开始是设计成整个任务跑完才一次性写盘。听着没问题,但只要中途崩一次,前面那几节的「记账」就全丢了,重跑的时候它不知道哪些已经做过,会从头再来一遍,等于重复花钱。我后来改成每合成一节就立刻把这一节的记录落盘,崩了也不丢进度,更不会重复扣费。长任务,尤其是花钱的长任务,一定要边做边存,别等最后统一写,这是我这回学到最值的一条。

剩下几个就是经典劝退项了,私有仓库用不了 GitHub Pages 免费版,所以换了 Cloudflare Pages;域名解析在阿里云、不在 Cloudflare,我手动加了条 CNAME 过去,Cloudflare 那边几乎是秒签的 HTTPS 证书;macOS 新版的系统 Python 被保护着、pip 装不了包,建个虚拟环境就解决了。这些就不展开了,遇到搜一下都有答案。

一个让我以后只花一两块钱改稿的小聪明

前面说的「可增量」那条死规矩,最后是靠一个小设计落地的。

我给每一节算了个指纹,把这一节的朗读文本、用的音色、用的模型揉一块做了个哈希。下次再跑的时候,脚本先比指纹,没变就直接跳过,只重做内容真改了的那几节。这意味着我以后哪天改了第 7 节的几句话,重新生成就只花第 7 节那一节的钱,大概一两块,而不是把 18 节再烧一遍。

这套东西是我用 Claude Code 一点点磨出来的。我还顺手写了个 CLAUDE.md 把项目规则记下来,又把「生成加部署」封成了一个 /deploy 技能,以后更新一句话的事。整个过程也算是个 build in public,做完回头看,真正攒下来的东西,反倒是上面这几条用真金白银踩出来的经验,技术选型本身倒在其次。

写在最后

整个站做下来,音频一次性 ¥40 出头,托管是免费的,域名我本来就有,后续改一节也就一两块钱。一套躺在仓库里没人看的长文,就这么变成了能戴耳机听的东西。

如果你也手里压着一堆写好却没人读的文字,真的可以试试这条路。技术门槛没你想的高,钱也花不了几个,避开我上面这几个坑就行。

成品就在 change-your-life.vance.xin,你可以直接点进去翻一翻、也可以挑一节听听那个配音的质感。最后想问问你:同样一段内容,你是更习惯安静读字,还是更愿意戴上耳机听别人念给你?我挺好奇大家在这两种方式之间是怎么选的。