082024.4

macos大文件分片上传

我打算把模型文件上传到服务器,可死活上传不上去,git也下载不了,原因肯定是文件太大。于是打算采用分片上传的方案,在本地切分为一堆小文件,上传到服务器后,再到服务器上合并为原始文件。

本地分片:

mkdir chunks # 创建一个用来放切片的目录
split -d -b 100m chatglm3-6b-q4_0-ggml.bin chunks/bin_

执行之后,chunks目录下就会有一大堆bin_**的文件,把这些文件上传到服务器上的一个目录里,然后再服务器上进入这个目录,执行:

cat bin_* > chatglm3-6b-q4_0-ggml.bin

这样就会把这些文件又组合成原始文件,把这个文件放到预定位置后,就可以把这个目录删掉。

21:50:41 已有0条回复
252024.3

Devika:第一个开源的软件工程师AI Agent,致力于成为Devin的开源替代

202024.3

一个用AI做音乐的网站

182024.3

今天把我压箱底的web-replayer公开发布了

在开源Anys之后,我再次把自己的压箱底作品公开发布。在此之前,我一直的想法是密而不发,毕竟现在的伸手党实在是太多了,白嫖过去用,一分钱不掏,最后还可能被喷。虽然开源本身是非常好的,可以促进技术的发展,相互学习,一起创造出一些有意思的东西出来。然而,由于环境不好,好好的一件事,最后搞的不愉快。因此,我现在开源也好,公开发布新东西也好,也都留了一个心眼,避免卷入这些内耗纷争。

今天发布的是我在后台用来进行日志回放的播放器,取名web-replayer,见名知意。

https://www.npmjs.com/package/web-replayer

简单讲它就是一个用代码来进行演示的播放器。什么意思呢?就是它让你的代码执行,像播放器播放视频一样进行执行。我们使用anys的一个能力,就是录制前端页面的变更,用户的行为等等。那么当这些数据进入数据库之后,通过web-replayer,就可以把这些日志数据取出来进行回放,这样我们就可以在web-replayer中,看到用户的操作,以及当时的情况。那么具体怎么把一条条日志数据进行播放呢?这里就需要引入视频里面的“帧”的概念,理论上,1条日志就是1帧。因此,我们只需要把这些一帧一帧的过程,在web环境下给它呈现出来。怎么呈现呢?当然是操作DOM了。因此,我们只需要提供每一帧,如何操作DOM即可。如何操作DOM,则是依赖日志本身,当我们看到是一条mousemove的日志时,我们就操作DOM里面用来模拟鼠标的元素进行移动;当我们看到是一条snapshot的日志时,我们就直接用HTML镜像覆盖当前的DOM。这样,我们把对每一条日志对应的DOM操作都写好之后,我们只需要按照时间的流逝,不断去执行这些动作即可。这就是web-replayer的底层思路。当然,它自己还有一些其他方面的设计和考虑,但是核心思路就在这里。

基于这一思路,web-replayer不单单可以用来回放日志,你甚至可以用来实现一段视频,因为你可以在帧上操作图片、声音等素材,通过代码来编写这些东西,就可以实现一种神奇的“用代码做视频”的效果。

好了,如果你有兴趣,不妨通过上面的链接去下载和使用web-replayer。最后,我使用了较为严格的license,主要是防止某些不良服务商白嫖。如果你是个人,且不需要对源码进行修改,也不需要部署自己的服务,那么可以随便使用。

00:14:15 已有0条回复
072024.3

我们看似不规律的事情,反而是规律的正弦波在时域上的投影,而正弦波又是一个旋转的圆在直线上的投影。……我们眼中的世界就像皮影戏的大幕布,幕后有无数的齿轮在旋转。我们只看到屏幕上毫无规律的小人在表演,无法预测它的下一步。而幕后的齿轮却永远一直那样旋转,永不停歇。

10:12:13 已有0条回复
012024.2

