2025-10-29 08:00:00

你是否像我一样,在日常碎片化时间中翻看公众号,即便遇到不错的文章,但是往往没时间深入细看,或者看过却回头就忘记了?仿佛我们看了个热闹而已,有多少内容转换为有效的输入了呢?本文分享如何用 Readwise Reader 打造个人知识管理系统,实现公众号文章的自动抓取、智能分类和深度阅读。
日常生活中,关于知识的更新,除了一些主动订阅的 Feed 流外,公众号的一批还不错的文章时常能让我扩大一些视野。有人说在短视频热之后,以往做公众号自媒体的一批人切过去了,仍然坚持留下来继续写公众号的人,反而让这块天地有了更纯粹和更高质量了,事实是否如此我不知道。我自己也写公众号,不求有多少人关注,也不想跟随热点,但愿能以文会友,交结到一些志同道合的朋友。
在我日常吃饭、如厕等时候,会翻看一些公众号,有一些较长的文章或者技术密度高的文章,为了不错失某些内容,我常将它悬浮可以随时调出来细读,但咱不明白微信为何限制只能稍后读5篇文章,并且几篇文章的切换和操作体验极差。
有些适合深度阅读的好文,它和我们日常使用手机的方式是冲突的。我个人更喜欢在电脑上,或者在专用软件上查看。我们可以划线留言,可以高亮备注。或许这样,先前的"看过"才不至于流于形式。
有个同事给我推荐了 Readwise,我发现它非常好地命中了我的诉求。它的功能非常简单,但却超级实用,如同它的宣传语:
Get the most out of what you read Readwise makes it easy to revisit and learn from your ebook & article highlights.
这个方案解决了我们信息获取和处理的几个关键点,我称之为串联或连接。

比如,它有浏览器插件,安装后我们可以方便地对正在阅读的网页内容划线、高亮或备注,这一切就会进入到你的 Readwise 账号中。还有一个副产品Reader,我觉得更赞的是,它支持将某个 URL 自动抓取,支持播客,支持传统 RSS,还支持youtube等视频直接在Reader 中观看,字幕同步。当然还可以导入 PDF、EBOOK等,在这里进行更深入的阅读和处理。

这样,信息的获取和快速处理便解决了。接下来工具不止于此,Readwise 除了提供我们划线或备注的 Review 功能后,更是可以将我们的这些内容与其它外部工具结合,比如相关内容自动同步到 Notion 中。
不止是 Notion,几乎市面上常见的主流的笔记软件它都可以导出,像印象笔记、Obsidian甚至 Apple Notes。还有热门的 MCP 等都支持,我只能惊叹。
但显然这是一篇技术文章,不是做广告。毕竟 Readwise出身于国外,互联网平台的技术封锁没有那么强,这个东西好归好,在国内却会有点水土不服了。比如微信公众号文章,你会发现给它链接后,它可能抓取不完整或者缺图片等,怎么办呢?继续往下看呗!
咱不是爱造轮子的人,遇上问题当然搜索过。找到这个工具,试用了一下效果还不错。

但我发现好像也有一些小问题,比如摘要不合理,有一些较长的文章,它不是对全文的摘要,只是文章部分内容的复述。其次标签不准确或者没有,对于快速 Get 文章主要内容的人,有时会观察一下相关标签,如上文,似乎没有生成任何标签,我推测是原文没有标签,所以在抓取保存入 Reader 后也没有标签。最后,它还是比较人性化地提供了 15 天免费试用的机会,但再想要使用,需要支付一定费用(好像年费 45 元,我已经付过表示支持作者)。当然如果你格外介意隐私,可能也会有一些小担心。
那么,作为一个程序员,是时候自己动手来解决这个问题了。
我希望对于这些文章的抓取是离线的,是Headless的。我的整体思想是先用成熟的组件自己组装一个相关功能,再考虑局部优化。整体交互希望和方案一类似的比较简单直接。
之前用过一阵firecrawl MCP来抓取网页,能力还不错,所以我先用它来抓取。在实践之前,咱们先基于MCP来测试一下效果。
Firecrawl 抓取结果示例:
|
|
结果不如人意,部分图片可以抓取到,但有部分图片显示为占位符。原因是微信公众号的部分图片是懒加载的,需要滚动到可见区域才会加载。既然firecrawl不行,有没有更强大的工具呢?请求AI支招,它推荐了Scrapeless,咱们来试试。通过一番注册与认证后,获得了免费试用额度。官方没有提供直接的MCP server,不过我把它的开发文档丢给AI,几分钟就搞定了。
通过Scrapeless解决上面图片问题的方式,主要是模拟了浏览器滚动后使图片可见,从而抓取到图片。当然我们还要将抓取的HTML中的占位符替换为最终图片:
|
|

我们这里使用的是现成的服务,我看了一下抓取一次网页的成本很低,一次请求几分钱。

现在抓取的内容已经可以正常显示了,还有一些元信息如文章发布时间等因为不在Content中,需要额外一点小处理即可。接下来我们需要将内容导入到Reader中。
上面我将抓取功能封装为一个 MCP server 了,现在要调用它并且将相关返回进一步处理。比如摘要,标签等通过 LLM 智能生成。考虑到作为 server 的可测试及调试性,我使用 GO 来实现它。代码已经不重要(若有人有需求未来可公开于 GitHub),我们看一下提示语即可:
|
|
最开始我犯了个错误,提取用时很长,仔细一看,它还返回了文章本体内容,这也难怪!千万别像我这样又费时又费钱,所以提示语中限制了某些字段不返回。上面我们让AI的输出完全按照Readwise API的文档来,这样便于接下来使用。
Readwise 提供了 API 可以助于我们将现成的 HTML 导入到它 Reader 中,它的文档在这里:Readwise API。借助于 AI,我把文档链接丢给它,没一会儿它就完成了相关接口封装,这时我连文档都还没看完,这颇有点温酒斩华雄的感觉。如果你的 AI 不能正常读取到文档,前面提过的 firecrawl mcp 不失为一个好选择,我经常借用它来访问某些文档。
代码写好,单元测试也看起来一切正常,哐当~导入成功!我们去 Reader 中看一看,咦,怎么文章的封面是这个玩意?它提示微信不允许展示,而文章里面的图片一切正常了,这是为什么呢?(此处不放图了,文章我还想在微信公众号发出呢:D)
显然直接怀疑对象就是微信限制了其它来源的访问,不过咱们文章内部又能显示图片?直接F12分析,猜想是正确的。

