Browse Source

feat: persistent voice commands execution log and robust ZWNJ-tolerant Antigravity matcher

main
Ali Alavi 14 hours ago
parent
commit
f7bfa5b2f5
  1. 1
      src/AppDelegate.swift
  2. 32
      src/StatusBarController.swift
  3. 678
      src/VoiceCommandExecutor.swift
  4. 119
      src/VoiceCommandLogger.swift

1
src/AppDelegate.swift

@ -131,6 +131,7 @@ public final class AppDelegate: NSObject, NSApplicationDelegate {
// 2. Normal dictation processing & paste
let processed = TextProcessor.shared.process(text: trimmed)
if !processed.isEmpty {
VoiceCommandLogger.shared.logDictation(rawSpeech: trimmed, processed: processed)
HistoryManager.shared.addEntry(processed)
self.pasteTextToFrontmostApp(text: processed)
}

32
src/StatusBarController.swift

@ -208,6 +208,20 @@ public final class StatusBarController: NSObject, NSMenuDelegate {
cheatSheetItem.target = self
advancedMenu.addItem(cheatSheetItem)
advancedMenu.addItem(NSMenuItem.separator())
let viewLogItem = NSMenuItem(title: "📜 View Voice Commands Log...", action: #selector(viewVoiceLogAction), keyEquivalent: "")
viewLogItem.target = self
advancedMenu.addItem(viewLogItem)
let openFolderItem = NSMenuItem(title: "📁 Open Logs Folder...", action: #selector(openLogFolderAction), keyEquivalent: "")
openFolderItem.target = self
advancedMenu.addItem(openFolderItem)
let clearLogItem = NSMenuItem(title: "🗑️ Clear Voice Commands Log", action: #selector(clearVoiceLogAction), keyEquivalent: "")
clearLogItem.target = self
advancedMenu.addItem(clearLogItem)
let advancedMenuItem = NSMenuItem(title: "🛠️ Advanced Options", action: nil, keyEquivalent: "")
advancedMenuItem.submenu = advancedMenu
menu.addItem(advancedMenuItem)
@ -475,6 +489,24 @@ public final class StatusBarController: NSObject, NSMenuDelegate {
alert.runModal()
}
@objc private func viewVoiceLogAction() {
VoiceCommandLogger.shared.openLogInViewer()
}
@objc private func openLogFolderAction() {
VoiceCommandLogger.shared.openLogFolder()
}
@objc private func clearVoiceLogAction() {
VoiceCommandLogger.shared.clearLog()
let alert = NSAlert()
alert.messageText = "Voice Log Cleared"
alert.informativeText = "The voice commands debug log has been cleared."
alert.alertStyle = .informational
alert.addButton(withTitle: "OK")
alert.runModal()
}
@objc private func toggleLaunchAtLoginAction(_ sender: NSMenuItem) {
SonioxSettings.shared.launchAtLogin.toggle()
buildMenu()

678
src/VoiceCommandExecutor.swift
File diff suppressed because it is too large
View File

119
src/VoiceCommandLogger.swift

@ -0,0 +1,119 @@
import Foundation
import Cocoa
public final class VoiceCommandLogger {
public static let shared = VoiceCommandLogger()
public let logFileURL: URL
private let queue = DispatchQueue(label: "com.soniox.voicecommandlogger", qos: .utility)
private let dateFormatter: DateFormatter
private init() {
let appSupport = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
let dir = appSupport.appendingPathComponent("SonioxVoice")
try? FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
self.logFileURL = dir.appendingPathComponent("voice_commands.log")
self.dateFormatter = DateFormatter()
self.dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
ensureLogHeader()
}
private func ensureLogHeader() {
if !FileManager.default.fileExists(atPath: logFileURL.path) {
let header = """
================================================================================
Soniox Voice Commands Execution & Debug Log
Log Location: \(logFileURL.path)
Started: \(dateFormatter.string(from: Date()))
================================================================================
"""
try? header.write(to: logFileURL, atomically: true, encoding: .utf8)
}
}
public func logCommand(
rawSpeech: String,
body: String,
normalized: String,
actionCategory: String,
actionDetail: String,
status: String
) {
queue.async {
let timestamp = self.dateFormatter.string(from: Date())
let statusIcon = status.contains("SUCCESS") ? "" : ""
let entry = """
--------------------------------------------------------------------------------
[\(timestamp)] VOICE SLASH COMMAND
🎤 Raw Soniox Speech: "\(rawSpeech)"
Extracted Body: "\(body)"
🔍 Normalized: "\(normalized)"
🏷 Category: \(actionCategory)
🎯 Executed Action: \(actionDetail)
\(statusIcon) Status: \(status)
--------------------------------------------------------------------------------
"""
self.appendToFile(text: entry)
}
}
public func logDictation(
rawSpeech: String,
processed: String
) {
queue.async {
let timestamp = self.dateFormatter.string(from: Date())
let entry = """
--------------------------------------------------------------------------------
[\(timestamp)] VOICE DICTATION (Normal Speech)
🎤 Raw Soniox Speech: "\(rawSpeech)"
📝 Processed Text: "\(processed)"
📋 Destination: Pasted to Frontmost Application
Status: SUCCESS
--------------------------------------------------------------------------------
"""
self.appendToFile(text: entry)
}
}
private func appendToFile(text: String) {
guard let data = text.data(using: .utf8) else { return }
if let fileHandle = try? FileHandle(forWritingTo: logFileURL) {
fileHandle.seekToEndOfFile()
fileHandle.write(data)
try? fileHandle.close()
} else {
try? data.write(to: logFileURL, options: .atomic)
}
}
public func clearLog() {
queue.async {
let timestamp = self.dateFormatter.string(from: Date())
let header = """
================================================================================
Soniox Voice Commands Execution & Debug Log (Cleared)
Reset At: \(timestamp)
================================================================================
"""
try? header.write(to: self.logFileURL, atomically: true, encoding: .utf8)
}
}
public func openLogInViewer() {
// Open log in default text editor or Console
NSWorkspace.shared.open(logFileURL)
}
public func openLogFolder() {
NSWorkspace.shared.activateFileViewerSelecting([logFileURL])
}
}
Loading…
Cancel
Save