add voxtype
This commit is contained in:
92
home/modules/voxtype/default.nix
Normal file
92
home/modules/voxtype/default.nix
Normal file
@@ -0,0 +1,92 @@
|
||||
{
|
||||
config,
|
||||
osConfig,
|
||||
lib,
|
||||
pkgs,
|
||||
pkgs-unstable,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.programs.voxtype;
|
||||
postProcessUnwrapped =
|
||||
pkgs.runCommand "voxtype-post-process-unwrapped"
|
||||
{
|
||||
code = ./post-process.cr;
|
||||
nativeBuildInputs = [
|
||||
pkgs-unstable.crystal
|
||||
];
|
||||
}
|
||||
''
|
||||
mkdir -p $out/bin
|
||||
crystal build $code -o $out/bin/voxtype-post-process
|
||||
'';
|
||||
|
||||
postProcess = pkgs.symlinkJoin {
|
||||
name = "voxtype-post-process";
|
||||
paths = [ postProcessUnwrapped ];
|
||||
nativeBuildInputs = [ pkgs.makeBinaryWrapper ];
|
||||
postBuild = ''
|
||||
wrapProgram $out/bin/voxtype-post-process \
|
||||
--set OLLAMA_PORT ${toString osConfig.services.ollama.port} \
|
||||
--set WALKER_BIN ${lib.getExe config.services.walker.package}
|
||||
'';
|
||||
meta.mainProgram = "voxtype-post-process";
|
||||
};
|
||||
in
|
||||
{
|
||||
options.programs.voxtype = {
|
||||
postProcessing = lib.mkOption {
|
||||
type = lib.types.submodule {
|
||||
options = {
|
||||
enable = lib.mkEnableOption "Enable post-processing of transcriptions";
|
||||
settings = lib.mkOption {
|
||||
type = lib.types.submodule {
|
||||
options = {
|
||||
model = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "The ollama model to use for post-processing";
|
||||
};
|
||||
commonInstructions = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "no quotes, no emojis, no explanations";
|
||||
description = "Instructions to include in every post-processing prompt";
|
||||
};
|
||||
prompts = lib.mkOption {
|
||||
type = lib.types.listOf (
|
||||
lib.types.submodule {
|
||||
options = {
|
||||
title = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "A title for this prompt, used in the selector";
|
||||
};
|
||||
instructions = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Instructions to include in the post-processing prompt, in addition to the common instructions";
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
default = [
|
||||
{
|
||||
title = "Clean up";
|
||||
instructions = "Clean up this dictation. Remove filler words, fix grammar and punctuation. Output ONLY the cleaned text";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
default = { };
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.postProcessing.enable {
|
||||
xdg.configFile."voxtype/post-processing.json".text = builtins.toJSON cfg.postProcessing.settings;
|
||||
programs.voxtype.settings.output.post_process = {
|
||||
command = lib.getExe postProcess;
|
||||
timeout_ms = 5 * 60 * 1000; # 5 minutes
|
||||
};
|
||||
};
|
||||
}
|
||||
54
home/modules/voxtype/post-process.cr
Normal file
54
home/modules/voxtype/post-process.cr
Normal file
@@ -0,0 +1,54 @@
|
||||
require "json"
|
||||
require "http/client"
|
||||
|
||||
struct OllamaResponse
|
||||
include JSON::Serializable
|
||||
|
||||
getter response : String
|
||||
end
|
||||
|
||||
struct Prompt
|
||||
include JSON::Serializable
|
||||
|
||||
getter title : String
|
||||
getter instructions : String
|
||||
end
|
||||
|
||||
struct Config
|
||||
include JSON::Serializable
|
||||
|
||||
getter model : String
|
||||
getter prompts : Array(Prompt)
|
||||
@[JSON::Field(key: "commonInstructions")]
|
||||
getter common_instructions : String
|
||||
end
|
||||
|
||||
config_path = "#{ENV.fetch("XDG_CONFIG_HOME", "~/.config")}/voxtype/post-processing.json"
|
||||
config = File.open(config_path) { |file| Config.from_json(file) }
|
||||
client = HTTP::Client.new("localhost", ENV.fetch("OLLAMA_PORT", "11434").to_i)
|
||||
|
||||
prompt_selection = Process.run(ENV["WALKER_BIN"], ["--dmenu"]) do |process|
|
||||
config.prompts.each do |prompt|
|
||||
process.input.puts prompt.title
|
||||
end
|
||||
|
||||
process.input.close
|
||||
process.output.gets_to_end.chomp
|
||||
end
|
||||
|
||||
instructions = config.prompts.find { |prompt| prompt.title == prompt_selection }.try(&.instructions) || prompt_selection
|
||||
|
||||
payload = {
|
||||
model: config.model,
|
||||
prompt: "#{instructions} - #{config.common_instructions}:\n\n#{STDIN.gets_to_end.chomp}",
|
||||
think: false,
|
||||
stream: false,
|
||||
}
|
||||
|
||||
client.post("/api/generate", body: payload.to_json) do |response|
|
||||
if response.status_code == 200
|
||||
puts OllamaResponse.from_json(response.body_io).response.strip
|
||||
else
|
||||
abort "Ollama API error: #{response.status_code} #{response.body}"
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user