可是蹊跷的是:我使用方案一中第三方解决方案,它的图片能正常显示。我进一步分析了一下,它的封面图片域名和我的不一样,是 wework.qpic.cn,我推测它们是将封面图片推到另一个自己可控的地方(不受 Referer 限制),然后修改了原文章的图片 URL,这样我们就可以正常显示图片了。咱也不是不能效仿,不过这会有一定成本。
还有一个蹊跷的事,尽管我没处理封面图片,但在手机的 Reader 客户端,它显示是正常的,会自动使用第一张图片(Why?)作为封面。
如果仅是电脑上有此问题,要解决这个就有其它方法了。网上看关于此问题的相关文章: https://an.admirable.pro/wechat-platform-referer/,我们借助于浏览器插件 Referer Control,添加一个规则将访问微信域名的请求的Referer设置为https://mp.weixin.qq.com,刷新后就可以正常显示图片了。
为了更容易将公众号文章分享后保存,方案一中使用转发到企业微信的某个账号,自动保存。我尝试自建了一个企业,创建了一个自建应用,可以接收输入的消息并通过 Webhook 交给后端处理。

之后我们完善服务器处理相关消息的逻辑即可,这块涉及消息加解密直接使用现成的 GO 包比较好,AI 可能尝试自己裸写相关逻辑,纯增加调试的工作量了。完成之后,当我将一个链接发给企业微信这个应用时,它便触发了上面我们的抓取文章以及导入到 Reader。我以为就要搞定收工了,但发生了意外。当我想通过微信添加这个应用,发现不可能,这条路不通。之后我又创建一个成员账号等,通过某种 hack 可以通过微信将消息发送到内部,但又不提供 API 访问和处理这类消息。准确的说不是不提供,需要企业认证,并且还需要额外付费,它这个功能叫会话内容存档。我理解微信限制这块的道理,避免虚假信息(企业)对微信生态的影响。
这条路走得戛然而止,现在我只能企业内部使用了,复制链接并且贴到内部应用号上,才能完成我的文章收藏功能。
这是这篇文章拖了很久的一个原因,没找到突破口。我还想找一个更好的途径便于一键分享,如果你有方法欢迎留言告知于我,感谢。
通过以上工作,我们算是按自己的想法实现了文章的抓取和导入到 Reader。我们来看一下效果:

可以看到针对文档生成了摘要和标签等,这相比于第三方的方案一定程度满足了自己的诉求,关键是咱是免费的呢!
本文主体内容到这里就结束了,感谢阅读。上面相关的代码都已经在GitHub开源了,如果你觉得有诚意,请给我的文章点个赞或在看呀!感谢感谢!
上文文章提到 Readwise,它的用途不止于此,比如我尝试统一管理邮件,邮件作为每天处理的信息流之一也是不错的,避免我经常漏掉某些重要通知。悄悄告诉你,Readwise虽然是收费的,我朋友说还提供了发展中国家的优惠,发个邮件很快申请到了,50% OFF。至于推广链接啥的,我太懒就不留了:)
本文介绍的方法,不光适用于微信公众号,只要是一个网页都适用,平常我还会看知乎等平台的文章,但知乎是有登录态限制的,如何将知乎文章保存呢?如果你也有兴趣,我也有一些想法,欢迎联系我探讨一下。
欢迎关注我,说不定后续就会有你想要的内容到来。下回见!
我是个爱折腾技术的工程师,也乐于分享。欢迎点赞、关注、分享,更欢迎一起探讨技术问题,共同学习,共同进步。为了获得更及时的文章推送,欢迎关注我的公众号:爱折腾的风

2025-08-31 08:00:00

