continue to clean

This commit is contained in:
Emil Lerch 2025-09-09 13:51:41 -07:00
parent 15df51e243
commit b26d139244
Signed by: lobo
GPG key ID: A7B62D657EF764F8

137
build.zig
View file

@ -6,17 +6,17 @@ pub fn build(b: *std.Build) void {
const vosk_dep = b.dependency("vosk", .{});
// Create a proper build step for model download with caching
// We need to use curl for this as the domain doesn't work with zig TLS
const model_step = ModelDownloadStep.create(b);
// Install the model to the output directory
const install_model = b.addInstallDirectory(.{
.source_dir = b.path("vosk-model-small-en-us-0.15"),
.source_dir = model_step.getOutputPath(),
.install_dir = .bin,
.install_subdir = "vosk-model-small-en-us-0.15",
});
install_model.step.dependOn(&model_step.step);
b.getInstallStep().dependOn(&install_model.step);
const exe = b.addExecutable(.{
.name = "stt",
@ -33,8 +33,6 @@ pub fn build(b: *std.Build) void {
exe.linkSystemLibrary("vosk");
exe.linkSystemLibrary("asound");
b.getInstallStep().dependOn(&install_model.step);
b.installArtifact(exe);
const run_step = b.step("run", "Run the app");
@ -65,6 +63,17 @@ const ModelDownloadStep = struct {
return self;
}
pub fn getOutputPath(self: *ModelDownloadStep) std.Build.LazyPath {
var hasher = std.hash.Wyhash.init(0);
hasher.update("https://alphacephei.com/vosk/models/vosk-model-small-en-us-0.15.zip");
const cache_hash = hasher.final();
var cache_dir_buf: [std.fs.max_path_bytes]u8 = undefined;
const cache_dir = std.fmt.bufPrint(&cache_dir_buf, "{s}/o/{x}/vosk-model-small-en-us-0.15", .{ self.builder.cache_root.path.?, cache_hash }) catch @panic("path too long");
return .{ .cwd_relative = self.builder.allocator.dupe(u8, cache_dir) catch @panic("OOM") };
}
fn make(step: *std.Build.Step, options: std.Build.Step.MakeOptions) anyerror!void {
_ = options;
const self: *ModelDownloadStep = @fieldParentPtr("step", step);
@ -84,37 +93,6 @@ const ModelDownloadStep = struct {
// Check if already cached
if (std.fs.cwd().access(cached_model_dir, .{})) |_| {
// Copy from cached version using stdlib
std.fs.cwd().deleteTree(model_dir) catch {};
std.fs.cwd().makePath(model_dir) catch {};
var cached_dir = std.fs.cwd().openDir(cached_model_dir, .{ .iterate = true }) catch return error.CopyFailed;
defer cached_dir.close();
var target_dir = std.fs.cwd().openDir(model_dir, .{}) catch return error.CopyFailed;
defer target_dir.close();
var iter = cached_dir.iterate();
while (iter.next() catch return error.CopyFailed) |entry| {
switch (entry.kind) {
.file => {
cached_dir.copyFile(entry.name, target_dir, entry.name, .{}) catch return error.CopyFailed;
},
.directory => {
target_dir.makeDir(entry.name) catch {};
var sub_cached = cached_dir.openDir(entry.name, .{ .iterate = true }) catch return error.CopyFailed;
defer sub_cached.close();
var sub_target = target_dir.openDir(entry.name, .{}) catch return error.CopyFailed;
defer sub_target.close();
var sub_iter = sub_cached.iterate();
while (sub_iter.next() catch return error.CopyFailed) |sub_entry| {
if (sub_entry.kind == .file) {
sub_cached.copyFile(sub_entry.name, sub_target, sub_entry.name, .{}) catch return error.CopyFailed;
}
}
},
else => {},
}
}
step.result_cached = true;
return;
} else |_| {}
@ -128,93 +106,22 @@ const ModelDownloadStep = struct {
// Download
const download_result = std.process.Child.run(.{
.allocator = self.builder.allocator,
.argv = &.{ "curl", "-s", "-L", "-o", model_zip, "https://alphacephei.com/vosk/models/vosk-model-small-en-us-0.15.zip" },
.argv = &.{ "curl", "-s", "-o", model_zip, "https://alphacephei.com/vosk/models/vosk-model-small-en-us-0.15.zip" },
}) catch return error.DownloadFailed;
if (download_result.term.Exited != 0) return error.DownloadFailed;
// Extract to cache
const extract_result = std.process.Child.run(.{
.allocator = self.builder.allocator,
.argv = &.{ "unzip", "-o", model_zip, "-d", cache_dir },
}) catch return error.UnzipFailed;
if (extract_result.term.Exited != 0) return error.UnzipFailed;
// Extract to cache using stdlib
var zip_file = std.fs.cwd().openFile(model_zip, .{}) catch return error.UnzipFailed;
defer zip_file.close();
// Copy to working directory using stdlib
std.fs.cwd().deleteTree(model_dir) catch {};
std.fs.cwd().makePath(model_dir) catch {};
var cached_dir = std.fs.cwd().openDir(cached_model_dir, .{ .iterate = true }) catch return error.CopyFailed;
defer cached_dir.close();
var target_dir = std.fs.cwd().openDir(model_dir, .{}) catch return error.CopyFailed;
defer target_dir.close();
var cache_dir_handle = std.fs.cwd().openDir(cache_dir, .{}) catch return error.UnzipFailed;
defer cache_dir_handle.close();
var iter = cached_dir.iterate();
while (iter.next() catch return error.CopyFailed) |entry| {
switch (entry.kind) {
.file => {
cached_dir.copyFile(entry.name, target_dir, entry.name, .{}) catch return error.CopyFailed;
},
.directory => {
target_dir.makeDir(entry.name) catch {};
var sub_cached = cached_dir.openDir(entry.name, .{ .iterate = true }) catch return error.CopyFailed;
defer sub_cached.close();
var sub_target = target_dir.openDir(entry.name, .{}) catch return error.CopyFailed;
defer sub_target.close();
var zip_file_buffer: [4096]u8 = undefined;
var zip_file_reader = zip_file.reader(&zip_file_buffer);
var sub_iter = sub_cached.iterate();
while (sub_iter.next() catch return error.CopyFailed) |sub_entry| {
if (sub_entry.kind == .file) {
sub_cached.copyFile(sub_entry.name, sub_target, sub_entry.name, .{}) catch return error.CopyFailed;
}
}
},
else => {},
}
}
std.zip.extract(cache_dir_handle, &zip_file_reader, .{}) catch return error.UnzipFailed;
step.result_cached = false;
}
};
const ModelInstallStep = struct {
step: std.Build.Step,
builder: *std.Build,
model_step: *std.Build.Step,
pub fn create(builder: *std.Build, model_step: *std.Build.Step) *ModelInstallStep {
const self = builder.allocator.create(ModelInstallStep) catch @panic("OOM");
self.* = .{
.step = std.Build.Step.init(.{
.id = .custom,
.name = "install vosk-model-small-en-us-0.15/",
.owner = builder,
.makeFn = make,
}),
.builder = builder,
.model_step = model_step,
};
self.step.dependOn(model_step);
return self;
}
fn make(step: *std.Build.Step, options: std.Build.Step.MakeOptions) anyerror!void {
_ = options;
const self: *ModelInstallStep = @fieldParentPtr("step", step);
const install_dir = self.builder.getInstallPath(.bin, "vosk-model-small-en-us-0.15");
// Inherit cache status from model step
step.result_cached = self.model_step.result_cached;
if (step.result_cached) return;
// Copy model to install directory
std.fs.cwd().makePath(std.fs.path.dirname(install_dir).?) catch {};
std.fs.cwd().deleteTree(install_dir) catch {};
const copy_result = std.process.Child.run(.{
.allocator = self.builder.allocator,
.argv = &.{ "cp", "-r", "vosk-model-small-en-us-0.15", install_dir },
}) catch return error.CopyFailed;
if (copy_result.term.Exited != 0) return error.CopyFailed;
}
};