技术本身的发展并不是核心,编程思想的发展才是进步

我最近一直在思考一个问题,大概9年前,我使用sea.js进行前端编程,那个时候觉得它很神奇,但于此同时,AMD/CMD带来的心智负担也很重,在编程中往往遇到一些不符合预期的结果。而我最近写了一个框架PHC,就开始反思,从技术层面讲,在sea.js的时代,似乎也是可以实现PHC的,为什么时隔那么多年,我才能写出这样的一个框架来呢?经过反思,我想这里面最大的原因,在于编程思维的进步。

我为什能写出PHC呢?因为我这么多年在前端的开发经验和尝试,让我自然而然的写出来。而我的这些尝试,往往又是在整个大的技术背景下被驱动的,如果没有这些年在sea.js, angularjs, vue, react等等框架的影响下,没有nodejs, 前端工程化, SSR, 微前端等等技术风潮的熏陶下,我也没有意识去写一个这样的框架。当随着技术的洪流随波逐行时,我们这一批的程序员的思维也在变迁,以前想不到的东西,在通过几个代际的更迭之后,也逐渐有了新想法,就有了PHC的尝试。

这一经历中,我发现,在sea.js的时代,我们完全可以做到PHC的同等效果,但是我们又做不到,因为那个时候没有UI组件化思想、微前端思想、沙盒思想,这些思想都是近几年才出现的,因此,在那个时代,我们无法做到。同样的道理,我现在能写出PHC,就像当年玉伯写出sea.js一样,他在模块化思潮的影响下写出的优秀框架,却无法超越时代写出更精简的实现。借古推今,再几年后,我自己回头看,也会感叹,自己当初怎么只能写出PHC这样的框架呢?历史时点上的思维限制,是我们技术发展本身无关的,虽然在技术发展中,新技术可以为我们提供可以用更少代码实现更强能力的工具,但是我们还是要看到,技术思维的发展,才是我们突破技术局限的核心根源。

这让我想起《三体》小说中的一句忠告:你要想,多想!

12:37:16 已有0条回复
222024.1

一个用canvas实现的word编辑器

122023.12

跨平台Web Canvas渲染引擎架构的设计与思考(内含实现方案)

082023.12

你不知道的sendBeacon

052023.12

如何彻底杀死child_process.exec子进程

最近在尝试使用child_process来跑一些子任务时,调用了yarn的命令来启动一个服务,但是发现怎么调接口都无法kill,子任务还在跑。后来灵光一闪,spawn在运行yarn命令的时候,是不是再在它的上面包了一层。顺藤摸瓜,发现网上也有同样的说法。原来,spawn在运行子命令的时候,首先要选一个shell来跑,默认是使用sh,也可以使用bash或cmd.exe,这个需要在调用spawn的时候传入它的第三个参数里面的配置来确定。这也就意味着,child.pid返回的是调用sh的进程,而在sh里面执行命令产生的子进程的pid不是默认返回的child.pid,而且,在sh里面,可能还会再起其他的子进程,也就是说,实际上,我们看似只跑了一个spawn,但是实际上它可能起了一堆子进程,而我们想要kill的目标进程只是这一堆里面的其中一个。

默认情况下,我们通过ctrl+c可以退出process,而nodejs会把SIGINI传递给所有子进程,进而关闭全部子进程。但是,如果我们自己手动调用child.kill来杀死子进程,就会导致只杀掉了一个,而且可能是最不重要的(因为跑的是sh)。

有了这个前置知识,那么问题就比较好解决了。我们只要封装一个自己的kill函数,传入child.pid,然后把其全部子进程杀掉即可。具体做法可以参考ps-tree里面的示例代码。在我们自己实现的时候,也可以直接引用ps-tree这个包来把所有子进程pid查出来,然后再通过exec遍历它们执行一个kill -9 {pid}即可。如此就可以真正把子进程杀掉了。

13:11:10 已有0条回复