难得出游,一边吹着海风,看着AI帮我在一片空白的白板上慢慢添加各种元素,也是另一种触感。牛马在驱动牛马 :)
在我使用Obsidian后了解到了绘图工具excalidraw,我曾经用它画了一些图,手绘风格在众多图表呈现中有它独特的味道。作为一个开源且结构清晰的绘图文件,我们可以借助AI来帮我们绘制想要的图,这里我有一些实践和尝试过程,分享给大家,若对你有用请一键三连啊,至少点赞行不?
本文分享的自动绘图不止适用于在Obsidian的Excalidraw插件中,同时也支持网页端(如官方)自动绘图。
我在Obsidian中随便画了一个图,这个文件从文本视角内容大概是这样:
|
|
将这个文件丢给AI分析了一下,给了如下的描述:
|
|
既然内容只是一个JSON,有压缩标识也可以不压缩,那么让AI帮我们生成内容难度就不大了。 我们先看看市面上当前有哪些方案以及它们的特点。
我搜索到有个MCP server (mcp_excalidraw](https://github.com/yctimlin/mcp_excalidraw),可以简单的启用:
|
|
现在我们打开浏览器,访问:http://localhost:3000 看到熟悉的Excalidraw绘图页面:
点右上角的Sync to Backend后我们的前后台打通,即可准备mcp server来操作这个画布了。以下是mcp-server的配置(替换成你的本地路径):
|
|
使用如下prompt:
请使用excalidraw mcp插件绘制一个太阳系及行星的运行图
选择一个合适的模型比如Claude-4-Sonnet,不一会儿我们就可以得到一个还不错的太阳系科谱示意图了:
各个行星相对于地球的体积AI还挺讲究,大体是对了。
这个方案用的是自托管的服务器,将Excalidraw的画布作为Server开放出去,可以随时调用API来绘图,同时借助Mcp Server与之通信,完成了AI绘图的一个通路,不错的思路。 那么,既然在网页上绘图,咱能不能直接在 Excalidraw 官方绘图网站上直接使用AI绘图呢?
我这里说的不是官方网站的AI绘图功能,它需要开通会员,而且我在免费试用期间就感觉到它还比较简单,AI画不了啥有用的图,但别慌,我们有黑科技!
我们先介绍一个强大的Chrome浏览器插件mcp-chrome插件:
🌟 让chrome浏览器变成你的智能助手 - 让AI接管你的浏览器,将您的浏览器转变为强大的 AI 控制自动化工具。
可以在GitHub根据文档下载安装,之后打开它:

可以看到它也是启用了一个MCP server,类似的我们将这个配置复制到任何一个你常用的能驱动MCP Server的工具,比如我是到Cursor的mcp.json中,顺手它改个名字叫mcp-chrome:
|
|
我们可以刷新一下工具,可以看到它有这些能力:

原来它的实现原理是向页面中注入一些脚本,之后通过HTTP和页面通信,并基于我们发给它的消息内容调用相应的页面工具。可是咱们是要在这个页面绘图呢,这就需要另一个东西 excalidraw-prompt了,你同样可以在上面的repo的prompt中获取到。我们可以简单看下内容:
|
|
将它复制到你的prompt中,如果在Cursor等编辑器中,另存为一个文件,一会引用它。现在我们就准备就绪了,测试一下:
请参考 @excalidraw-prompt.md ,调用mcp-chrome在excalidraw中帮我绘制一个太阳系的示意图
你会发现浏览器自动打开了excalidraw.com页面并且LLM正在尝试注入控制脚本等,如果顺利,一会便能在白板上陆续出现各种元素了。但也可能不幸运,卡在首页中,注入脚本不成功。经过我分析,这种情况有两种可能:
grok-code-fast-1也能基本完成任务。使用Gemini2.5 Pro或Claude4也完全没问题。app.excalidraw.com。因为如你有登录态,网站会重定向到app.excalidraw.com,那个页面插件就找不到正确的注入点了。有两种做法,修改脚本让它兼容,或者修改一下我们的prompt,让打开 excalidraw.com/#noredirect页面。
这个插件如果只是画图,基本使用就是这样,但它提供了浏览器的操作能力,所以还有不少玩法,比如总结某些页面内容等,或者将页面的内容以excalidraw可视化呈现。 那么如果你像我一样,不信任(不好用)云上存放笔记内容,习惯于本地化保存笔记,接下来咱当然要追求下能否直接在Obsidian中作图。
虽然我们使用mcp-chrome+prompt在excalidraw.com上绘图很方便,但仍然需要浏览器操作,甚至还需要一点儿时间等待打开浏览器和注入脚本等动作。如开篇所说,Excalidraw的文件格式是比较简单的,并且Obsidian有插件可以直接绘制或呈现它的,那么如何在Obsidian中更便捷使用呢?
我们让AI先基于之前分析的Excalidraw文件格式,生成一套提示词:
请参考 @excalidraw格式说明.md ,帮我生成一个用于指导 AI 生成相关excalidraw文件的prompt 文件,取名为excalidraw绘图大师
没一会AI就给我们生成了一份不错的Prompt指南,想的还挺周到,绝对比我自己写的初版要好,请你也过目一下:
|
|
我们稍作一点小修改,原来Excalidraw的文件中有一部分 compressed-json字段,有压缩的格式后续让AI生成容易出错,我们将其改为不需要压缩,这样AI生成绘图文件一次成功率便高多了。现在我们只要一句话,比如:
请参考 @excalidraw绘图大师.md 帮我创建一个火箭发射的运行原理示意图

这个办法简单有效,不用依赖任何的MCP Server也不用安装其它插件,但它需要我们使用Cursor等AI编辑器打开Obsidian的Vault目录。我们再贪心点,能不能直接在Obsidian中操作呢?也不是不行。
有一款插件叫obsidian-local-rest-api,可以让我们的Obsidian以REST API来提供接口:
This plugin provides a secure HTTPS interface gated behind api key authentication that allows you to:
- Read, create, update or delete existing notes. There’s even a PATCH HTTP method for inserting content into a particular section of a note.
- List notes stored in your vault.
- Create and fetch periodic notes.
- Execute commands and list what commands are available.
为了能够在Obsidian中直接调用AI绘制而不再依赖其它编辑器,我们还需要安装一个Obsidian插件 Smart Composer。它提供了和大模型聊天对话而修改笔记的功能,灵感来源于Cursor。同时也支持MCP Server。关于它的更多使用技巧,未来有空可以另起一篇文章。现在我们继续配置上:Obsidian mcp-server:
|
|
然后和之前类似,我们只要让它参考我们的Prompt,说明要绘制什么即可,当然对现在有笔记进行总结并梳理出一些图表也是不在话下。

经过一番探索,相信你也大概感受到了基于AI来调用Excalidraw绘图并非难事。未来当基础模型越发强大,这块的上手难度可能会更低。 在实际体验中,不同模型的审美以及指令遵循上还是有不少差异的。使用时需要注意选择适合自己的模型,也需要注意花费。
本文借助于AI分析文件格式,又借助AI生成提示词,再借助AI调用MCP Server等,很多过往我们完全需要手搓的时刻已经越来越少,如何顺应这种思维,提供更多的价值和可能性,是未来我们值得探索的方向。
当然,模型的更新可以毁灭曾经的各种努力,但,在路上就是意义,是吧?
以上便是最近关于Excalidraw的一点折腾经验,希望对你有帮助。欢迎点赞、收藏、分享,更欢迎分享你的使用经验。我们下篇文章见。
我是个爱折腾技术的工程师,也乐于分享。欢迎点赞、关注、分享,更欢迎一起探讨技术问题,共同学习,共同进步。为了获得更及时的文章推送,欢迎关注我的公众号:爱折腾的风

2025-07-20 08:00:00

最近Claude Code爆火,很多人都说Cursor不香了。无奈原生的Claude Code使用对国人来说特别不便,我这里尝试了一些新的解决方案,希望对你流畅使用Claude Code有帮助。
Claude模型的母公司Anthropic,对国内用户使用限制特别多,我曾经注册或购买的几个号没多久就阵亡了。但人家的这个工具确实不错,我们没账号怎么办?
听说可以使用一些第三方模型了,比如最近国内月之暗面推出的Kimi-K2,它们机智的直接支持了Anthropic的API。我们可以简单配置一下,就可以在Claude Code中使用Kimi-K2模型了。 但是有时我们想使用其他更强大的模型,比如Gemini,怎么办?
我又继续寻找到了最近刚开源的一个解决方案,claude-code-router,它支持了多个模型,包括Gemini,DeepSeek,GPT等。这里又产生一个问题,可以使用原生Gemini模型,但Google家模型不能精确控制预算,哪天你哐哐用,金钱也哗哗出的时候,看到账单傻眼了怎么办?
以上各个问题,本文都会尝试给一个解决方案,如果对你有帮助,请帮我点个赞吧!
本文假定你会Claude Code的安装和使用,我们直接进入主题:如何优雅的让Claude Code使用第三方模型?
这块已经有不少文章介绍了,我简单说几个关键点:
|
|
~/.claude.json 添加(你可能要先启动一次才会自动生成这个配置):
|
|
然后重启Claude Code,就可以使用Kimi-K2模型了。在里面似乎kimi做得足够兼容,你连模型都不用切换,直接就开箱即用了。我问了一句你是谁,看来Claude Code有被骗到:)
|
|

