我是小码哥,欢迎来到我的博客!
- 随意写写,试图记录下自己的每一个平凡日常。
- 时常也会写一些关于创业/产品/Web开发/效率/DevOps/玩等方面的文章。
我是小码哥,欢迎来到我的博客!
FoloToy AI 玩具是如何工作的? FoloToy 出品的所有玩具(包括电路板)作为客户端连接玩具服务,玩具服务我们提供了folotoy-server的docker自部署镜像,可以轻易的部署在各种 Linux 发行版系统上,包括 Debian/Ubuntu/CentOS等等,自部署镜像配置下载地址为: 自部署镜像:https://github.com/FoloToy/folotoy-server-self-hosting 部署教程:https://docs.folotoy.com/zh/docs/installation/start 玩具服务 folotoy-server 主要由以下3个部分组成 语音转文本:服务程序通过互联网接收玩具发送的实时录音数据,并调用 STT(声音转文本)API 将声音转换为文本。目前支持的 STT 选项包括:openai-whisper、azure-stt、azure-whisper、dify-stt、aliyun-asr 等,点击查看支持的STT完整列表。 调用大模型生成文本:在接收到上述文本后,立即调用 LLM(大型语言模型)API以流式方式获取 LLM 生成的句子。然后,调用 TTS(文本转语音)API 将句子转换为人类语音。目前支持的 LLM 选项包括:openai、 azure-openai、gemini、qianfan、dify或由 One-Api 代理的 LLM,以及与 OpenAI 接口兼容的其他大模型服务,如 moonshot 等, 点击查看支持的LLM或者Agent完整列表。 文本转语音:玩具将接收由FoloToy服务器生成的 TTS(文本转语音)音频文件流,并按顺序播放它们。目前支持的 TTS 选项包括: openai-tts、 azure-tts、 elevenlabs、 aliyun-tts、dify-tts、edge-tts(免费)等,点击查看支持的TTS完整列表。 FoloToy AI玩具调用的接口,支持了LLM行业的通行的做法,即完全兼容 OpenAI 的接口,在了解工作原理之后,只需要提供 OpenAI 接口格式相同RESTful接口,给folotoy-server调用,就能实现让玩具使用自定义的STT/LLM/TTS服务,如图所示: 接下来介绍如何实现蓝色圆圈的部分服务 实现和调用自定义服务 实现支持 OpenAI 接口的自定义服务之后可以通过修改 docker-compose.yml 或者 roles.json 文件来调用。docker-compose.yml 为修改全局变量,roles.json 可以针对角色进行修改,roles.json 配置的优先级高于 docker-compose.yml。 自定义 STT 服务 接口说明 自行实现 STT 服务 RESTful 接口说明,详情请参考 OpenAI STT 接口:https://platform....
我的推特账号 x.com/lewangdev 终于解封了,从去年8月17号一直封到今天,已经差不多快有 6 个月的时间。在这 6 个月里,除了今年 1 月份,我每个月都写了一封申请解封的邮件,前几个月全部都是使用 ChatGPT 写的英文版解封申请,就在去年12月份的时候,想想自己莫名其妙被封确实有点恼火,于是用中文写了一封解封邮件,并且提到封我的账号是否是因为审核人员有种族歧视。以下是我的邮件内容: Hi, 已经过去四个月了,我的账号 lewangdev 还是被冻结着的,真是太难熬了。我翻看自己的推文,始终认为我没有发布任何破坏了推特的规则的推文,冻结我的账号一定是一个误会。 我已经使用这个账号十多年了,一直在个人使用,我的账号被冻结不仅是我感觉到惊愕,我的所有朋友们都觉得太莫名奇妙了,让大家都觉得推特平台怎么会这样不确定。 另外我不知道你们为什么会封禁我的账号,是因为我一个亚洲人吗,如果不能给出冻结我账号的明确理由,我非常怀疑你们的审核人员是否有种族歧视。 请帮我解封账号,或者给出明确的冻结理由。 谢谢 到现在我都不知道我的账号为何被封,被举报还是被误杀?也许就像能哥说的,是马斯克在搬机房的时候弄坏了我的数据。看到能哥的说笑我还真可找到了可疑的证据: 账号被封之后几天,我发的推文里面的图片链接都挂掉了。 不过在我收到的解封邮件里,推特还是告诉了我,被冻结是因为违反了平台的4条规则,我确信我都没有做过。以下是推特解封邮件提到的我违反的规则: Sending multiple unsolicited @replies or mentions. Learn more. Posting multiple unrelated updates to a trending or popular topic. Learn more. Aggressive and random repost and/or liking posts from other accounts. Learn more. Misuse of X product features This includes any of the following: “follow churn” – following and then unfollowing large numbers of accounts in an effort to inflate one’s own follower count; indiscriminate following – following and/or unfollowing a large number of unrelated accounts in a short time period, particularly by automated means; and duplicating another account’s followers, particularly using automation....
两周前是我第一次去日本,而且还独自带了一个8岁的孩子一起,在日本十多天,算是佛系的走了几个地方,无论走到哪里都感觉基础设施非常好,城市干净,空气清新,物价低廉,社会文明程度极高,网络畅通,另外饮食也很适合我和孩子的口味,完全不懂日语也不会影响到旅行。 在旅行的过程中,我使用最多的 App 是 Google Maps 和苹果自带的 Translate,找路和坐车都靠 Google Maps,Google Maps 唯一的不足是缺少店铺楼层的信息。我在上海很少用 Google Maps, 所以到了日本还不是很会用,有次在公交站台不知道自己有没有坐对方向来回看,也会有热心的人主动问我怎么样然后教我怎么用。 另外苹果自带的 Translate 使用非常方便,可以语音也可以拍照进行中日文互译,这样在没有中英文菜单的饭馆,也能点菜了。我刚开始没有使用 Translate,第一天住酒店的时候,看到前台在用它与我沟通才想起这个自带的 App。 接下来我从衣食住行四个方面说下我的体验。 「衣」 这次游览的地方在东京和大阪之间的区域,体感温度和上海感觉差不多,只有在箱根大涌谷火山口的山顶比较冷。我们没有带很多衣服,穿着与在上海时完全相同。 另外据说日本优衣库衣服非常便宜,打算实在不够穿再去买几件,后来路过优衣库的时候,还真的去买了几件衣服,但实在不知道要买什么,为了凑单到免税额,买了4件衣服。 「食」 在日本旅行,最不担心就是吃饭。我们在上海也很喜欢吃日式的餐饮,这次去日本更是连续吃了7-8顿寿司。我没有提前去搜索网红的餐厅,基本都是在 Google Maps 上看看住的附近有什么,或者路过商场车站的时候,看看楼宇广告牌有什么吃的就过去了。寿司吃过连锁的店和自助餐厅,价格感觉都不高,人均1-200就能吃得很爽了,像京都站11楼的「築地寿司清」,70-80块就可以点一大盘了。 另外我也去看了超市和便利店,价格低廉的便当比比皆是,而且还写清楚了热量和成分。 感觉不足的地方就是蔬菜和水果吃得很少,这段时间基本是在酒店早餐里才吃得到,如香蕉橙子和蔬菜色拉。要么就是喝各种蔬菜汁和果汁。 「住」 前面讲到日本物价低廉,也是因为我们体验了各种价格酒店之后得出来的一个结论。 订酒店的时候,看到各种价格的酒店都有,这几天住的酒店价格分布在 100-1500 之间,我感觉 100-800 之间的酒店,体验下来基本没什么区别,房间小但都很干净,感觉就像吃的一样,什么价格都有,但是价格便宜的体验也是很好的,甚至几乎所有的酒店配置都差不多,都有浴缸卫洗丽净化器等。而且住的几家酒店的前台,大多都有会说英语的接待人员。 我和朋友说,我在东京住了 300 多的酒店,在京都住了 100 多的酒店时,而且位置很好,酒店条件也很好,大多人反应都是日本酒店不会这么便宜,问我是不是青旅。等我发照片给他们看,才相信是真的。大概也因为是淡季,酒店整体的价格也便宜。 「行」 从上海往返东京或者大阪的机票很便宜,我买的国行的航班往返,提早预订当时花了 6000 多,日本地震后,机票价格暴降,且因地震可以免费退票,于是我退掉重新预订了相同的航班,一下子省了 3000 多块。 在日本的时候交通费用远高于上海,地铁公交都比上海贵一些。通过app和车站的牌子也能看到打车的价格,也是非常的高。 在日本坐地铁和新干线不需要安检,买新干线车票也不需要实名,这点非常的方便。 我在到日本后,在 Apple Pay 里开通了 Suica,并且在东京站也给孩子办理了一张儿童版的 Suica 卡,这样小孩坐公交和地铁都可以半价。Suica 卡不仅可以当公交卡使用,在很多自动售货机和店铺都可以直接当银行卡使用,无接触的像刷公交卡一样付钱,相当的方便。 下一次旅行 以前一直没有去过日本,因为担心语言的问题,现在来看,完全不用担心,这趟旅行我和孩子都非常满意,以后会多多去日本游玩。
最近几天连续做了几次改图标的事情,非常无用却令我开心。 给 Alacritty 换个图标 新安装了 Alacritty 这个终端,Alacritty 什么都好,就是图标我感觉太丑了。之前看到 @hitw93 的博客提到给 Alacritty 更改了图标,我照葫芦画瓢,做了红绿蓝三种颜色的终端图标,替换之后,每次在切换 app 或者在 Lanuchpad 页面看到它的图标时候,都会惊叹自己太有才了,心满意足。我制作的图标和替换方法都放在这里了:Alacritty.icns。 另外 Alacritty 也支持了背景模糊,这个功能我等了很久,不用担心截图时候把背景也显示出来了。 给输入法鼠须管 Squirrel 换个系统托盘图标 然后就是修改 rime 输入法鼠须管 Squirrel 的系统托盘图标了。macOS 在 Ventura/Monoma 系统之后,把输入法的图标由方形变成了矩形,在用 Ventura 或者 Monoma 选择输入法的时候,列表中那种不一致的感觉真让人难受,于是我去rime项目的仓库里搜索了一下有没有报过这个问题,果然有人与我的感受是相同的,我找到了修改图标的 PR,终于所有的输入法图标都一致变成矩形,看起来舒服了很多。 替换步骤: 打开目录 /Library/Input Methods/Squirrel.app/Contents/Resources 下载 rime.pdf 把目录下的 rime.pdf 换掉 退出系统登录再重新登录 给 LaCie 移动硬盘换个图标 今天又做了件没用的事:给移动硬盘换图标。买了块 SATA 口的 SSD,替换已经吃灰多年的 LaCie 移动硬盘里面的机械盘,替换完插到电脑上发现 LaCie 图标竟然没了,于是去官网搜了一下,不愧是法国的公司,管他性能怎么样,首先是要好看,所有产品的 icns 图标都可以下载,并且写清楚了怎么替换。图标和替换方法在这里:LaCie Drive Icons 现在好了,电脑里看得见的地方都满意了,虽然没啥用,却能让自己快乐事,为何不去做。这可能是细节控,每一个做产品的人大概都很注重细节,但是细节在一些情况下也需要妥协。 还是一件小事,我在发推特的时候会遇到:发推时是否需在英文单词的左右添加空格。我虽然有蓝标,但是我还是希望我的推文尽量只用一条并且能在 280 个字符以内,这样不会被折叠起来。如果提炼推文之后字数还超了,手动输入的空格明显就是浪费了,所以字数较少的推我会加空格,字数较多的推文我会去掉空格。 就这样,我经常会折腾一些无用的事,想一些无用的问题,但是能给我带来快乐。
在主机还有 1 天到期之前,尝试下云就成功了,节省几千块。从阿里云下载的虚拟机文件在本地用 qemu 运行没有任何问题,因为备份的磁盘文件单个接近 200GB,我还担心网络问题以及操作复杂会比较耗时间,于是先把主机降到了最低配置准备再续一个月,没想到迁移过程很丝滑。这次迁移主机的系统盘和数据盘是通过下载从阿里云的磁盘快照构建镜像来恢复的,而不是通过备份数据的方式。 通过直接恢复虚拟机磁盘这种方式来迁移云主机,相较于通过 rsync 备份数据,要方便得多。 以下是我的操作过程。 阿里云导出主机镜像的文档写得还是不错的,生成和导出磁盘镜像我都是看阿里云文档来操作。第一步是打开阿里云控制台进入镜像页面,为自己的云主机创建一个镜像。我的这台主机每天都自动生成快照,并且在创建镜像之前,我手动也创建了一个永久保存的快照,我用这个永久快照来构建镜像的。 接下来点击「导出镜像」,阿里云后台会弹出提示窗口,根据提示配置好 oss Bucket,然后耐心等待,最后在会在 oss Bucket 看到两个文件,一个是系统盘,另外一个数据盘。 从 oss Bucket 下载文件到外网的流量是收费,我第一次直接用 http 链接下载,系统盘可以下载下来,但是数据盘下载失败了,浪费了不少的流量(钱),后来尝试用 阿里云的 ossutil 命令来下载,一次就成功了,把着两个文件下载到本地之后,接下来在本地使用 qemu 就可以把虚拟机跑起来 我从阿里云导出的 raw 格式的镜像, qemu 可以直接使用,如果打算用 virtualbox 来运行,也可以尝试用 qumu-img 转为 virtualbox 支持的磁盘格式。我这里直接解压系统盘和数据盘文件之后,执行一下命令来构建虚拟机: # 使用系统盘创建虚拟机 virt-install \ --name aliyun-ci \ --osinfo centos7 \ --ram 8192 \ --vcpus 4 \ --network network=default \ --disk /var/lib/libvirt/images/aliyun-ci.raw \ --graphics vnc,listen=0.0.0.0 \ --noautoconsole --autostart \ --import # 挂载数据盘 virsh attach-disk aliyun-ci /mnt/nas/aliyun/ci/data....
昨天组装了一台GPU 开发机,我使用 rcode+vscode+docker 可以快速搭建出隔离的cuda开发环境,我感觉非常的方便。特别是 rcode 这个命令在使用 docker 构建 cuda 开发环境时非常有用。下面以搭建 faster-whisper 开发环境为例: faster-whisper 的项目说明里提到,NVIDIA 官方 Docker 镜像 nvidia/cuda:11.8.0-cudnn8-runtime-ubuntu22.04 已经包括了开发需要的库 cuBLAS for CUDA 11 和 cuDNN 8 for CUDA 11。执行以下命令下载并启动这个镜像,并且在启动时,安装好需要的 python 库 和 openssh-server 服务 执行以下命令查找到刚刚启动的容器的名称 sudo docker ps 例如我的容器名称是 admiring_kapitsa,使用以下命令进入容器的 console sudo docker exec -it admiring_kapitsa /bin/bash 进入 console 之后,进入 /root 目录,创建以下目录和文件,并且把自己的公钥加到 authorized_keys 中: mkdir /root/.ssh touch /root/.ssh/authorized_keys chmod 600 /root/.ssh/authorized_keys 经过这一步操作之后,后面可以通过 ssh 直接登录到容器中。 关闭容器 admiring_kapitsa 之后,把容器 commit 为一个本地镜像,这样以后可以重复使用 sudo docker stop admiring_kapitsa sudo docker commit admiring_kapitsa lewangdev/cudalab 下载 faster-whisper 的代码然后重新启动一个容器,并且配置好容器的 ssh 端口,挂载 faster-whisper 项目代码到容器中,例如我这里把 8822 端口映射到容器的 22 端口,把 faster-whisper 代码挂载到容器的 /src 目录下:...
获取「改造火火兔」动态和「FoloToy」玩具进展请关注我的电报频道 FoloToy 从上个月在推上公开一系列脑洞开始,到选定其中做智能硬件的想法,借助「改造火火兔」到昨天大概一个多月才算验证通所有的产品化技术难点,群友们都在安静等待着产品发布,我自己反而觉得越来越着急,这是一个月遇到技术问题的汇总,希望也能给其他做 IoT 硬件产品的朋友以启发。 我们没有选用树莓派之类的可以运行完整 Linux 的方案,而是采用了 ESP32 嵌入式方案,我们希望模块可以做得非常小,功耗低,成本也低,这样我们就需要自己搞定硬件的设计和固件的开发,也就遇到了后续的这些问题。 开始的选择了 ESP32S3 模块,搭配数字麦克风,第一版硬件做出来以后,发现数字麦克风在 USB 充电时总是会受到干扰,导致录音噪声太多以致不能识别语音,经过多次尝试,始终无法解决问题,我认为这种缺陷无法接受,需要调整。在测试玩具自带的模拟麦克风时,发现效果非常好,于是尝试使用自带麦克风。 起初想法是用户在拿到板子后,不需要自己运行服务程序,只需在固件中配置好 OpenAI 和 Azure 的 APIKey 就可以使用,在做了一些测试之后,发现芯片计算能力有限,从录音到播放生成的回复语音这段过程耗时太长,这样的体验让人难以接受,而把语音处理的过程放到服务器来实现后,回复较短的情况下,整体的响应的速度提高到 3-5s。 ChatGPT 玩具在对话时需要一直在线,是需要联网的 IoT 设备,除了要支持上下行控制指令和配置参数的下发上传,还需要上传下载语音。实现上,在线控制我们使用了 MQTT, 实时发送语音使用单独了 UDP 通道,设备再通过 HTTPS 下载服务器生成好的语音回复文件来播放,数据传输的方案也是遇到一些问题后才确定的。 一开始,我们认为玩具的交互过程非常简单,直接使用 UDP 就可以了,但在实现的过程中发现,服务器在向 ESP32 板子发送 UDP 的语音数据时,会发生非常明显的丢包,从而造成扬声器播放有断断续续的现象,而且不同的电脑运行服务器程序现象还不尽相同,我的 MacBook 体验就很好,而换成 ThinkPad 就丢包严重。 从 UDP 上解决这个问题我感觉难度较大,可能要我们自己做缓存适配硬件解码速度的来播放语音。于是我们从服务器推语音文件转向由板子自己拉(下载)语音文件的方式,流程:板子通过 UDP 上传语音,服务器接收语音后通过 MQTT 下发语音文件 URL,在服务器完成所有的接口调用和语音处理之后,通知板子下载语音。 到此,技术上主要的问题都已经解决,此外我们还做好了通过 Web 更新固件,配网,定义好了灯的状态,而且芯片换为资源更多的 ESP32,从而有足够的 Flash 用于存储出厂固件等。 另外也我注册好了产品的域名 https://FoloToy.com,接下来我们在 https://FoloToy.com 上相会, 谢谢。
上个月在 X 上公开脑洞之后,得到了很多 X 友的鼓励和帮助,而且讨论氛围实在是太棒,让我很是感动。看到有位 X 友这样说: 𝕏𝕏助手™:评论区的态度和语气都很友善,让思路在探讨中变得更清晰这件事本身,不光对推主,对其他参与讨论或仅围观的推友来说,或许都有一定的参考价值。也是交流的意义之所在 原文点击这里查看:原文。 我把一些建议汇总了一下,放在这篇博文里。 开发硬件产品的门槛,做方案和做产品的区别 象牙山刘能:儿童那个不错,不过看起来不像是单枪匹马的项目 小码哥:能哥看得很准,我有个小团队,做 IoT 方案的,在验证这个想法 雷尼尔: 这个方案技术上的问题不是问题,我验证过了。但是真正的门槛在后面,产品开发和市场运营。 因为这个东西需要一直联网,而且对网络的信号有要求。另外设备网络的初始化,以及chatgpt或者类似技术在大陆的合规,都是比较大的问题。另外就是moq。你这个产品出来后,产品是自己做还是卖给其他人,差别很大。如果你自己做,开模具,到产品的初次量产,需要投入的资金都是不低的。做硬件产品的门槛要比软件高很多。 小码哥:合规的问题在大陆比较难解决,等政策明确了再看走正常途径申报,或者面向国内的产品就用国内的技术方案。光做硬件做到“产品”级门槛就很高,外型做好看一点,硬件本体最大的成本可能就是结构设计和开模。 我考虑先不追求外观,尽可能利用现有玩具的公模或者3d打印,芯片方案考虑用 ESP32,先做 DEMO orange.ai:ai智能硬件空间还蛮大的,找到合适的模型,效果会很好。国家对硬件也没有啥监管,挺好发育的。 henu王凯:硬件门槛特别高、周期长、风险大,独立开发者、资金不宽裕的别碰硬件。 Justin.Ko: 智能硬件能toc,做得好能上量。对应的问题是团队变大,链条长,对创业有一定难度 Morris: 为什么用火火兔做智能硬件Demo?它有开放接口可定制吗? 小码哥: 因为我家里刚好有,另外它也是国内前几年儿童故事机市场最顶级的IP,应该会比较容易玩起来 ZHX:儿童玩具硬件部分也容易实现,主要是营销推广 昵称太受欢迎已被抢注: 儿童教育,英语智能对话,或者发音纠正的,应该很好 如何去做 Digital Signage(数字广告屏) Raymond: 我不是做硬件的,但是我其实非常羡慕可以做硬件的朋友,说实话,需求真的是太多了,比卷上天的软件多了去了。独立开发者,成功的案例也多,比如做 HHKB 蓝牙硬件的那个人,这个算是非常细分,非常小众了吧,过去10年,他个人只是做这个的收益,肯定非常可观了。还有哪个做LED氛围灯的,也是做的不错。 Yup: 这些里面我最看好的项目是做 Digital Signage的 SaaS,这个市场不大,但毛利丰足。做一个通用的管理后端,以插件形式深耕各个使用场景,以至于插件市场也是可以做成收费。将你们很在行的硬件盒子铺到Amazon等渠道,找KOL review一下,在线广告推一推,可以的。。。 Yup: 另外,做SaaS就真的不建议面向国内市场了,一定要先出海 小码哥: 多谢指导。前段时间接了一个港澳那边 Digital Signage 的项目,做完项目之后,大体上是这个思路 BobJiang: digital signage SaaS这个有利润,虽然规模不大,但是做深一点,复购还是可以。具体就考验你怎么执行了 小码哥: 确实,最近做了一个海外的digital signage项目,都是采购的软硬件产品来交付的,看到里面有不少地方可以去改进,关键的是项目的利润非常好。 验证产品需求的方法 Luo说不啰嗦: 加油!建议先验证需求再开动,选择比努力重要。 Tantan Fu: 请教一下如何验证需求呀? 你看我的尝试,感觉验证不成功 Luo说不啰嗦: 首先,想清楚你的用户是谁,这个画像一定要越精准越好,不要试图一上来做一款 for everyone 的产品,这会成为你的负担。想清楚用户是谁之后,把人群特征用几个关键词列出来,这时候你就可以开始验证了:落地页/博客/社群/发帖, 尽可能多地收集线索 (leads),和他们对话,做预售。...
写了篇随笔记录送娃那天的心里感受,拍照片录视频很容易记录一些画面,但是想把自己的心里感受的记录下来,可能还是要靠文字 我的妹妹一家三口住在南方小镇,暑假之前儿子就和我说好,等放假了他要和奶奶一起去姑姑家找哥哥玩。上海南站有趟卧铺列车时间很合适,在高铁的时代,儿子从来没有体验过卧铺列车旅行,全家商量好之后,儿子决定尝试“新”的旅行方式。 送儿子和我妈去上海南站坐车,我先送他们到出发层,车站门口只能停 6 分钟,送他们到进站口后,我便马上返回车上开往停车场,准备在停好车之后再去车站找他们,还没等我停好车,儿子打来电话,好稚嫩的声音:“爸爸,你走吧,我们不需要你了,我们已经找到了候车的地方。” 我听完在夸他做得很好之后,除了惊讶,心里竟有了些失落,不过想到他那小小孩子就有了独立自信的样子,我心里也有了些许难以言说的自豪。 我刚出停车场没开出多远,我妈又打来了电话,说她在候车厅看到有人可以帮他们送上车,问我要不要让人送一下。我当然说同意,然后就听到我妈在电话里传来喊人的声音:“师傅,师傅,帮我们送上去” 。挂掉电话后,我继续驾车前行。 不一会儿,我正在高架上行驶,我妈再一次打来了电话。她告诉我他们已经到达了自己的卧铺座位,还告诉我他们没有找人送,因为我儿子不同意,死活不让别人送,坚持要自己去找位置。 其实在我妈打电话给我的时候,我也在想,虽然这是你们第一次坐卧铺车,但也没什么行李,是可以自己排队检票上车的。这时才明白原来我妈给我打电话是希望征得我的支持来否定她孙子的想法。 儿子继续在电话里和我说,奶奶路上一直在问人,他觉得没有必要,因为他有妈妈给他制作的乘车卡片,再根据车站里面的路牌指示,就可以认得路。我能想象出儿子他那坚定自信的样子,就像平时他坚持他可以自己建造他的乐高城堡一样。 祝他们旅途顺利。
这几天在整理自己以前随意记录的文字,准备喂给 ChatGPT 看看能不能做出一个 AI, 真的 Talk to Myself, 顺便放几篇到博客上来充充数 本文写于 2018 年 8 月 28 日, 天气晴 28-33°C 这几天上海的天气都很不错,最近一个月台风特别多,而且巧得很都是周末来。最热的夏天已经过去了,早上骑着共享单车去云台路那边的星巴克办公,大概需要骑行 15 分钟。 每天骑车路上,总是有汽车不让路权的情形发生,没办法,肉身是斗不过杀人机器的,只好让让他们,人们的驾驶素养如此的差劲,没有好转的迹象,越来越让自己失去了对这个中国最发达城市一点点的爱。像这样的情形,几乎走在马路的人天天都会遇到,也没人愿意出来指责,姑且就这样吧。 想起来前几天在黄浦区人民政府那栋棺材楼附近,我绿灯走人行道过马路,还被转弯的烂司机指着警告,连一旁的金发外国友人都看了瞠目结舌。本想跟他较真到底,想想还是算了,祖国的人民警察那么忙,没空来处理这样的小屁事。就算来了又如何,对司机扣 2 分罚 100 块钱能有什么用?更何况,满大街的都是没有执法权的临时工警察(辅警协警), 喊了他们也没用, 就算喊来了,他们也是会催你赶紧走,别妨碍交通。哪里还有希望,我看不到。 不想太烦心,随他去吧,爱怎样就怎样,没人在乎。 每天的最快乐的时光是下班回到家里。和老婆一起陪陪孩子,做做游戏,聊聊天,轻松自在。今天和娃一起玩识字的游戏,一人写,家里剩下的人认字。儿子才三岁,当然不太认识几个汉字,但是他有很强的要“赢”的心态,一旦“输”就会伤心的哭起来。我妈说很像我小时候,自尊心太强了。 我不太认同自尊心太强这个说法。好在自己小时的那种感觉还没有完全消失,希望能帮助儿子自己找到问题(也可能不是问题),要让他知道,输了也无妨,至少可以看到自己的弱在哪里,而且能认识冠军赢家也挺好,输了也可以大方的走过去为赢家送去祝贺。更何况,很多事情根本也不是比赛,不一定要有输赢。
前几天亚马逊宣告 Kindle 中国电子书店运营进行调整,通知标题写得比较委婉,其实就是亚马逊电子书即将退出中国市场,到时候我们购买的国行版 Kindle 将不能购买新电子书,也不能下载已经购买的电子书了。 如果购买的电子书比较多,手动一本一本的去下载是挺费时间的,我来分享一下我是如何使用 Python 一键下载所有电子书的。 安装 Python 用 Chrome 浏览器打开 https://python.org,下载最新版本的 Python 3.10.4 下载好然后运行 python-3.10.4-amd64.exe, 选择第一个选项,一定要记得勾选添加到 PATH,否则在命令行中执行 python 时会报错。 准备 Python 一键下载脚本 用 Chrome 浏览器打开 https://github.com/yihong0618/Kindle_download_helper,下载 ZIP 包后并且解压: 使用 Python 一键下载脚本 进入解压后的目录,点击鼠标右键打开一个命令行窗口 打开的命令行窗口是这样的: 接下来准备 python 的虚拟环境,在命令行窗口输入: python -m venv venv 创建好虚拟环境之后,再激活虚拟环境,在命令行窗口输入: .\venv\Scripts\activate.bat 安装 Python 脚本的依赖库,在命令行窗口输入: pip install -r requirements.txt 至此,一键下载脚本准备就绪,在命令行窗口输入: python kindle.py 这样看到了脚本的帮助提示: 接下来我们准备脚本需要的 cookie 和 csrf_token, 这两个值都需要通过 Chrome 浏览器获取。 获取 cookie 和 csrf_token 首先使用浏览器登录亚马逊账号, 登录地址 https://z.cn, 登录之后访问 https://www....
前几天刷新闻的时候,看到了一个代码仓库 YouTubeDrive 的介绍,他的作者在多年前用 Wolfram 语言(也就是 Mathematica) 编写了一段代码,可以将油管变成一个无限容量的大网盘,看完介绍之后我脑子里直接蹦出无数个“卧槽”,心里顿生“这样也行”的膜拜之情,不禁提问:这个是薅羊毛的最高境界吗? 说起 Wolfram 语言和 Mathematica,不得不提一下,它是我学习的第一个编程语言(汇编是第二个)。多年前我是在学校机房学的,当时只用它画画数学公式的图,今天看着 YouTubeDrive 的实现,才了解到 Wolfram 还可以这样用。 首先,和原作者一样,我也不提倡这样把 YouTube 当成一个无限容量的网盘使用,相同的道理,我也不提倡在国内把 B 站或者任意视频平台当做位无限容量的网盘来用。 昨天在看完 YouTubeDrive 源码之后,想着要不我也用 Python 实现一个,正好傍晚溜娃的时候,啥也不能干,就边走边想,我用 Python 应该怎么来实现一个? 在坐着等娃的时候,就用手机查下资料,大概了解了一下 numpy 和 opencv 的使用,晚上吃过晚饭就开始写了,很快也实现了一个可以工作的 Python 版的。 我觉得这个想法还是挺有意思的,虽然不太靠谱,但是真的好玩。不想去读 Wolfram 源码的朋友可以看看我接下来的分析,看看是如何把文件变成 YouTube 视频的进行存储的。 磁盘上的文件是什么 在我们的计算机(无论电脑还是手机都是计算机)磁盘里,存放了很多很多的文件,例如图片,文档,视频等等,每种文件都有自己的类型,或者叫格式,一般我们都会给文件添加一个后缀名展示文件的类型,但是对于电脑而言,无论是什么文件,它都只是由比特(bit) 0 和 1 组成的数据。 例如这张图片: 用 vim 执行命令 :%!xxd,打开是这样的: 图片文件的头 4 个字节是 ffd8(其实 ffd8 说明了这个是 JPEG 格式的文件),ffd8 是 16 进制的表示法,比 2 进制看起来更清晰。 在计算机里,用 8 个 bit 表示一个 byte,即 1 个字节有 8 位,一个字节需要用 2 个 16 进制数来表示,例如:ffd8 是 2 个字节。...
趁着周末空隙把自己年久失修博客整理了一下,用到了 grep,xargs 和 sed 命令,使用这 3 个命令组合批量替换了所有 Markdown 文件中的图片链接。 我的博客从我的学生时代就开始了,不断折腾自己的博客,所以学会了 HTML/CSS/JS,下次和大家分享一下我的博客旅程。 这里不详细讲解这 3 个命令的使用,这 3 个命令的使用可以写出来厚厚的一本书。如果希望详细的了解这些命令,可以在 Linux 的终端下输入这样的命令查看文档,例如查看 grep 如何使用: man grep man 命令的常用操作: 退出: 按 q 键 查找:按 / 后输入查找关键字 下一页: 按 ctrl + d 或者 ctrl + f,tips: 这里的 d 大概是 down,f 大概是 forward 上一页: 按 ctrl + u 或者 ctrl + b,tips: 这里的 d 大概是 up,b 大概是 backward 查看其它命令的手册也是类似的。 我博客的问题 我的博客是用 hugo 构建的,所有的文章都放在 post 下面的目录里,图片则需要放在 static 的 images 下面,这样在用 vscode 写博客 Markdown 的时候无法在预览里面看到图片。于是我在 hugo 项目的根目录下添加了的一个 images 的符号链接到 static 目录下的 images, 才能解决图片预览的问题。...
今天要改 Docker 的两个配置 hostconfig.json 和 config.v2.json,打开一看,这个文件是单行的,在编辑器里面显示这是这样的: 代码都堆在一起,用 vim 格式化也没啥效果,编辑起来不是很方便。 Python 自带模块格式化 JSON 格式化 JSON 文件有很多方法,我最常用的就是 Python 自带的 json.tool 这个模块,只要安装了 Python 的电脑,都可以直接使用,这样就可以了: python -m json.tool hostconfig.json > hostconfig-formatted.json 格式化以后再打开看一看: 这样编辑文件就方便多了。 与管道符一起使用 前面的例子我们还可以使用管道符(|)来实现,例如: cat hostconfig.json | python -m json.tool > hostconfig-formatted.json 从 RESTful 接口直接获取数据并且格式化: curl -s https://api.github.com/users/lewangdev | python -m json.tool 其它本地格式化工具 DevToysMac: MacOS 版的 DevToys or Windows,我是用 Windows 11 时候看到这个软件的,于是顺手搜了一下 MacOS 版的,也挺好用的。 jq: 除了像 sed 一样的处理 JSON 以外,还能把输出的 JSON 变成彩色的。 curl 'https://api....
本项目正在调整,请稍等再使用 一个对国内开发者可能有点用的网络工具,cndevnet 帮助开发者,尤其是初学者不用再费心折腾 pip/npm/golang/flutter/android/blockchain 等等无法访问的问题。 背景 由于某些原因,国内开发者需要的不少技术站点或者镜像源都无法直接访问,这使得在开发者在日常工作中会消耗额外的时间,去设置各种代理或者寻找国内的可替代的镜像源来使用。 在开源软件的世界里,几乎所有的知名项目,原本只要把代码 clone 回来,不需要做额外任何配置,只需要按照它的说明就可以直接编译源码。但由于网络的原因,在国内甚至连开源软件的源码都不太方便直接下载,一些原本只需要从 GitHub 拉下来代码就可以直接编译成功的项目,在国内也是连编译都编译不过。 国内开发者群体是非常庞大的,所以我看到了很多知名的开源项目为中国用户在 README.md 文档或是页面的显著位置都增加了中文提示,去引导国内开发者去使用国内的镜像。 Flutter powerlevel10k 但是,我想这种做法应该不属于 i18n,因为我很少看到有引导日本的开发者去用日本的镜像,或者引导德国的开发者去用德国的镜像,这看似解决了访问慢或者无法访问的问题,但其实是加剧了国内开发者与全球互联网的割裂,在开发者的世界里面,也形成了国内和国外两个网络。 给系统或软件单独设置代理,或者寻找国内的可替代的镜像源我都觉得不是一个好方案,因为这样在国内的你总会遇到各种各样的国外开发者就不会遇到的问题,最好还是能够拥有一个与国外开发者“用起来”好像是一样的网络环境。 cndevnet 就是为了解决这个问题而创建的,希望能帮助到和我一样遇到相同问题的国内开发者。 从 Linux 开始 cndevnet 可以在 Linux 环境下搭建一个专为初学开发者设置的开发网络,搭配使用 vscode 进行远程开发是一种不错的体验,适合学习 python/golang 等。 Linux 环境可以是在国内云平台上的一台云主机,也可以是运行在本地虚拟机里面的主机,或者是局域网中的一台 Linux 主机。 Debian 是一个非常棒的 Linux 发行版,推荐希望学习 Linux 的初学者使用。如果希望使用带有图形界面的 Linux 系统,Ubuntu 也是一个非常好的选择。 cndevnet 使用了以下软件和服务 Debian:目前支持的 Linux 系统 Docker: 用于运行 gost 和 smartdns 服务 gost: 用于建立 WSS(Websocket over TLS) 服务 smartdns: 用于解决 DNS 污染 dnsmasq-china-list: 国内域名 Cloudflare IP Range: Cloudflare 的 IP 范围 Cloudflare: Cloudflare 的 WSS 代理服务 Oracle Cloud: Oracle Cloud 的云主机 cndevnet 原理 cndevnet 通过 iptables 等工具和数据实现了系统的透明代理,由于是系统级的透明代理,所以在启用了 cndevnet 的 Linux 系统上,是不需要为系统或者各类开发工具或者服务单独设置代理的。...
gost 是一个非常有用的网络工具,可以在 ShadowsocksX-NG 中安装 gost 插件,方便在 ShadowsocksX-NG 中使用 gost。 原由 自从查资料上网工具换成 gost 之后,由于 MacOS 上没有 gost 专用的智能代理(也就是该翻的时候翻,不用翻的时候不翻)桌面客户端,所以需要用 gost 在本地把 wss 代理转成 ss 后再继续使用 ShadowsocksX-NG。 虽然可以用 launchctl 启动一个 gost 后台服务,但是用起来还是不太方便。 看了下 ShadowsocksX-NG 是如何工作的: ShadowsocksX-NG 会在本地启动 ss-local 进程跑一个 socks5 服务,而且 ShadowsocksX-NG 实现智能代理的逻辑与 ss-local 并没有太多的关系,所以只要在想办法本地能提供一个 socks5 服务就够了。 于是写了以下脚本替换了 ShadowsocksX-NG 安装目录下的 ss-local(替换之前要备份一下这个文件) #!/bin/sh - #/opt/gost/gost -L=sock5://:1086 -F=wss://username:[email protected]:443 # Use gost.json #{ # "Retries": 3, # "Debug": false, # "ServeNodes": [ # "socks5://127.0.0.1:1086" # ], # "ChainNodes": [ # "wss://username:password@1....
创业这段时间以来,我们的 IoT 系统已经在不少客户的机房做了私有化部署,客户大多都是机加工厂、商业大楼、医院和大学实验室等,客户的机房都有一个相同的特点:私有云,与外网隔离,不能访问互联网。或者更为准确的说,是我们部署的服务器不能访问互联网,在没有互联网访问权限的情况下,系统的包管理工具(yum/apt/docker)都无法使用了,在这种情况下进行系统部署安装,费时费力,而且无法进行远程部署维护,也大大增加了项目的实施成本。 在最近的一个客户项目的实施过程中,看到客户的一些其他供应商在系统部署过程中非常艰难,甚至是 CentOS 系统初始化和 Docker 的安装就花掉了两个礼拜的人力,不排除一些供应商这样折腾会给他的客户留下工作敬业钱花的值的好印象,但对于我们这样的小创业公司来说,这样的时间浪费和低效是无法承担的成本,因为来实操部署的人就是公司老板本人了,我也不想出差在客户这里待上两个礼拜。 在工作完成之后,想想可以把解决问题的方法记录一下,也许能给遇到相同问题的同行一些启发和帮助。好了,废话不多说,接下来我们就来解决这个无外网的部署问题,顺便再解决一下远程维护的问题。 一、面临的问题 在部署和维护一个私有化企业内部使用且无互联网访问的系统中,可能会面临以下问题: 机房服务器无法访问 Internet 可通过接入企业内网来访问服务器,而从服务器无法直连办公室网络,即机房和办公室在不同的网段 无互联网访问权限的情况下,无法直接使用系统的配置工具,如 yum/apt/docker 等,配置系统和部署服务费时费力 无法远程进行维护 客户内网拓扑示意图,此处省略了防火墙,简化拓扑图的复杂度,如下: 网络拓扑图说明: 机房和办公室不在一个网段 机房网段假设为 172.22.0.0/16,办公室内网 WiFi 的网段为 192.168.137.0/24 机房服务器之间是互通的,办公室可以 ping 通机房服务器,在机房服务器上无法 ping 通办公室部署控制主机,这里假设办公室网络作为一个 NAT 放在上层交换机后面 内网没有互联网访问权限,包括机房服务器和办公室内网 WiFI 二、解决问题的方法 既然是由于机房服务器没有互联网访问权限,不能联网下载安装包,那就想办法让机房服务器可以连接互联网或者搭建内网的软件包镜像服务,于是想到一些方法来达到目的: 告知客户问题,申请开通互联网访问权限,可以限定为指定的网址和协议(HTTP/HTTPS),需要远程维护的化,还需要申请可以连接到服务器的 VPN。这个方法在需要客户的进行审批,可能时间比较长。我们的客户中有不少都没有自建 VPN,或这不方便给我们开通 VPN,另外也无法开通需要我们部署的服务器的互联网访问权限,所以不能使用这个方法 在客户机房放置可以通过 4G 上网的堡垒机,堡垒机接入客户机房网络。在客户机房放一个堡垒机,虽然说是堡垒机,但可能客户那边的机房管理也还是不容许放置这样的机器的,所以也不能使用这个方法 搭建 yum(CentOS)/apt(Debian/Ubuntu)/docker 的内网镜像服务,搭建内网镜像服务可能就是一个比较艰巨的任务,难以接受给自己又添加了一个艰难的任务,此方法也作罢 通过在办公室网里放置部署控制机,同时连接内网和 4G 路由器提供的外网(互联网),在部署控制机上搭建 SDWAN 或者 HTTP 代理,yum/apt/docker 都支持 HTTP 代理,这样修改系统配置之后,就可以通过代理安装部署服务,这个方法比较简单,而且几乎不需要客户的参与就可以完成。不过也有一些前置条件,例如: 办公室中主机可以接入客户网络 客户服务器允许办公室网络中主机通过 TCP 或者 UDP 访问其任意或者指定的端口 客户办公室的 4G 网络信号要足够好,这样可以提供更好的外网速度 拥有服务器的 root 管理员权限(需要安装软件和修改系统配置) 通过权衡利弊,我们最终使用的是第 4 个方法来搭建的,下面来讲讲搭建的过程。...
小码哥:“与大象(Gradle)一见如故?你就是 Gradle?” 大象:“对,我就是那个用来构建 Java 项目的 Gradle 大象。 ” 小码哥:“我好像天天都在用你啊。看,我的项目都是用你构建的。” 大象:“但你不一定真的认识我,你每次修改点构建代码时是不是都要问下谷哥哥(Google)或溢栈哥哥(StackOverflow)?” 小码哥:“额。。。” 大象:“我是你的老朋友了,不要天天如初见哦,咱们得多聊聊,我爸妈给我写了传记(文档),估计你也懒得细看,不如我给你做个自我介绍吧。” 小码哥:“👌ok” 大象:“你有用 InteliJ IDEA 吗? ” 小码哥:“对,用的社区版。” 大象:“那我就用 InteliJ IDEA CE 版来给你介绍自己”。 你好,我是 Gradle! Gradle 是一个用来自动化构建项目的的工具,可以用来构建你常用的 Java、Kotlin 等 JVM 语言开发的项目。我的配置文件可以使用 Gvoovy 或者 Kotlin 来编写,不像隔壁前辈 Maven 那样,要写一大段 XML,你可以很开心的像写代码一样来调整我的配置。 其实我就是你的代码自动化产线,产线有几个工序(Task),你负责喂我代码,我负责打包(Jar/War/JavaDoc/Test)。是不是觉得与科幻片里面的工厂很像? 创建项目 请打开你的 InteliJ IDEA CE,使用 idea 可以很方便的创建一个由我构建的项目(File > New > Project…)。 这里在对话框的左边栏选择 Gradle,右边选择 Java 项目。 输入好项目名之后点击 Finish 就可以啦。 探索项目 idea 帮我们创建了一个 Java 项目,浏览项目很容易发现两个以 gradle 为结尾的文件: build.gradle 和 settings.gradle。我们来看一下它们俩的内容。 settings.gradle...
昨日陪小糍粑参加幼儿园秋游活动,游览了一下位于松江区的方塔园,校方安排幼儿在白色布袋上绘画,于是有了以下大作。 观察幼儿绘画的过程挺有意思的,我们父母无须提供任何绘画的指导,只要等待小朋友们绘画完毕,来听听他们关于自己的画的解释即可。 关于上面的画,小糍粑是这样解释的。 他和爸爸来看方塔,想象和爸爸在方塔里面,草地的旁边有水,有果树(梨树),有蓝天,蓝天上面有飞机在飞,他穿着红色的衣服和黑色的鞋子。 我感觉他画的非常自信,有考虑绘画的布局,所有的线条几乎都是一笔成型,丝毫不拖沓,很符合这个年龄幼儿的表现。 图里面有个地方是我画的,大家可以猜猜是哪里。
背景 搭建 VPN 方便连接无公网 IP 云主机进行开发,WireGuard 配置比 OpenVPN 要简单很多,WireGuard 是通过 Linux 内核模块的方式实现的,这样性能最好,但是只能用在 Linux 系统上。本文使用的 wireguard-go, 则是使用 Golang 实现的 WireGuard 协议,属于用户空间(User Space)的实现,性能没有内核模块方式好,但好处就是跨平台且更简单易用。 VPN 的用处非常的多,不像 frp 之类的端口穿透应用,它是直接建立虚拟的网络,网络中的每个客户端也都可以拥有自己独立的 IP,于是测试调试就没有了端口的限制,非常的方便。 除了方便安全连接云服务器,还可以通过 VPN 搭建工业设备的远程部署和维护的解决方案。 编译 wireguard-go # 使用 GitHub 的源码镜像,速度会快一些 git clone [email protected]:wireguard/wireguard-go.git # 在 MacOS 下交叉编译 CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -v -o "wireguard-go" # Linux 环境下直接编译 go build -v -o "wireguard-go" cp wireguard-go /usr/sbin/ 编译 WireGuard tools git clone [email protected]:wireguard/wireguard.git # 安装依赖 ## debian&ubuntu sudo apt-get install libmnl-dev libelf-dev ## centos sudo yum install libmnl-devel elfutils-libelf-devel cd wireguard/src/tools make sudo make install 配置 WireGuard 生成密钥...