@Lenciel

不花钱的同声传译

最近参加一个技术会议,我请大家举手简单统计了一下参会者在 ChatGPT、Kimi 等产品上的活跃度,发现每天都用的人大大减少了。

这跟我两年前的判断差不多: LLM 对搜索会有很大的冲击(因为用户脑子里有关键词,好写 prompt),但大部分时候,聊天仍然是个非常糟糕的用户界面(问什么怎么问,压力都在用户这边)。

如果让我总结使用 LLM 频度最高的场景,是嵌在飞书里的那些跟开会相关的功能:自动字幕,自动转文本,自动给总结等等。

如果让蒙爷总结,他的最核心场景会是 Youtube 上实时给视频的添加的中文字幕,一下子把他可以看懂的视频扩大了几个数量级。

这些功能都涉及语音转文本再进行处理(记录、总结或者翻译)。由于目前的解决方案基本都是跑在服务器端的,所以也有一些问题。

首先是不够安全。不管是私人的通话,还是工作的会议,把音频录制和处理交给第三方,特别是国内一些厂商,还是让人感觉有点害怕的。

其次是不够灵活。比如,YouTube 自动加字幕的功能,依赖 Google 的服务。本地下载了一部冷门的电影,就还得老老实实花时间去找字幕。

这些问题的解决,核心是下面两个方面:

  • 有没有办法很容易的提取音轨或者转发音频流
  • 有没有办法在本地对音轨或者音频流使用 LLM 进行处理

如果是有钱人,我会推荐 Rogue Amoeba 家的 Loopback 和 Audio Hijack。 Loopback 可以通过创建虚拟声卡对音频进行各种的控制和转发解决第一步。而 Audio Hijack 的新版本里内置了一个 transcribe 模块解决第二步实际上背后也是 OpenAI 的 Whisper ,精确版对应 large-v2 的模型。

advancedblocks-transcribe-frommic.png
图1. 从输入设备对音频流进行录制和转写

如果稍微愿意动动手,我会推荐 ffmpeg +VB-Cable 解决第一个问题,whisper-cpp 解决第二步:因为它们免费,并且开源,完全可控。

下面的步骤针对 Mac,但 Widnes 上相同的思路应该也是工作的。

安装 ffmpeg 和 VB-Cable

ffmpeg 主要用来处理音频文件,安装就直接用 Homebrew。

brew install ffmpeg

然后如果是现场的音频文件,需要处理成 16khz 的 WAV 文件:

ffmpeg -i audio.mp3 -acodec pcm_s16le -ac 1 -ar 16000 audio.wav

如果是视频,则需要抓取里面的音轨做转换:

ffmpeg -i vod.mp4 -hide_banner -vn -ar 16000 -ac 1 -c:a pcm_s16le -y vod-resampled.wav

VB-Cable 是一个安装文件,装好了之后可以看到在音频配置里面多了一块虚拟声卡:

vb-cable.jpg
图2. 输入输出里面都有,因此可以录也可以回放

这个主要是用来捕获音频流的。

安装 whisper-cpp

虽然 Homebrew 提供了 formula 但是我选择了 clone 项目来编译。因为有一些平台相关的优化我不知道 Homebrew 的版本是怎么处理的。

比如,把 Apple Neural Engine (ANE) 用起来 whisper-cpp 能够快最少三倍,但是它需要做一些设置更多关于 whisper-cpp 对 Core ML 的支持,可以看这里

pip install ane_transformers
pip install openai-whisper
pip install coremltools

然后生成模型的 Core ML 版本,比如我使用了 large-v3 版本的模型:

./models/generate-coreml-model.sh large-v3

最后需要打开编译开关进行编译:

# using Makefile
make clean
WHISPER_COREML=1 make -j

当跑起来的时候提示 Core ML 模型正确加载了,就说明成功了:

./main -m models/ggml-large-v3-q5_0.bin ./samples/jfk.wav