我感觉Kimi-K2这次挺“鸡贼”的,借了一波Claude Code的东风,应该引了不少新进,现在它官网开始提示繁忙起来了呢:)
我试着用了一阵Kimi-K2,有时候反应较慢,我在想是否可能把Gemini家的和OpenAI家的模型一起集成进来呢?方法当然是有的。
在一两周前,我在寻找如何让Claude Code可使用更多种第三方模型。在搜索这个问题的解法,国外的Perplexity居然没有推荐这个项目,反倒是国内腾讯元宝给我介绍了有这样一个开源项目,claude-code-router(以下简称CCR)可能解决我的问题,一看到我甚为惊喜,我想莫不是这个项目是国人写的原因,咱离自己人更近。
A powerful tool to route Claude Code requests to different models and customize any request.
在GitHub仓库中也写了项目的实现原理。简单的说,作者经过逆向分析后,发现在Claude Code中它在调用模型时,各个参数都是通过环境变量获取的,作者想到开发一个中间件,将各个环境变量替换掉,这样可以实现调用第三方模型。同时因为Claude Code使用Anthropic API的规范,我们需要将对第三方模型的调用转换成Anthropic API的格式。
和Claude Code类似通过npm即可安装。
|
|
你可以参考官方提供的示例,配置~/.claude-code-router/config.json:
|
|
这里定义了不同的Provider,并且有一些模型可以有其设置。比如为了让DeepSeek模型更积极使用工具,有个tooluse的设置。比如为了转换Gemini模型,有个gemini的Transformer。 同时可看到,它还真是国人开发,很有本地化特色,比如显式支持PROXY设置方便你访问某些模型。
到这里配置好后,当你在使用Claude Code时,想切换模型时,可以输入/model命令,然后选择你想要的模型。比如:

不过有点遗憾的是,当前通过CCR中还不支持Web搜索和图片上传,这离我们想要的完整体还是有点距离,但官方已经在计划中,并且这个项目最近更新很频繁,Star也涨得非常快。
折腾到这里就结束了吗?这里发生了一件小事,让我觉得有必要继续折腾一下。我使用OpenRouter来调用Claude模型,为了省钱,我已经很勤俭地只用 claude-3.7-sonnet 了,但几轮对话下来,发现账单还是有点夸张。我在一个不算太大的项目中进行了/init和简要对话而已。虽然OpenRouter提供了对每个KEY的费用限制(Credit limit),但是如Google的Gemini等模型,它就没有可以限制额度,那就只能等收到账单才后知后觉了?
问题不大,我想起来之前折腾过LiteLLM,它不仅能聚合LLM接口,还能像个贴心管家一样帮你控制预算。就决定是你了,继续折腾!
很早前想写一篇LiteLLM+Librechat的教程,但一直没时间,今天就让LiteLLM先出场吧。我继续在k8s中部署它,如果你是容器或其它方式,请参考官方文档,部署过程都是简单的。
我们创建一个configmap定义了LiteLLM的配置文件config.yaml,大概内容如下:
|
|
接着定义一个Deployment即可。
|
|
要注意LiteLLM启动时,有时资源消耗会比较高,我的弱鸡k8s节点时不时会给搞得濒死,最好像上面限制一下资源。 我们可以测试一下LiteLLM对外的接口是否正常,比如:
|
|
正常返回后,说明我们的LiteLLM服务工作正常。接下来我们就可以在claude-code-router中统一使用litellm作为唯一的Provider了。
现在,我们的config.json可以变得非常清爽,Providers里只留下litellm一个就行:
|
|
这里要注意,如果直接对接官方的Gemini模型,只需要配置Gemini的Transformer即可。但这里咱们是通过LiteLLM调用的,还需要配置use: cleancache的Transformer。不然会报类似下面这样的错误:
⎿ API Error: 400 {“error”:{“message”:“Error from provider: {"error":{"message":"litellm.BadRequestError: VertexAIException BadRequestError - {\n \"error\": {\n \"code\": 400,\n \"message\": \"* GenerateContentRequest.contents: contents is not specified\\n\",\n \"status\": \"INVALID_ARGUMENT\"\n }\n}\n. Received Model Group=gemini/gemini-2.5-pro\nAvailable Model Group Fallbacks=None","type":null,"param":null,"code":"400"}}”,“type”:“api_error”,“code”:“provider_response_error”}}
还好LiteLLM的日志相当给力,我通过排查请求体,很快就定位到问题出在 “cache_control” 这个字段上——删掉它就一切正常了。最后我们可以在LiteLLM的管理端看到每次Claude Code发出了哪些请求,使用了多少Token,花费了多少钱等。

我们也可以在LiteLLM中创建的API_KEY中定义它的额度,这样避免我们不小心超支。

现在,让我们开心的在Claude Code中使用各种模型吧!
本文介绍了三种方式让你更好的基于第三方大语言模型来使用Claude Code,希望对你有所帮助。我们除了直接使用Kimi-K2外,还可以使用CCR来扩展模型库,最后通过LiteLLM来统一LLM的调用,这样也能让我们更精细化的观察Token的使用以及控制费用。
三种方案对比:
| 特性 | 方案一:Kimi 直连 | 方案二:CCR | 方案三:CCR + LiteLLM |
|---|---|---|---|
| 设置简易度 | ⭐⭐⭐⭐⭐ (极简) | ⭐⭐⭐⭐ (简单) | ⭐⭐ (较复杂) |
| 模型丰富度 | ⭐ (仅 Kimi) | ⭐⭐⭐⭐ (丰富) | ⭐⭐⭐⭐⭐ (最丰富) |
| 费用控制力 | ⭐⭐ (依赖 Kimi 平台) | ⭐⭐ (依赖上游) | ⭐⭐⭐⭐⭐ (精准控制) |
| 折腾系数 | ⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
以上便是最近关于Claude Code的一点折腾经验,希望对你有帮助。欢迎点赞、收藏、分享,更欢迎分享你的使用经验。我们下篇文章见。
我是个爱折腾技术的工程师,也乐于分享。欢迎点赞、关注、分享,更欢迎一起探讨技术问题,共同学习,共同进步。为了获得更及时的文章推送,欢迎关注我的公众号:爱折腾的风

2025-07-12 08:00:00

经常从图书馆借一些书来给孩子看,有一些是他们感兴趣的可以反复阅读的,无奈借书终有归期,如何解决这个问题呢?作为一个程序员爸爸,何不将它“保留”下来,并且让老父亲可以给他们朗读呢?
孩子的天性,对于喜欢的绘本,可以反复阅读,一遍又一遍。我还记得有一次带女儿去图书馆还书,有几本她不舍得还,于是我们在一个楼梯边上坐下,一起再读了一遍。之后才恋恋不舍地将书交给“机器人”(自动分检)。我也颇遗憾的是记忆中有几本书,每次读起来,娃们都笑逐颜开。于是我打算“留住”这些特别的书,那是他们的美妙回忆。
原本打算写个微信小程序,但想着优先把核心功能跑起来,还是以网站呈现比较简单些。花了一些闲暇时间,借助于 VideCoding 有个初步可用的版本了。
以下简要介绍一下我的一些探索和实现过程,代码没整理暂时没打算开源。如果你想看看效果,我已经部署在vercel了,可以访问:https://audiobook-web-brown.vercel.app 查看。


