diff --git a/build.zig b/build.zig index 70814b8..b68a66c 100644 --- a/build.zig +++ b/build.zig @@ -46,9 +46,9 @@ pub fn build(b: *std.Build) void { b.installArtifact(stt_lib); - // Create the demo executable + // Create the executable const exe = b.addExecutable(.{ - .name = "stt-demo", + .name = "stt", .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = target, @@ -114,7 +114,7 @@ pub fn build(b: *std.Build) void { const run_dedicated_unit_tests = b.addRunArtifact(dedicated_unit_tests); - // Creates a step for unit testing the demo application + // Creates a step for unit testing the application const exe_unit_tests = b.addTest(.{ .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), diff --git a/src/main.zig b/src/main.zig index 853495a..8f12195 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,7 +1,4 @@ -//! STT Library Demo Application -//! -//! This demonstrates how to use the STT library for speech recognition -//! with callback-based event handling and proper resource management. +//! STT with callback-based event handling const std = @import("std"); const builtin = @import("builtin"); @@ -11,29 +8,38 @@ const stt = @import("stt.zig"); var should_exit = std.atomic.Value(bool).init(false); /// Demo implementation of speech event handler with comprehensive error handling -const DemoHandler = struct { +const SpeechHandler = struct { speech_count: u32 = 0, error_count: u32 = 0, warning_count: u32 = 0, recoverable_error_count: u32 = 0, + exec_program: ?[]const u8 = null, /// Handle detected speech fn onSpeech(ctx: *anyopaque, text: []const u8) void { if (builtin.is_test) return; // Suppress output during tests - const self: *DemoHandler = @ptrCast(@alignCast(ctx)); + const self: *SpeechHandler = @ptrCast(@alignCast(ctx)); self.speech_count += 1; - // Print with timestamp for better demo experience + // Print with timestamp for better experience const timestamp = std.time.timestamp(); std.debug.print("[{}] Speech #{}: {s}\n", .{ timestamp, self.speech_count, text }); + + // Execute program if specified + if (self.exec_program) |program| { + var child = std.process.Child.init(&[_][]const u8{ program, text }, std.heap.page_allocator); + _ = child.spawn() catch |err| { + std.log.err("Failed to execute program '{s}': {}", .{ program, err }); + }; + } } /// Handle basic errors (fallback for compatibility) fn onError(ctx: *anyopaque, error_code: stt.SttError, message: []const u8) void { if (builtin.is_test) return; // Suppress output during tests - const self: *DemoHandler = @ptrCast(@alignCast(ctx)); + const self: *SpeechHandler = @ptrCast(@alignCast(ctx)); self.error_count += 1; // Print error with timestamp @@ -43,13 +49,13 @@ const DemoHandler = struct { /// Handle detailed errors with comprehensive information fn onDetailedError(ctx: *anyopaque, error_info: stt.SttErrorInfo) void { - const self: *DemoHandler = @ptrCast(@alignCast(ctx)); + const self: *SpeechHandler = @ptrCast(@alignCast(ctx)); logDetail(self, error_info) catch |e| std.log.err("Error writing error {}. Original message: {s}", .{ e, error_info.message }); } - fn logDetail(self: *DemoHandler, error_info: stt.SttErrorInfo) !void { + fn logDetail(self: *SpeechHandler, error_info: stt.SttErrorInfo) !void { const log = std.log.scoped(.stt); // Categorize the error for statistics if (error_info.recoverable) @@ -106,7 +112,7 @@ const DemoHandler = struct { } /// Get comprehensive statistics for summary - fn getStats(self: *const DemoHandler) struct { + fn getStats(self: *const SpeechHandler) struct { speech_count: u32, error_count: u32, warning_count: u32, @@ -156,29 +162,31 @@ pub fn main() !void { }); _ = c.signal(c.SIGINT, signalHandler); - // Create demo handler with statistics tracking - var demo_handler = DemoHandler{}; - const speech_handler = stt.SpeechEventHandler{ - .onSpeechFn = DemoHandler.onSpeech, - .onErrorFn = DemoHandler.onError, - .onDetailedErrorFn = DemoHandler.onDetailedError, - .ctx = &demo_handler, - }; - // Parse command line arguments const args = try std.process.argsAlloc(allocator); defer std.process.argsFree(allocator, args); var model_path: ?[]const u8 = null; + var exec_program: ?[]const u8 = null; - // Parse --model argument + // Parse --model and --exec arguments for (args[1..]) |arg| { if (std.mem.startsWith(u8, arg, "--model=")) { model_path = arg[8..]; // Skip "--model=" - break; + } else if (std.mem.startsWith(u8, arg, "--exec=")) { + exec_program = arg[7..]; // Skip "--exec=" } } + // Create handler with statistics tracking + var handler = SpeechHandler{ .exec_program = exec_program }; + const speech_handler = stt.SpeechEventHandler{ + .onSpeechFn = SpeechHandler.onSpeech, + .onErrorFn = SpeechHandler.onError, + .onDetailedErrorFn = SpeechHandler.onDetailedError, + .ctx = &handler, + }; + // If no model specified, try default locations const default_paths = [_][]const u8{ "vosk-model-small-en-us-0.15", @@ -197,7 +205,7 @@ pub fn main() !void { // Check if model path exists if (model_path == null) { _ = try stderr.writeAll("Error: Vosk model not found.\n\n"); - _ = try stderr.writeAll("Usage: stt-demo [--model=]\n\n"); + _ = try stderr.writeAll("Usage: stt [--model=] [--exec=]\n\n"); _ = try stderr.writeAll("Locations searched:\n"); inline for (default_paths) |path| _ = try stderr.writeAll("\t" ++ path ++ "\n"); @@ -289,8 +297,8 @@ pub fn main() !void { _ = stdout.writeAll("\n----------------------------------------\n") catch {}; _ = stdout.writeAll("Shutdown signal received, stopping...\n") catch {}; - // Get final statistics from demo handler - const stats = demo_handler.getStats(); + // Get final statistics from handler + const stats = handler.getStats(); std.log.info("Demo Session Summary:", .{}); std.log.info(" Speech detections: {}", .{stats.speech_count}); std.log.info(" Fatal errors: {}", .{stats.error_count}); @@ -304,15 +312,15 @@ pub fn main() !void { _ = stdout.writeAll("Session completed successfully.\n") catch {}; } -// Test the demo functionality -test "demo handler functionality" { +// Test the functionality +test "handler functionality" { const testing = std.testing; - var demo_handler = DemoHandler{}; + var handler = SpeechHandler{}; const speech_handler = stt.SpeechEventHandler{ - .onSpeechFn = DemoHandler.onSpeech, - .onErrorFn = DemoHandler.onError, - .ctx = &demo_handler, + .onSpeechFn = SpeechHandler.onSpeech, + .onErrorFn = SpeechHandler.onError, + .ctx = &handler, }; // Test that callbacks can be invoked without crashing