...
whisper_init_state: kv cross size =  245.76 MB
whisper_init_state: loading Core ML model from 'models/ggml-large-v3-encoder.mlmodelc'
whisper_init_state: first run on a device may take a while ...
whisper_init_state: Core ML model loaded
ggml_backend_metal_buffer_type_alloc_buffer: allocated buffer, size =     8.80 MiB, ( 1490.55 / 12288.02)

处理音频文件

whisper-cpp 处理本地的音频文件就只需要组合使用参数,比如我要用 8 线程对一部法语电影的音轨做翻译并且生成字幕文件:

./main -m ./models/ggml-large-v3.bin -f samples/movie.wav -l fr -t 8 -osrt --translate

whisper-cpp 有很丰富的参数:

usage: whisper-cpp [options] file0.wav file1.wav ...

options:
  -h,        --help              [default] show this help message and exit
  -t N,      --threads N         [4      ] number of threads to use during computation
  -p N,      --processors N      [1      ] number of processors to use during computation
  -ot N,     --offset-t N        [0      ] time offset in milliseconds
  -on N,     --offset-n N        [0      ] segment index offset
  -d  N,     --duration N        [0      ] duration of audio to process in milliseconds
  -mc N,     --max-context N     [-1     ] maximum number of text context tokens to store
  -ml N,     --max-len N         [0      ] maximum segment length in characters
  -sow,      --split-on-word     [false  ] split on word rather than on token
  -bo N,     --best-of N         [5      ] number of best candidates to keep
  -bs N,     --beam-size N       [5      ] beam size for beam search
  -wt N,     --word-thold N      [0.01   ] word timestamp probability threshold
  -et N,     --entropy-thold N   [2.40   ] entropy threshold for decoder fail
  -lpt N,    --logprob-thold N   [-1.00  ] log probability threshold for decoder fail
  -debug,    --debug-mode        [false  ] enable debug mode (eg. dump log_mel)
  -tr,       --translate         [false  ] translate from source language to english
  -di,       --diarize           [false  ] stereo audio diarization
  -tdrz,     --tinydiarize       [false  ] enable tinydiarize (requires a tdrz model)
  -nf,       --no-fallback       [false  ] do not use temperature fallback while decoding
  -otxt,     --output-txt        [false  ] output result in a text file
  -ovtt,     --output-vtt        [false  ] output result in a vtt file
  -osrt,     --output-srt        [false  ] output result in a srt file
  -olrc,     --output-lrc        [false  ] output result in a lrc file
  -owts,     --output-words      [false  ] output script for generating karaoke video
  -fp,       --font-path         [/System/Library/Fonts/Supplemental/Courier New Bold.ttf] path to a monospace font for karaoke video
  -ocsv,     --output-csv        [false  ] output result in a CSV file
  -oj,       --output-json       [false  ] output result in a JSON file
  -ojf,      --output-json-full  [false  ] include more information in the JSON file
  -of FNAME, --output-file FNAME [       ] output file path (without file extension)
  -ps,       --print-special     [false  ] print special tokens
  -pc,       --print-colors      [false  ] print colors
  -pp,       --print-progress    [false  ] print progress
  -nt,       --no-timestamps     [false  ] do not print timestamps
  -l LANG,   --language LANG     [en     ] spoken language ('auto' for auto-detect)
  -dl,       --detect-language   [false  ] exit after automatically detecting language
             --prompt PROMPT     [       ] initial prompt
  -m FNAME,  --model FNAME       [models/ggml-base.en.bin] model path
  -f FNAME,  --file FNAME        [       ] input WAV file path
  -oved D,   --ov-e-device DNAME [CPU    ] the OpenVINO device used for encode inference
  -ls,       --log-score         [false  ] log best decoder scores of tokens
  -ng,       --no-gpu            [false  ] disable GPU

处理音频流

音频文件不能覆盖所有场景。如果想要在看各种网页或者视频的时候有一个「同声翻译」,或者是在开会的时候有「实时转录」,就涉及到处理音频流了。

把 VB-Cable 设置成输出之后,我们的所有音频就会转发到这个设备上(如果你同时还想听到,可以再甚至个输入)。然后编译 whisper-cpp 提供的 stream 进行监听:

brew install sdl2
make stream
./stream -m models/ggml-large-v3-q5_0.bin -t 8 --step 5000 --length 5000 -l zh

这里因为指定了输出语言是中文,所以如果你播放的是其他语言的内容,whisper-cpp 会尝试进行翻译:虽然效果一般,但是就像 YouTube 生成的自动字幕一样,能够帮助你大概看明白了。

TODO

从音频转文字之后,还可以做一些额外的处理,比如把一个会议的内容交给模型做提纯做归纳总结等等。

相信在各个活菩萨公司开源的大模型的帮助下,端侧的更多场景会从可玩过渡到可用。

文学有什么用?

上回聊《小王子》,跟蒙爷坦白我能力不够,没法给他讲明白。但我俩成功地把问题收敛到了,「我就爱看科学看赛车,文学有啥用」,约好这周交卷。

和去骑会儿车出身汗,或者琢磨力热声光电相比,读文学作品让你觉得索然无味。

这个现象应该是普遍存在的。

今天的教育比较强调技能的习得。你爷爷奶奶那一辈,写诗搞文学还会有很多人仰慕。今天,你可以看到各种调侃「文科生」的段子,「文学青年」好像也变成了个骂人的称呼。

全世界范围内,人文科学都处在低谷。

为什么?

首先也是最根本的原因,是科技改变了人类的精神生活。随便谁都能聊两句宇宙起源的今天,价值空前多元,意义土崩瓦解,不仅「上帝死了」,包括宗教、艺术在内的所有人类曾经觉得有超越感的事物,都被理性主义搞残了。承载着对人性的关怀和探索之重任的文学,随着大势所趋,也在生活中变得可有可无——诺奖给了歌手 虽然鲍勃·迪伦是一位我很喜欢的歌手,他的民谣歌词也确实很有文学性。 被看成是个标志。

其次,科技也改变了人类的现实生活。由算法精心准备的海量信息,将用户的时间切成碎片。世界各地的教育机构都发现,孩子们阅读长文本的能力正在逐步退化

但我想,这或许正好说明文学将迎来它的机会。因为我们中国有句话,叫物极必反。焦虑不安地面对着个人发展、家庭生活、经济危机甚至是战争迷雾的现代人,或许很快就会意识到,对意义的抛弃只会让自己变得更加无依无靠。而人类历史上创造的包括文学在内的所有不可替代的东西,那些使得我们之所以成为人的根本,大都无法单纯用理性去梳理和框定。

那么,文学究竟有什么用?

认识世界

眼见为实的成本很高,无论是金钱还是时间。

但不费什么力气,你就可以在书里请出国王,进入太空,请诸葛亮出山,让伏地魔入土。

是的,你现在看过最大部头的作品,应该是《哈利·波特》。侦探、武侠、儿童、科幻…常被称为是「通俗文学」或者「类型文学」:言下之意,每个类型有自己的套路,且难登大雅之堂。

能感觉到,你对自己「文学名著」看得不够多,会感到有点不好意思。

其实没关系。我也是小学看了外公的金庸套装,开始了书虫生涯。所以上面的「言下之意」,我只愿意同意前面的一半:类型小说确实有自己的套路,但俗不俗,还是得看情节角色是有血有肉还是虚头巴脑,核心目的是表现人性还是满足欲望,而不是只看类型。

并且,人处于还没有被这个世界说服的孩童时期,总是直接表达和满足自己的需求的。类型小说未必俗气,但通常把巧思花在别处,对生活里的那些感受和情绪通常比较直给。因此和文学大师们的作品比起来,是更合适用作启蒙的。

这肯定不是终点。很快你就会发现,好的文学作品,并不刻意制造戏剧性也就是说,它们不专门为了让你感到恐怖、神奇、伤感或兴奋,来搭建故事。汪曾祺、阿城这些中文圈子的顶尖高手,故事总是很淡,很多留白。米兰·昆德拉也说,《唐·吉诃德》好就好在,那种「人在无限大的土地之上一种幸福而无所事事的冒险旅行」的特质。