显然我们这个网站有几个基本功能要支持一下,比如绘本管理、绘本语音生成、绘本阅读体验等基本功能,多用户管理也可以考虑。 在绘本管理上,比如:
在绘本语音生成上,我们之前也试过多种声音复刻了,今天会推荐另一个简单便宜的渠道(后文),我考虑这样:
在绘本阅读过程中,希望能提供沉浸式的阅读UI,同时需要支持:
用户管理等就是区分不同的用户和阅读进度等啦,这个就不细说了。我们首先面临的是,绘本从何而来?
我们需要将纸质书迁移到线上,最直接的莫过于拿起手机直接对着绘本拍照了,这里有一点小技巧要注意。为了便于后续照片的处理,我们尽量让书本放在一个比较纯净的背景色下,比如下面垫一张大白纸等。之后是将我们拍的照片处理,这里涉及到一些图像校正,透视校正等,如果可以,一些锐化或超分技术也可以使用上。我尝试了几种方式,最后选择了一个简单的方式,但或许不是最终解:
当然如果花一些时间仔细研究算法和以书本来定制化识别方案,或许是可以调好的。文本图像增强(Text Image Enhancement)是面向文档类图片提供的图像增强处理能力,包括切边增强、图像矫正、阴影去除、摩尔纹去除等;可以有效优化文档类的图片质量,提升文字的清晰度。 它的效果整体还不错,不过对于一些需要先旋转再裁剪的图片,它不会智能处理,所以交给它前最好先预处理一下。
以上,对于希望免费使用,推荐使用 Lens来处理。而如果希望批量自动化处理,或许调用 API 是更便捷的。
当我们已经准备好图片或绘本的 PDF 后,如何将绘本内的文字提取出来便是个问题。我试过传统的 OCR,老实说可读性和进一步处理都比较麻烦。幸运的是现在各种视觉模型都支持图像识别了,所以我们只需要借助他们之力便可以轻松实现目标。考虑到不同模型可能的识别的差异,这里我做了一个测试,使用如下Prompt:
|
|
比如有如下这张图:
📊 各模型结果对比:
| 模型 | 状态 | 识别结果 |
|---|---|---|
| minimax-io/MiniMax-Text-01 | ✅ 主模型 | 蓝色还是有点怀疑: “天空这么大,要不就留在这里?” 山谷中, 有歌声轻轻响起, 洒在她身上的, 是橘色的晨曦。 |
| gemini/gemini-2.5-flash | ❌ 备用模型 | 蓝色还是有点怀疑: 山谷中, 有歌声轻轻响起, 洒在她身上的, 是橘色的晨曦。 |
| doubao/doubao-seed-1.6-flash | ✅ 备用模型 | 蓝色还是有点怀疑:“天空这么大,要不就留在这里?” 山谷中, 有歌声轻轻响起, 洒在她身上的, 是橘色的晨曦。 |
| moonshot/moonshot-v1-8k-vision-preview | ✅ 备用模型 | 蓝色还是有点怀疑: “天空这么大,要不就留在这里?” 山谷中, 有歌声轻轻响起, 洒在她身上的, 是橘色的晨曦。 |
| azure/gpt-4o | ✅ 备用模型 | 蓝色还是有点怀疑: “天空这么大,要不就留在这里?” 山谷中, 有歌声轻轻响起, 落在她身上的, 是橘色的晨曦。 |
| tencent/hunyuan-turbos-vision | ✅ 备用模型 | 蓝色还是有点怀疑: “天空这么大,要不就留在这里?” 山谷中, 有歌声轻轻响起, 洒在她身上的, 是橘色的晨曦。 |
最终结果: 蓝色还是有点怀疑: “天空这么大,要不就留在这里?” 山谷中, 有歌声轻轻响起, 洒在她身上的, 是橘色的晨曦。
上面是写文章时再跑了一次数据,这次 gpt-4o正确了,过往它的错误率也很高。整体的模型测试挺有意思,发现gpt系列没那么准确时,我试了一下gemini 系列,准确性上升不少,但也有出错时。考虑到我是中文绘本的场景,我换成国内的豆包,居然正确率一下提高更多,豆包出错的地方,我就尝试了一下moonshot的模型,又一次给我惊喜,最后是minimax家模型,在我的几个绘本的识别中,准确率是最高的。咱国内模型在这块也是挺能打的嘛!!
我借用多个模型提取出结果,然后有一个模型来判断哪一个是更大概率正确的内容,这样避免单模型的问题,整体上提升识别成功率。 至此,绘本的文字已经准备好,我们开始着手给它配置语音吧。
没有声音,再好的戏也出不来:) 小朋友需要一些声音来辅助读绘本。我在之前的让你的小智AI机器人起飞一文中介绍过如何在腾讯云平台复刻声音并且使用,还有豆包平台也有不少音色可选并且也支持声音复刻。但,等等……我找到一个相对更物美价廉的方案,使用 MiniMax 平台进行 TTS以及复刻。MiniMax平台国内注册即有 15 元可以体验,普通的通过 TTS 生成语音可以花一阵子。复刻一个声音只要 9.9 元,这比豆包和腾讯云上似乎便宜得多。同时我发现它的国际版本 minimax.io 可以申请开发者体验计划,我简单填写了一个表格,很快就到账 50刀,这绝对是很大方了,强烈推荐。 推荐它的原因不光是咱可能免费褥到羊毛,更重要的是它的效果很不错。
MiniMax 这家公司还很早提供了 MCP server,可以直接借助 MCP server测试一下它的能力,使用各种声音(复刻)来从文本生成语音(TTS)。我们甚至都不用写一行代码就可以玩起来了。除了使用 MCP 来复刻,也可以简单的使用几行curl命令来完成。
|
|
返回:
{“file”:{“file_id”:281211669533090,“bytes”:259501,“created_at”:1750210557,“filename”:“output.m4a”,“purpose”:“voice_clone”},“base_resp”:{“status_code”:0,“status_msg”:“success”}}
|
|
返回:
{“input_sensitive”:false,“input_sensitive_type”:0,“demo_audio”:"",“base_resp”:{“status_code”:0,“status_msg”:“success”}}
|
|
注意,在没有使用此音色时,上面查询不到这个,只有在首次使用后才扣费和能够被查询到
欲查询音色类型,支持以下取值:
“system”(系统音色),
“voice_cloning”(快速复刻的音色),
“voice_generation”(文生音色接口生成的音色),
“music_generation”(音乐生成产生的人声或者伴奏音色),
“all”(以上全部)。
|
|
这样这个复刻的音色就可以后面随时使用了。它在你第一次使用时会扣除 9.9 元(国内)或 3 刀(国际)费用。
在我和 Gemini 探讨如何更好的设计这个绘本功能时,它提出了一个很不错的建议:
在准备配音文案时,我建议你创建一个“配音脚本”,不仅仅是抄录文字,而是像一个导演一样,设计整个声音的蓝图。你可以按照这个格式来整理:
| 页面 | 角色/旁白 | 文字内容 | 声音特效/拟声词 | 背景音乐建议 |
| P1-2 | 旁白 | 在一个安静的小镇上,住着一只名叫乐乐的小狗。 | (远处几声狗叫) (风轻轻吹过的声音) | 舒缓、宁静的钢琴曲 |
| P3 | 旁白 | 一天早上,他被一阵“叩叩叩”的声音吵醒了。 | 叩叩叩 (清晰有力的敲门声) | 音乐暂停或减弱 |
| P3 | 乐乐 | “是谁呀?” | (乐乐迷糊的、带点奶气的声音) | (无) |
总结一下,要成为声音的东西,不仅仅是“文字”,而是整个“故事场景”。你需要从一个“阅读者”转变为一个“声音导演”。在看每一页图画时,都可以问自己这几个问题:
通过这样的思考和准备,你最终创作出的有声绘本,将不仅仅是“读”出来的故事,而是一个生动、立体、能让孩子沉浸其中的声音世界。
如果我们可以在绘本期间追加一些声效,以及控制各个角色的声音情绪表现,那必然是更沉浸的体验。这块我寻找了一些方案:
ElevenLabs
Stability AI
测试效果两者效果差不多,从费用上来说,似乎ElevenLabs 更便宜一些。暂时因为时间问题,我还没有将这块和上面 TTS 整合。它需要重新编排识别到的文本,在恰到好处的地方插入音效。未来有时间,我会尝试将这块整合到一起。
这个应用是前后端分离设计的,前端基于 Vue 3 + TypeScript + Vite 构建,提供沉浸式阅读体验和智能用户管理。后端使用 golang来开发,同时将数据保存在对象存储中,这样我们的一些图片音频等可以借助对象存储的 CDN 有更快的响应速度。
我试着让 AI 帮我将前端对接到 Vercel 上,它帮我生成了一个 vercel.json 文件,我试着将它部署到 Vercel 上,结果居然一次成功咯,可以开心的用免费服务了。
|
|
后端就自己将程序打包为镜像,部署在我原来的k8s集群上了。
在初步完成后,我给孩子试用了几次,效果还不错,他们惊讶于识别到这是爸爸的声音,这是他自己的声音等,也能认真的听完一本又一本绘本,作为老父亲,几个晚上的熬夜也没有白费了。 我突然想起来,有几本英文绘本,碍于我自己的英文水平和发音,都没怎么给孩子读,那真是误自己子弟了:)不过,现在有这个玩意,我可算找到救星了!文字就搞个双语吧,那发音到底是英式还是美式好呢?
我是个爱折腾技术的工程师,也乐于分享。欢迎点赞、关注、分享,更欢迎一起探讨技术问题,共同学习,共同进步。为了获得更及时的文章推送,欢迎关注我的公众号:爱折腾的风

