{ config, ... }: let homeModules = config.flake.modules.homeManager; in { flake.modules.homeManager.transcription = { config, lib, pkgs, ... }: let modelName = "large-v3-turbo-q5_0"; modelHash = "sha256-OUIhcJzVrR9AxG5gMcphvOiJMebgiMGIKUxtWlX/p+I="; modelSha256 = builtins.convertHash { hash = modelHash; toHashFormat = "base16"; }; diarizationModelName = "pyannote/speaker-diarization-community-1"; diarizationModelRevision = "3533c8cf8e369892e6b79ff1bf80f7b0286a54ee"; diarizationModel = "${config.xdg.dataHome}/transcribe-recordings/speaker-diarization-community-1"; model = pkgs.fetchurl { name = "ggml-${modelName}.bin"; url = "https://huggingface.co/ggerganov/whisper.cpp/resolve/98aa99a0a9db05ae2342309f5096248665f7cba3/ggml-${modelName}.bin"; hash = modelHash; }; diarizationPython = pkgs.python3.withPackages (pythonPackages: [ pythonPackages.pyannote-audio ]); diarizeTranscript = pkgs.writeTextFile { name = "diarize-transcript"; destination = "/bin/diarize-transcript"; executable = true; text = '' #!${diarizationPython}/bin/python3 ${builtins.readFile ./_diarize-transcript.py} ''; }; prepareDiarizationModel = pkgs.writeShellApplication { name = "prepare-transcription-diarization-model"; runtimeInputs = with pkgs; [ coreutils python3Packages.huggingface-hub ]; text = '' model_dir=${lib.escapeShellArg diarizationModel} if [[ -f "$model_dir/.complete" ]]; then printf 'Speaker diarization model is already installed at %s\n' "$model_dir" exit 0 fi printf 'Accept the model terms at https://huggingface.co/${diarizationModelName}\n' if ! hf auth whoami >/dev/null 2>&1; then hf auth login fi mkdir -p "$model_dir" hf download \ ${lib.escapeShellArg diarizationModelName} \ --revision ${lib.escapeShellArg diarizationModelRevision} \ --local-dir "$model_dir" touch "$model_dir/.complete" printf 'Installed speaker diarization model at %s\n' "$model_dir" ''; }; transcribeRecordings = pkgs.writeShellApplication { name = "transcribe-recordings"; runtimeInputs = with pkgs; [ coreutils diarizeTranscript ffmpeg findutils whisper-cpp-vulkan ]; text = builtins.readFile ./_transcribe-recordings.sh; }; in { home.packages = with pkgs; [ ffmpeg prepareDiarizationModel whisper-cpp-vulkan ]; systemd.user.services.transcribe-recordings = { Unit.Description = "Transcribe synchronized recordings with whisper.cpp"; Service = { Type = "oneshot"; ExecStart = lib.getExe transcribeRecordings; Environment = [ "TRANSCRIBE_ENGINE_VERSION=${pkgs.whisper-cpp-vulkan.version}" "TRANSCRIBE_MODEL=${model}" ''"TRANSCRIBE_MODEL_NAME=${modelName} multilingual"'' "TRANSCRIBE_MODEL_SHA256=${modelSha256}" "TRANSCRIBE_DIARIZATION_ENGINE_VERSION=${pkgs.python3Packages.pyannote-audio.version}" "TRANSCRIBE_DIARIZATION_MODEL=${diarizationModel}" "TRANSCRIBE_DIARIZATION_MODEL_NAME=${diarizationModelName}" "TRANSCRIBE_DIARIZATION_MODEL_REVISION=${diarizationModelRevision}" "TRANSCRIBE_SYNC_ROOT=${config.home.homeDirectory}/sync" ]; }; }; systemd.user.timers.transcribe-recordings = { Unit.Description = "Transcribe new recordings every two minutes"; Timer = { OnCalendar = "*:0/2"; Persistent = true; }; Install.WantedBy = [ "timers.target" ]; }; }; flake.modules.nixos.transcription = { ... }: { home-manager.sharedModules = [ homeModules.transcription ]; }; }