但不用急,记得我们说过的「先打猎」吗?现在读得浅一点,杂一点有什么呢?有兴趣,愿意读,就很好了。

Quantity has a quality all its own。

认识他人

读书会让我们拥有更好的同理心。

作者都是人,跟你一样,被某位母亲生在某个国家,有自己的饮食习惯,有自己的社会关系。

于是好的作者有两类。

第一类,我称 Ta 们这是我写东西的一个习惯,用「他们」总感觉对不起伟大的女性们,所以都用 「Ta 们」。这不太适用于偏正式的文本,所以你先别学。 为「蜘蛛侠」好了。

蜘蛛侠擅长在巴掌大的一张网上精心布置,努力经营。这张网的背后有时是实际的土地,比如陈忠实的关中,莫言的高密,福克纳的美国南部,巴尔扎克的封建大巴黎;有时是概念的集合,比如汪曾祺的高邮,刘震云的延津,契诃夫的俄国城乡结合部。无论哪种,网中的故事人物,与这个地方,与作者的关系,往往很深刻。你会看到对世界上某时某地某人最真实最透彻的描写,对你理解他人大有好处。

这些人的一部分书,也是《哈利·波特》之后,我会推荐你先下手去翻的。

另一类,我称 Ta 们为「机器猫」。你应该猜到了,「机器猫」可以随时从口袋里掏出个新鲜玩意儿,或者推开「随意门」带你进入另一个世界。

「机器猫」基本在我们书架的右边,可以稍后再看。哈谢克,卡夫卡,博尔赫斯,格雷厄姆·格林,村上春树,这些作者营造的世界丰富而多样,却都很吸引人(这是因为这些世界虽然是虚构的,里面的人却很真实)。

要真正理解它们,需要一定的阅历,所以可以再等等。

另外,有个额外的收益不能不提:无论「蜘蛛侠」还是「机器猫」,都偏爱失败者。因此文学作品里有人恋爱失败,有人经商失败,有人起义失败,有人治国失败,有人突然失败,有人一直失败。

学会接收自己的失败,学会体谅他人的失败,比学习怎么成功,要重要得多。

认识自己

最后,也是最重要的,读书让我们认识自己。

你从小是个喜欢幻想的孩子。上课常走神,各种本子上全是你的漫画作品,躺在床上也经常云游四海。

所以我给你说,你可以多读读唐诗。因为我们的文化强调群体性,强调纪律。古诗是为数不多的,被广泛允许的,很个体很主观很性情的东西我先喜欢李白,后喜欢杜甫,说不定你也能找到几个对脾气的。

我们每个人,都比我们被允许承认或允许表现出来的样子要奇怪得多。

因此,我们常常无法说出我们真正的想法。那些你会爱上的书有个独特的共同点,就是都会有人站出来替你说话。

是的,最好的作者好像比我们自己更了解我们。Ta 们找到最合适的词句来描绘我们内心中那些细碎、脆弱而又不愿意轻易端出来给大家看的独特瞬间:夏天的第一口冰西瓜,在音乐课上怕自己唱歌不好听感受到的焦虑,当朋友告诉我们新业务突飞猛进时那种夹杂着嫉妒的开心…

作家撕掉伪装,推倒围挡,其实是绘制地图,让我们能够安全地、无压力地去找到并正视我们无处安放的那部分自己。

各种学科,包括如经济、法律、新闻、哲学这样的人文学科,都在追求统一的认知和理论当然,不同文化统一的方向和主题可能不一样。比如我们讲究天人合一,西方天是天人是人,人和天有时候互相闹闹脾气。 ,只有文学、电影、游戏、绘画等为数不多的艺术领域,评价标准中仍以创造性和独特性作为重点。

所以我说过,弄明白爱读谁的诗,或者爱看谁的书,就加入了属于自己的部落。

文学,它提供了让你保持思考的独立性的最坚实的堡垒。