2025-06-01 08:00:00

我对现今的前端技术几乎完全不懂,但借助于AI,几乎不需要什么背景知识就可以轻松构建这样一个还不错的应用。本文除了简要介绍一下这个网站的功能外,同时也谈谈开发过程的一些经验感悟,希望对你有所帮助,更期待一起交流经验。
在医院看到不少爸妈都很认真负责地记录着孩子的各项检测数值,我也曾经将一些数据记录在笔记本中。那些牵动家长们内心的数值,一旦离开了纸质记录本,就很难说清楚,也不便于和医生沟通交流,更难发现其中的变化规律。某天在从医院回家的路上,灵机一动:何不构建一个血常规追踪应用,让整个治疗过程清晰直观呢?
本文会简单介绍一下这个网站,更重要的会分享一下在使用Lovable平台和Cursor中的一些独家的感受。
我的Lovable会员每个月有100次AI对话额度,打算物尽其用,“强行”让它值回票价,便计划用它来搭建网站雏形。经历了几天的迭代、趟过一些坑、也用光了Cursor的次数后,我总算以网站的形式,捣鼓出了一个比较完整的血常规追踪功能。先来看看基础功能,后面再谈谈开发过程中的一些经验。
我们可以快速预览到最近一次检测有哪些指标异常:

也可以通过单指标或多指标的选择进一步分析变化趋势,同时可以结合期间的治疗及手术情况,分析指标变化的原因:

然后可以通过医疗日历,查看到每天的用药情况等:

在检测数据的录入中,除了传统的手术填表外,借助于AI识图,可以通过上传图片,系统会自动识别出检测数据,包括采样时间等以及各项指标的数值,并自动填充到表单中:

我们可以添加期间的用药及手术类型,针对不同的病种,可以自定义自己的用药以及手术,可以用不同颜色区分:

同时也提供了一些预设,可以选择性导入:

同时,除了单个日期的添加记录,支持批量选择日期,通过Shift等常用区间选择的交互方式,可以快速添加一整段时间的记录,这样对于一些需要长期用药,这会更便捷一些。
有时找医生沟通,我们需要一个表格呈现一些数据,网站提供了将选定区间的信息导出的功能,同时会标注期间的一些关键事项。

做完这些后,为了让初次使用的人可以快速上手,我们可能还需要一个使用指南,借助于现在便捷的网页生成能力,一个简洁美观的说明页也快速生成了:

尽管头脑中已经有不少这个应用的功能点,但在让AI开始正式编码前,我们还需要细化一些东西,于是我和Gemini 2.5 Pro聊了起来。像一个倾诉对象一样,我和它谈我的目标,也让它反过来询问我一些事项,最后我们敲定了方案,Gemini 2.5 Pro 在我得到有首肯后,很快就帮我生成了一份需求文档。这期间,AI会帮助我们完善一些可能欠考虑的细节,比如数据的隐私性,它强调:
数据安全:对病人的血常规数据进行加密存储,确保数据库中的数据没有明文可读内容。加密算法建议采用行业常用的对称加密算法如AES(高级加密标准),以保障数据在存储过程中的安全性。
最终形成了一个初版的提示词,它将交给Lovable平台:
|
|
虽然作为开发者,手上有不少编程工具可以使用,我这次还是选择了Lovable平台,除了我恰好有会员外,还有几个因素也是比较重要的:
和Lovable寒暄几句(你好)后便开始制造我们应用的初始版本,没一会,几个页面便出来了,整体雏形便有了。页面美观程度嘛,也还不错?
但在和Lovable深入接触后(也就是真正开始开发),我有几点不太爽的感受:
这让我像一个渣男,打算"移情别恋"转投Cursor的怀抱。但更渣的是,我时不时还得回来蹭一下它的发布能力——毕竟人家有打通GitHub一键部署的神通。
我早前写过一篇Cursor的开发技巧及思考,感兴趣可以翻看过往文章,也可以在我博客找到:AI编程之Cursor使用技巧及一些思考。在Lovable那儿碰了几鼻子灰后,我不得不把代码克隆下来,开始进行“真刀真枪”的开发。
借助于Cursor,我们可以这样更有效的推进工作。为了让它知道我在干啥,也为了它不要反复乱改一些设定,我们先让Cursor通读一下整个项目,并生成Cursor rules。没一会就生成了好几个文件,看起来满满当当,也有模有样的,为了更好的使用,你可别全信,咱继续定制:
Always规则,使每次沟通可以带上。反正Cursor又不会基于Token计费(不过Max版本说会收费,你要更小心),这里规则三五百行是没问题的。注意上面默认生成的里面,一般是不会给你设定Always规则的。你每次得自己主动添加上相关文件,这对擅长遗忘的我们容易造成伤害。
|
|
还有一些规则,我们要一边开发,根据AI的表现为它量身定制。比如我们已经npm run dev启动了项目,它每次提交完又想运行一次,你知道这显然不必,咱已经能动态热更新,所以得限制它。有时我们会沉迷于Vibe Coding的便捷,执着于像个甲方一样反复让它修改实现,就是不想思考如何优化规则,这时AI就会反复提醒你:)所以我感觉,在一个较复杂的项目上,想要快,必须得慢下来,琢磨一下如何去定义适合自己的规则。
在不断的调整和修改下,Cursor的月次数告急。我观察了一下Cursor的计数规则,它不是以你每次的交互多少来计数,而是差不多按完成一项工作来计算。于是假如你是想一出是一出,让它把东边修缮一下,西边再改改,那次数就哗哗的没了。可以考虑以一次将要修改的任务整理好,甚至一些关联的地方也提醒它注意修改,这样可以更充分的利用好次数。比如我这里的用药管理和手术管理经常是类似的逻辑,我就让它修改用药管理界面的A、B、C处,同时在手术管理中也需要类似的逻辑。这次只需要消耗一次计数,哗啦啦一大堆代码和功能就完善了。不过这招也别滥用,不建议一次性塞给它太多不相关的修改任务。我的经验是,把类似的功能打包一次性修改,独立的功能分开处理。改完一部分,自己确认没问题了就赶紧提交到版本库,免得一次改太多,到头来想挑挑拣拣哪些要哪些不要的时候,那叫一个尴尬!虽然Cursor和Cline等都有Checkpoint,其实都不好解决这个问题,我们得自己规范流程。
在使用Cursor过程中,过往我对模型的选择没有太在意,但这次我特意观察了一下,发现不同模型在Cursor中的表现还是有些差异的。比如在Cursor中,我试着用了一段时间那传说中被各大自媒体吹爆的Gemini 2.5 Pro,结果发现这家伙有点“高冷范儿”——思维链一开始还好好说中文,搞着搞着就中英混杂,甚至直接飙英文了,跟它沟通像在考六级。同时感觉它可能太过思维活跃了,动不动自我否定又来推敲一次,导致产出效率其实不高。而当我切换到Claude 3.5 Sonnet模型时,它甚至都表现更好一些,这或许和不少人的感知略有不同,我不确定是否Cursor未对它调教好(默认Prompt未能很好适配?)。但也不要迷恋Claude 3.5 Sonnet,在一次调整中,它也陷入了无尽的自我怀疑与纠结中,还是多花一倍代价(2x)切换到它哥(Claude 3.7 Sonnet)后问题很快得以解决。这告诉我一个道理,必要时启用最强大模型有时是更经济的事情。这个道理很快又被证明也不靠谱,因为没几天Claude 4 Sonnet出来了,号称更强大的编码能力,同时在Cursor中更便宜(0.5x)。我赶紧用上,没想到它似乎还是一匹没有驯服的野马,时有脱缰的时候。事后我在想为啥Cursor给这些优惠呢,在几天后费用升到0.75x时,它渐渐好了起来,或许前面就是鼓励我们使用,有足够数据偷偷调教呢?
我是在使用Lovable才知道有Supabase这个数据库的。最开始惊讶于原来居然可以在保障安全性的同时,不需要借助后端,前端直接就可以和DB交互。它借助了Postgresql的RLS机制,用户的权限被严格限制了。在开发期间,我有一次需要调整和迁移DB。最开始我频繁将DB Schema以及现有数据等截图贴给它,然后Cursor又为我生成一些SQL语句,说可以让我在Supabase平台SQL Editor中执行。我意识到这不是我想要的方式,作为一个现代化的BaaS服务(后端即服务),它也提供了mcp server,果断添加到Cursor中,然后就可以在Cursor中直接操作数据库了。
|
|
如下图,对于DB的修改及查询,甚至迁移等工作,都可以借助这个MCP工具完全在Cursor中完成,我终于不用当搬运工了。

整体网站的功能基本就绪后,要是想给其他人用,我寻思着得给它配个好记的网址才行。在NameCheap上找了一个并不太Cheap的com域名: blood-track.com。然后在Lovable平台直接绑定这个域名就可以通过新的自有域名访问啦。我看了一下,域名解析到了一个IPv4地址,应该是Lovable的接入层,因为我在平台登记了项目的自有域名,请求中header又有这个域名信息,故让Lovable路由到它所部署的代码实例上并不困难。
开发的初衷嘛,主要是想解决自己记录、整理和洞察(或‘分析’)这些医疗数据时遇到的一些麻烦。因为所知有限,不一定适配于其它病种,虽然基础完备,但也有一些工作后续有空会继续考虑完善:
本站提供的是公益免费的服务,域名、开发维护等成本较低,包括AI的识别等,整体花费不多暂时能够承担。(话说大模型识别一次检查数据费用不到一分钱,感谢这个时代。)
如果你完整看完,不知道期间的感触你是否也有共鸣?如何在AI时代更高效的开发,这是现今乃至未来几年传统开发者都需要面临和思考的问题。 你可能有疑问为什么不开发一个微信小程序等,其实我也有此意。所以期间也尝试用全新的开发范式来建立微信小程序,比如从UI的设计开始,借助AI来设计交互图,然后我也试着回归VSCode + Cline看整体开发一个微信小程序的成本如何,初步完成一个Demo来看,成本尚可接受。未来有空会进一步聊一聊。有Cline后咱最新的模型或免费的渠道羊毛都可以褥一下,成本可能更低(注意也可能时间成本高得多)。
本篇文章就先到这里,感谢你的耐心阅读。期待未来有更多的成果和经验可以继续和你聊聊,欢迎一起交流探讨。这一块领域,全世界都还在探索,我们保持在路上。
我是个爱折腾技术的工程师,也乐于分享。欢迎点赞、关注、分享,更欢迎一起探讨技术问题,共同学习,共同进步。为了获得更及时的文章推送,欢迎关注我的公众号:爱折腾的风

