FluidInference

Activity

Stars and mentions · Last 30 days, Oct 6 – Nov 4

GitHub stars321
Mentions21
012243648Oct 6Oct 20Nov 4
UTC days · repositories FluidInference owns4 repositories

Top repositories

FluidInference’s repositories ranked by new forks, as on trending.

Loading

Contributes to

Repositories outside FluidInference’s account where FluidInference opened or reviewed pull requests in the past 365 days.

Who noticed FluidInference

Everyone who starred or forked FluidInference’s repositories since the archive began in 2011.

Notable accounts

Ordered by the stars their own repositories have received.

Biggest fans

Accounts that starred the most of these repositories.

Breakout weeks

Each repository’s best week of new stars, with the release published around it.

Mentions

21posts
Nov 51 post
  1. 日本語音声認識のHaasをCore ML化して、Rustで音声入力アプリを作った きっかけ:HaasをMacで使いたい 以前、音声入力アプリを作ったときは、FluidAudio経由でParakeetを使っていた。Rust側からSwift製の音声認識サービスを呼び出す構成で、モデルの取得や読み込み、推論はFluidAudioに任せていた。 認識したテキストは、そのあとLLMに渡して文章を整えていた。 ただ、ここは少し気になっていた。文章がきれいになる一方で、話した内容の細かいニュアンスまで変わらないか。認識が終わってから、整形を待つ時間もある。エージェントに指示を出したいだけのときは、この一工程が毎回必要なのか、という疑問があった。 今回使いたくなったのが、日本語音声認識モデルのHaas-ja-v1.0。ただ、公式の推論環境はLinuxとNVIDIA GPUを前提にしている。手元のMacで使うには、モデルの実行環境から用意する必要があった。 そこで、HaasをCore ML形式に変換し、Rustから呼び出せる音声認識ライブラリを作った。さらに、そのライブラリを使ってGPUIでmacOSアプリも作った。 Fnキーを押して話し、離すと入力中のアプリに文字が入る。音声ファイルの文字起こしもできる。認識処理はMacの中で動く。 Haasの日本語認識はかなりよく、自分が普段エージェントへ指示を出す用途では、LLMで整形しなくても、認識結果をそのまま渡すだけで十分通じている。話し言葉をきれいな文章へ直す工程を挟まずに済むのは、使っていて大きな違いだった。 今回は、FluidAudio+Parakeetを使っていた構成から何を変えたのかと、モデルを音声入力アプリにつなぐまでの話を書いていく。 Core MLに変換したら、それで終わりではなかった Haasは、音声を一度渡したら文章がそのまま出てくる、という単純な構成ではない。 まず、音声を特徴量に変換してエンコーダーへ渡す。その出力と、それまでに認識したトークンの状態を使って、デコーダーが次のトークンを決める。この処理を繰り返して文章にしていく。 HaasではFastConformerエンコーダーとTDTデコーダーを組み合わせ、予測ネットワークにKimi Delta Attentionを使っている。構成の詳細は公式モデルカードにまとまっている。 Core MLへの変換にはPythonのcoremltoolsを使った。エンコーダーの重みにはINT8量子化を使い、変換済みモデルをHugging Faceで配布している。 huggingface.co ただ、変換済みモデルを読み込めるようになっても、まだアプリから使える状態にはならない。音声の前処理、テンソルの受け渡し、デコーダーの状態更新、トークンから文字列への変換が必要になる。 以前は、このあたりをFluidAudio側に任せていた。今回はHaas向けの処理をRustで実装し、アプリから使うためのライブラリにまとめた。 全体の流れはこうなる。 マイク・音声ファイル → モノラル化・リサンプリング → 音声特徴量 → Core MLのHaasモデル → Rustでデコード・結果の結合 → GPUIの画面・入力先アプリ Core MLを使う点は以前と同じ。変わったのは、ParakeetからHaasへモデルを替えたことと、モデルを制御する部分をRust側に持ったことだ。 実行設定は、エンコーダーにCPUとApple Neural Engineを許可し、デコーダーにはCPUを指定している。実際にどの演算をどこで実行するかは、この設定の範囲でCore MLが決める。 speech.cppのHaasと比べる HaasをMacで動かす方法は、Core MLだけではない。speech.cppにもHaasの実装があり、GGUF形式の量子化モデルをMetalで動かせる。 では、Core ML版にすると何が変わるのか。同じHaas-ja-v1.0を使い、手元のMacで比較した。 測定日は2026年11月3日。条件は次の通り。 Apple M3、メモリ16GB、macOS 26.6.2 FLEURSの日本語testから、15秒以内の479音声、合計約91分。開発中に使った6音声は除外 同じ16kHz・モノラル音声をメモリへ読み込み、発話ごとに認識。VAD、辞書、LLM整形は使わない モデル読み込み・ウォームアップ・ファイルI/Oを除き、前処理からテキスト生成までを計測 実行順を反転して2回測定。表の処理時間は2回の平均。プロセス優先度はnice 10 構成 処理時間 RTFx CER モデル等の容量 Core ML・15秒エンコーダー 29.16秒 187× 3.982% 623MB Core ML・30.72秒エンコーダー 56.91秒 96× 3.987% 634MB speech.cpp・Q4_K 75.05秒 73× 4.180% 352MB speech.cpp・Q8_0 90.69秒 60× 3.973% 656MB RTFxは音声の長さを処理時間で割った値で、大きいほど速い。容量はモデルと必要なアセットの非圧縮サイズで、使用メモリではない。 Core ML側はINT8重み・FP16演算のエンコーダーと、FP32の分離デコーダーを使用。エンコーダーにはCPU+ANEを許可し、デコーダーはCPUを指定した。speech.cppは0.10.1で、MetalのMTL0とCPU 4スレッドを使用した。 CERは文字単位の誤り率で、小さいほどよい。正解と認識結果をNFKCで正規化し、英字を小文字化、句読点・記号・空白・制御文字を除いて計算した。数字と漢数字、かなと漢字の表記揺れは同一視していない。 この条件では、15秒エンコーダーのCore ML版はQ4_Kより約2.57倍、Q8_0より約3.11倍速かった。Q8_0とのCER差は約0.009ポイントで、479音声全体の文字編集数では2文字分。認識精度はほぼ同じだった。 15秒と30.72秒は、Core MLエンコーダーが一度に受け付ける入力枠の違いだ。この表は全音声が15秒以内なので、長い文脈を必要とする録音での精度差は含まない。短い入力を繰り返す今回の条件では、15秒エンコーダーの方が速かった。 通常のプロセス優先度(nice 0)でも、先頭96音声を順序反転して2回測った。この場合の15秒Core ML版とQ4_Kの速度差は約2.00倍だった。倍率は実行条件で変わるが、どちらの測定でもCore ML版の方が短時間で処理できた。 一方で、容量はQ4_Kが小さい。Core ML版がすべての面で有利という結果ではなく、今回は速度とQ8_0に近い精度を両立できた、という読み方になる。モデルの精度形式や入力形状も異なるため、RustとC++という言語だけの比較でもない。 モデルのパスを渡すところから始めたくない ライブラリを使うたびに、モデルを手でダウンロードして、ファイルを展開して、パスを調べて……という手順があると、組み込む前に面倒になる。 ここはFluidAudioのように、モデルのダウンロードとキャッシュまでライブラリで扱う形にした。 Rustから短いWAVファイルを認識するなら、次のように書ける。入力は16kHz・モノラルで、読み込んだエンコーダーの入力範囲内に収まる音声を使う。 cargo add mozu-audio@0.3.0 use std::path::{Path, PathBuf}; use mozu_audio::{Cancellation, ComputeConfig, models::ModelCache}; fn transcribe_wav( cache_dir: PathBuf, audio_file: &Path, ) -> mozu_audio::Result<String> { let cancellation = Cancellation::new(); let cache = ModelCache::new(cache_dir); let files = cache.prepare_haas(&cancellation, |_| {})?; let engine = files.load(ComputeConfig::standard())?; let result = engine.transcribe_wav(audio_file, &cancellation)?; Ok(result.text) } 初回は必要なモデルを取得し、以後は検証済みのキャッシュを使う。利用するアプリ側でモデル変換をする必要はない。 GUIアプリでは、モデルを専用のワーカースレッドで保持している。音声入力を始めるたびに読み込み直さず、そのワーカーへ音声を渡す。画面の描画と認識処理も、ここで分けている。 長い音声は、どこで区切るかが大事 短い音声を認識できるようになったら、次は長い音声をどう扱うか。 エンコーダーの入力枠に合わせて機械的に切ると、単語や文の途中が境界になる。前後の文脈が切れるので、各区間を認識して文字列をつなぐだけではうまくいかない。 そこで、ファイルの文字起こしでは静かな位置を使って区間を分ける。逐次認識では、前後の音声が重なる窓を作り、音声が増えるたびに認識し直す。発話区間の検出にはSilero VADを使っている。 この逐次認識は、到着済みの音声をオフラインモデルで繰り返し認識する方式だ。後から音声が加わると文脈も変わるので、途中の認識結果は書き換わることがある。 これをそのまま全部画面へ流すと、読んでいる文章が何度も入れ替わってしまう。 文字起こし画面では、確定した本文と、まだ変わる可能性のある暫定部分を分けた。更新するのは暫定部分で、確定済みの本文は残す。 一方、Fnキーで使う音声入力は、話している途中の文章を読む必要があまりない。録音中は小さな波形を表示し、停止したら結果を入力先へ渡す操作にした。 同じ認識処理でも、文字起こしと音声入力では見せ方を変えている。 UIもRustで書く 画面には、Zedでも使われているGPUIを使った。 音声認識ライブラリとGUIアプリは別リポジトリに分けている。認識処理だけ使いたければ、GPUIアプリを経由する必要はない。CLIや別のアプリにも組み込める。 アプリはサイドバーと本文という構成にして、音声入力の履歴、文字起こし、辞書、モデル管理を行き来できるようにした。履歴と辞書の保存にはSQLiteを使っている。 見た目は、macOSのマテリアル表現に寄せた。RustからAppKitのNSVisualEffectViewを呼び出し、ネイティブのマテリアルの上にGPUIのUIを重ねている。 話し始めるときに、入力先を覚えておく 音声入力は、Fnキーの長押しで録音し、離すと停止する。短く押して開始・停止を切り替える操作にも対応している。 ここで必要になるのが、認識結果をどこへ渡すかという処理。 録音を始めたときのアプリやフォーカスを記録しておき、認識後に入力先を確認して貼り付ける。結果は履歴にも保存するので、あとからコピーすることもできる。 macOSのマイクとアクセシビリティの許可は設定画面から確認できるようにした。 固有名詞は辞書に入れる 音声入力で使いたいのは普通の日本語だけではない。プロジェクト名や技術用語も、そのまま入力したい。 辞書には、出したい表記と読みを登録できる。たとえば「Haas」と「はーす」のように対応付ける。仕事や開発でよく使う言葉を登録しておけば、毎回同じ表記を直す手間を減らせる。 文字起こしでは、ファイルに加えてマイクからの録音にも対応した。マイクとシステム音声を一緒に取り込む経路も用意している。 LLMは、用途に合わせて文章を変えるときに使いたい 一方で、LLMを使いたい場面はある。 たとえば、話した内容を決まったスニペットの形式にまとめたり、そのまま相手へ送れるメール文面に校正したりする場面。GranolaのRecipesのように、保存しておいた指示を使って、メモから用途に合った文章を作る使い方も面白い。 エージェントへの指示は、Haasの認識結果をそのまま渡す。人に送る文章を作りたいときは、目的に合った形へLLMで変換する。この辺りは、必要なものから少しずつ試していきたい。 公開したもの 今回作ったものは、Core ML形式のHaasモデル、Rustの音声認識ライブラリ、それを使うmacOSアプリの3つ。 Haas-ja-v1.0のCore ML版 Rustの音声認識ライブラリ GPUI製のmacOSアプリ 以前のFluidAudio+Parakeetの構成から、今回はHaasをMac上で動かすところから取り組んだ。モデルを変換する部分と、アプリから使う部分を分けているので、HaasをRustのアプリへ組み込みたい場合は、ライブラリだけでも使ってもらえると思う。

  2. The new 18M / 7M / 2M Pocket TTS models now run on coreml in FluidAudio, open source, with the flow model on ANE. M5 Pro: 18M at 24 rtfx, 2M at 51 rtfx, TTFT ~25 ms after, under 110 MB of memory. macOS 15 / iOS 18. Model: huggingface.co Code: FluidInference/FluidAudio Great work @kyutai_labs 🙏

    28 likes · 3 reposts · 955 views
  3. Reddit · · r/BestGitHubRepos · u/company_url_finder · FluidInference/FluidAudio

    FluidAudio: Frontier CoreML audio models in your apps: text-to-speech, speech-to-text, voice activity detection, and speaker diarization. In Swift, powered by SOTA open source. (3.1k stars) What it does All text below is quoted directly from the project README. >FluidAudio is a Swift SDK for fully local, low-latency audio AI on Apple devices, with inference offloaded to the Apple Neural Engine (ANE), resulting in less memory and generally faster inference. >The SDK includes state-of-the-art speaker diarization, transcription, and voice activity detection via open-source models (MIT/Apache 2.0) that can be integrated with just a few lines of code. Models are optimized for background processing, ambient computing and always on workloads by running inference on the ANE, minimizing CPU usage and avoiding GPU/MPS entirely. Highlights: - Automatic Speech Recognition (ASR): Parakeet TDT v3 (0.6b) and other TDT/CTC models for batch transcription supporting 25 European languages and Japanese, plus SenseVoice and Paraformer for Mandarin Chinese; Parakeet EOU (120m) for streaming ASR with end-of-utterance detection (English only). - Text-to-Speech (TTS): Kokoro (82m) for parallel synthesis with SSML and pronunciation control across 9 languages (EN, ES, FR, HI, IT, JA, PT, ZH); PocketTTS for streaming TTS with voice cloning support (EN, DE, ES, FR, IT, PT, 6L and 24L variants); Chatterbox Multilingual (520M, 18 languages) and Chatterbox Nano (110M, English with [laugh]/[chuckle] paralinguistic tags) in beta; Paradee (8M Kokoro distill, English, 12 MB) in beta - Speaker Diarization (Online + Offline): Speaker separation and identification across audio streams. Streaming pipeline for real-time processing and offline batch pipeline with advanced clustering. - Speaker Embedding Extraction: Generate speaker embeddings for voice comparison and clustering, you can use this for speaker identification - Voice Activity Detection (VAD): Voice activity detection with Silero models - Speech Enhancement (AEC + Noise Suppression): LocalVQE (4.8M) removes loudspeaker echo, noise and reverb from 16 kHz mic audio given a far-end reference; streaming with 16 ms latency (beta) - Apple Neural Engine: Models run efficiently on Apple's ANE for maximum performance with minimal power consumption - Open-Source Models: All models are publicly available on HuggingFace, converted and optimized by our team; permissive licenses. >Add FluidAudio to your project using Swift Package Manager. Repository FluidInference/FluidAudio Repository stats |Metric|Value| |:-|:-| |Stars|3,079| |Forks|472| |Last release|v0.17.7 (2026-10-08)| |Languages|Swift 97.6%, Python 1.1%| |Contributors|122| |AI contributor accounts (Claude / Codex / Cursor / Copilot)|claude (22 commits), Copilot (3)| |AI co-authored commits|Claude: 23, Copilot: 3| Main contributor |Field|Value| |:-|:-| |Name|A W| |GitHub|@Alex-Wengg| |Commits to this repo|403 (top contributor)| |Bio|AI Researcher| |X / Twitter|@Alex_tra_memory| |Followers|86|

    31 points · 2 comments
  4. Inspired by Shahir's demo, FluidAudio Phonon 2 coreml transcribing an hour of audio in 5.6 s and a full 24 hours in 2 min 19 s on a M5 Pro. Phonon-2 Core ML 1 hour rtfx went from 480× → 644×. test-clean wer the same while 150 -> 195 rtfx FluidInference/FluidAudio huggingface.co

    48 likes · 6 reposts · 2,024 views
  5. How I benchmarked on-device speech-to-text on Apple silicon (Whisper vs Parakeet) --- title: How I benchmarked on-device speech-to-text on Apple silicon (Whisper vs Parakeet) published: true tags: swift, machinelearning, macos, opensource --- I build Plainsay, an open-source dictation app for the Mac. You hold a key, speak, release, and the text is pasted at your cursor. It can run two speech engines entirely on the Mac: OpenAI's Whisper large-v3-turbo through WhisperKit, and NVIDIA's Parakeet TDT 0.6B v3 through FluidAudio. Both run on Core ML. When I had to choose a default, I found plenty of claims about which model is "faster" or "more accurate", and very few measurements I could rerun. So I wrote a small harness, committed the audio and the results, and wrote down what it does and doesn't show. Here's how it works and what I learned from reading the errors one by one. What I wanted to measure Two things matter for dictation: 1. Accuracy, as word error rate (WER): substitutions + deletions + insertions, divided by the number of words in the reference. 2. Latency: how long after you stop talking until the text is ready. In push-to-talk dictation you transcribe the whole clip when the key is released, so that wait is what you feel. I deliberately did not benchmark other dictation apps. Driving someone else's proprietary app in an unattended script isn't something I can do fairly, and I didn't want to republish other vendors' numbers I couldn't reproduce. This measures my own two engines, with enough detail that anyone can check it. The dataset: a small, disclosed sample of LibriSpeech I used LibriSpeech test-clean (CC BY 4.0), downloaded from OpenSLR and checked against its published MD5. The full set has 2,620 utterances from 40 speakers. I used a 50-utterance stratified sample: 10 speakers spread evenly through the sorted speaker list (every 4th), and 5 utterances spread across each speaker's first chapter. That's 1,002 reference words and about 356 seconds of audio. It's small enough that I can read every hypothesis by hand, and it spans 10 different voices. It's also small enough that one or two words move the WER by 0.1 to 0.2 points, which matters later. The 50 FLAC files and their reference transcripts are committed to the repo, so the benchmark runs without downloading the 346 MB archive. The harness The harness is a ~240-line Swift command-line target, Sources/BenchmarkCLI/main.swift. The design choices that matter: - Same engine code as the app. It calls WhisperKitEngine and ParakeetEngine from the app's core module directly, not a reimplementation. Dependencies were pinned (WhisperKit 1.1.0, FluidAudio 0.15.6). - Same audio format as the microphone path. Each FLAC is decoded with AVAudioFile and resampled with AVAudioConverter to 16 kHz mono Float32, which is what the app's recorder produces. All clips are decoded up front, so file I/O isn't timed. - Only transcription is timed. The clock wraps transcribe(samples:prompt:) after the engine has been prepared. Model download and Core ML preparation are outside the timed region. - No hidden warm-up. The first timed clip is the first inference after prepare(), and the same model instance is reused for all 50 clips. I'd rather include the slow first call than quietly drop it. - No prompt. Both engines run with an empty vocabulary prompt. - Simple normalization. Before scoring, both the reference and the hypothesis are lowercased, punctuation except apostrophes is stripped, and whitespace is collapsed. LibriSpeech references are bare uppercase words, and Whisper outputs capitalized, punctuated text, so without this you'd count formatting as errors. - WER is a plain Levenshtein alignment over words. It writes a JSON file with every reference, hypothesis and per-clip latency. Results Run on 2026-08-22, MacBook Air (M4, 10-core CPU, 16 GB), macOS 26.5.1: | Engine | WER | Avg latency | Real-time factor | |---|---:|---:|---:| | Parakeet TDT 0.6B v3 | 2.50% (25 / 1,002) | 0.10 s | 0.014 | | Whisper large-v3-turbo | 2.89% (29 / 1,002) | 0.68 s | 0.095 | Neither engine failed on any clip. The latency gap is the clear result. From the per-clip data, Parakeet's median clip took 0.088 s and its slowest 0.19 s. Whisper's median was 0.64 s and its slowest 1.04 s. The first inference after preparation was 0.13 s for Parakeet and 0.93 s for Whisper, so the cold first call matters a lot more for Whisper. For push-to-talk, Parakeet's result is effectively instant. Whisper's is a short but noticeable pause. The accuracy gap is not a clear result, and reading the errors shows why. Reading the errors With per-clip hypotheses committed, you can see what each counted "error" actually was. A good share of them aren't recognition mistakes: - British vs American spelling, in both directions. Some references use British spelling (HONOUR, ENQUIRE) and both engines wrote "honor" and "inquire". Other references use American spelling (COLOR, CHECK) and Parakeet wrote "colour" and "cheque". Each counts as a full word error. - Abbreviations. Whisper wrote "St. Francis" for SAINT FRANCIS, and "Mr Watson" for MISTER WATSON. - Quotation marks. On two clips Whisper produced nested quotes ("'We wish to talk with him,' answered Kenneth. "'Talk!'). My normalizer keeps apostrophes so "don't" stays one word, which means 'we and him' no longer match the reference. The clip above accounts for 4 of Whisper's 29 errors, and quote artifacts cost it 6 in total. - Rare proper nouns. "Margolotte" became "Margolot", "Donnithorne" became "donnythorne" (Whisper) or "Donny Thorne" (Parakeet, two errors), and "Silvia" became "Sylvia" in both engines. There are real mistakes too. Both engines heard BOOKKEEPER as "bit keeper", and Whisper turned the French word BADAUDERIE into "Bad-Dot-Grey". The takeaway: on clean read speech, the 0.39-point WER difference between these engines is about the same size as the normalization noise. An earlier committed run (Aug 17) had Parakeet at 23 errors instead of 25 on the same clips. Before you conclude one model is more accurate, look at what the errors are. A more complete normalizer (spelling variants, abbreviations, edge apostrophes, like Whisper's English text normalizer) would shrink both numbers. I haven't committed that yet, so I'm not quoting a re-scored figure. What this benchmark doesn't tell you - It's English only. LibriSpeech test-clean says nothing about Polish, German or any other language. Parakeet v3's multilingual coverage and Whisper's language breadth are separate, unmeasured claims. - It's clean audiobook narration. Real dictation means a laptop mic, a room, hesitations, "no wait, I mean". WER will be higher for both engines. - It skips the capture path. Clips are decoded from files, so microphone behavior and voice-activity handling aren't tested. - It's one machine. An M4 MacBook Air. Older M1 machines will be slower, especially for Whisper. - It's a snapshot. The app has since moved to FluidAudio 0.15.8, which fixed dropped endings on some long recordings. Long dictations aren't in this sample at all, since LibriSpeech clips are short. Why Parakeet ended up the recommended default For push-to-talk dictation in English, latency decides a lot: a tenth of a second against two-thirds of a second, on clips of a few seconds. Accuracy on this sample is a tie within noise. Whisper is still there for the languages and accents where it does better, and because some people simply prefer its punctuation style. Run it yourself git clone conrader/plainsay cd plainsay git checkout 2bc1552b19a5ae4094bd81714461baf4ebaa7202 swift build --product BenchmarkCLI .build/debug/BenchmarkCLI Benchmark/data/librispeech-test-clean-manifest.json It prints per-clip progress, then WER, latency and real-time factor per engine, and writes results.json next to the manifest. The full method is in BENCHMARK.md, and the committed results are in Benchmark/data/. If you run it on a different Mac, I'd like to see the numbers, especially from M1/M2 machines. Open an issue or a discussion on the repo. Pull requests that add a better normalizer or a noisier test set are welcome.

    1 reaction · 1 comment
  6. Decision 3.0 now on Core ML 🍎 d3-lite triaging 1,000 pull requests into vllm-sr workgroups, live on an M5 Pro: 0.12 s per PR, 8.3 PRs/s, nothing leaves the Mac ⚡ lite, nano and mini are all converted and in one repo 👇 🤗 huggingface.co 🛠️ FluidInference/FluidUse t.co

    61 likes · 9 reposts · 3,218 views
  7. We distilled clef-flash into a 0.6B model and supporting ANE option. 1,000 support tickets triaged on a M5 pro in 57 s: team, urgency and refund for each, 48 ms per ticket. Within a few points of the 9B on classification. 🤗 huggingface.co 💻 FluidInference/FluidUse t.co

    68 likes · 4 reposts · 2,593 views
  8. We got EmbeddingGemma 2 running 100% on the Apple Neural Engine 🍎 M5 Pro 10,080 posts sorted into topics live, ~620/s on a MacBook, then any topic splits into subtopics in under a second. Fully on-device. 🤗 huggingface.co 💻 FluidInference/FluidUse t.co

    76 likes · 6 reposts · 2,712 views

Achievements

Awards earned by the repositories FluidInference owns. Select an award to embed its badge.

No awards yet

Repositories earn awards by reaching the top three in a completed trending day or week.

A repository earns an award for finishing first, second or third in a completed trending day or week, ranked by new stars, new forks or pull request authors. Awards follow a repository through renames and transfers and count toward its current owner. Weeks run Monday to Sunday, UTC.