2025-05-10 08:00:00

有一天,我突然发现无法从外部连接家里的NAS了。我开始慌了,预感到不妙。莫非是公网IP被运营商回收了?我也成为一个大内网用户了。所幸已经有不少成熟的方案,而FRP就是其中之一。它开源免费,易上手,并且支持的协议还比较多(当然,部署服务器的费用得另算)。晚上回到家,我决定面对现实,好好折腾一番。虽然网上现有的FRP教程多数只完成了‘能用’的第一步,但距离‘好用易用’还有点距离。
本文简要描述一下我使用FRP的过程,并且看一下我们如何给FRP套上坚固的盾牌,配上易用的武器。我假定你已经知道FRP是什么,并且最基本的FRP使用已经了解。不了解也没关系,继续看你也大概能懂。
虽然咱数据或许对别人而言也没那么重要,但自我保护意识也不可松懈。
frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP、UDP、HTTP、HTTPS 等多种协议,且支持 P2P 通信。可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。
为了方便迁移和管理,在使用FRP时我首推容器化方案。不过似乎没看到官方的镜像,但dockerhub上有一个社区广泛使用且下载量很高的镜像,大抵错不了:snowdreamtech/frpc和snowdreamtech/frps。
FRP是分客户端和服务端的,需要在不同的机器分别配置。frpc一般部署在内网,用于将内部需要对外暴露的服务定义出来。而frps一般部署在有公网IP的服务器上,用于接收外部连接并转发到内部服务。这里有几个安全事项需要关注:
很多分享的方案里基本不启用TLS,也对暴露的端口没有进一步的限制,这其实是不安全的。秉承这些目标,我们开始行动吧。
这里我直接使用docker-compose部署,并使用snowdreamtech/frpc镜像。
|
|
这里需要的TLS证书一会我们再生成。这里的.env文件内容如下:
|
|
为了方便修改和对齐,我们将frpc.toml文件中的一部分配置放在.env文件中定义。而frpc.toml文件内容如下:
|
|
我们的服务端一般是部署在一台有公网IP的服务器上,用于我们从任何地方通过它连接回家里内网。这个服务器可以从国内国外各种云上买一台或者找机会白嫖一台。我是在腾讯云上有一台机器,安装好docker以及docker-compose后,使用snowdreamtech/frps镜像部署。部署在公网的服务,基于安全性考虑,我们希望即使frps被攻击,其它服务也是安全的,所以除了放在容器中,把网络也隔离出来。这里便不再使用network_mode: host,而是使用默认的network_mode: bridge,同时预留一些端口用于后续我们的服务暴露。
|
|
同样的,为了配置修改方便,我们将frps.toml文件中的一部分配置放在.env文件中定义:
|
|
而frps.toml文件内容如下:
|
|
为了让FRP的连接更安全,我们使用TLS证书来加密连接。它确保我们的frpc和frps之间的连接是安全的,并且防止中间人攻击。我们使用自签名证书来生成TLS证书。以下提供了一段脚本,方便一键生成我们需要的证书。
|
|
使用方式:
|
|
这样我们的服务器与客户端双向认证,谁都不可被冒充。
到这里,你的FRP连接已经通过TLS和双向认证得到了很好的保护,即使token不慎泄露,没有匹配的证书也无法建立连接。接下来,我们在此基础上更进一步,结合云主机的防火墙(安全组)策略,实现更精细的访问控制。我们希望达成:
相信很多人都明白这个道理,但手动操作实在繁琐,所以我们需要一个工具来帮忙。在我看来,最便捷的莫过于再次祭出alfred workflow来实现。于是我抽空写了一个,并开源在github上,感兴趣的可以看这里:alfred-workflow-sg-manager。
我们基于frpc.toml中的一部分配置[[proxies]],来动态开启与关闭相关的端口。一点点前置工作还需要你做的,便是将你的服务器绑定一个安全组,至于安全组后续规则添加维护等就交给这个工具了。
比如先查看一下当前列表:
你上面可以看到这些内网服务还未开放,我们选择一个,比如想从外部访问家里的Mac mini了,我们在alfred框中输入frp open可以看到可开放的列表:
选中Mac mini,然后回车,这个通路便打开了。再次查看可以看到它开放并且绑定了本机的出口IP:

现在你可以开心的从外部VNC到你家内网的Mac mini了,并且安全得多了。
用过之后想关闭的一些端口,比如Mac mini的VNC端口,我们输入frp close,然后选择对应的要关闭的服务回车即可:

现在咱是不是对于FRP的安全使用更有信心了。有些人可能会说:何苦呢,有谁会看中咱攻击咱呢?或许可能Maybe:我们就是控制欲作祟而已:)
还有两个小窍门我也想让你知道,看在这么认真的份上小手点点赞不过份吧!
第一:如上面截图出现了external-http,我们可以借助于将内网服务统一在一个ingress服务(反向代理)下,然后通过这个ingress服务进一步路由,这样我们只需要穿透一个端口即可访问内网的各种服务,免去了配置FRP的手续。也通过让ingress服务走TLS,或者后端服务对接OAuth2等更安全的认证方式,可以进一步保护我们的内网服务。
第二:FRPS除了默认有Dashboard外,还支持Prometheus。我们可以复用这种生态。Prometheus用于收集监控数据,Grafana用于可视化数据和配置告警。比如我们可监控FRP的连接访问情况,并且添加告警,这样某个敏感服务有连接,我们便可以及时收到通知。
本文整体到这里就结束了。我们尝试用docker来部署了FRP的客户端和服务端,并且基于安全的考虑,我们启用了TLS和创建了一个便捷的工具来快速修改云上的安全策略。这犹如一块坚固的盾牌,避免我们可能受到的攻击。
当我折腾好FRP,并且安全地将它保护起来后。有一天,我查看我家的外网IP,发现它居然是一个公网IP。我的天啦,我这折腾一番可是为了啥!我要不要重新回归到公网IP的路线呢?可是我却放不下这份安全了呢。
注:题图来自于互联网,我觉得画得挺棒,若有侵权请联系我删除。
我是个爱折腾技术的工程师,也乐于分享。欢迎点赞、关注、分享,更欢迎一起探讨技术问题,共同学习,共同进步。为了获得更及时的文章推送,欢迎关注我的公众号:爱折腾的风
