chore(swabble): apply swiftformat
This commit is contained in:
@@ -33,5 +33,4 @@ let package = Package(
|
||||
.product(name: "Testing", package: "swift-testing"),
|
||||
]),
|
||||
],
|
||||
swiftLanguageModes: [.v6]
|
||||
)
|
||||
swiftLanguageModes: [.v6])
|
||||
|
||||
@@ -17,11 +17,11 @@ public actor HookRunner {
|
||||
|
||||
public init(config: SwabbleConfig) {
|
||||
self.config = config
|
||||
self.hostname = Host.current().localizedName ?? "host"
|
||||
hostname = Host.current().localizedName ?? "host"
|
||||
}
|
||||
|
||||
public func shouldRun() -> Bool {
|
||||
guard self.config.hook.cooldownSeconds > 0 else { return true }
|
||||
guard config.hook.cooldownSeconds > 0 else { return true }
|
||||
if let lastRun, Date().timeIntervalSince(lastRun) < config.hook.cooldownSeconds {
|
||||
return false
|
||||
}
|
||||
@@ -29,23 +29,23 @@ public actor HookRunner {
|
||||
}
|
||||
|
||||
public func run(job: HookJob) async throws {
|
||||
guard self.shouldRun() else { return }
|
||||
guard !self.config.hook.command.isEmpty else { throw NSError(
|
||||
guard shouldRun() else { return }
|
||||
guard !config.hook.command.isEmpty else { throw NSError(
|
||||
domain: "Hook",
|
||||
code: 1,
|
||||
userInfo: [NSLocalizedDescriptionKey: "hook command not set"]) }
|
||||
|
||||
let prefix = self.config.hook.prefix.replacingOccurrences(of: "${hostname}", with: self.hostname)
|
||||
let prefix = config.hook.prefix.replacingOccurrences(of: "${hostname}", with: hostname)
|
||||
let payload = prefix + job.text
|
||||
|
||||
let process = Process()
|
||||
process.executableURL = URL(fileURLWithPath: self.config.hook.command)
|
||||
process.arguments = self.config.hook.args + [payload]
|
||||
process.executableURL = URL(fileURLWithPath: config.hook.command)
|
||||
process.arguments = config.hook.args + [payload]
|
||||
|
||||
var env = ProcessInfo.processInfo.environment
|
||||
env["SWABBLE_TEXT"] = job.text
|
||||
env["SWABBLE_PREFIX"] = prefix
|
||||
for (k, v) in self.config.hook.env {
|
||||
for (k, v) in config.hook.env {
|
||||
env[k] = v
|
||||
}
|
||||
process.environment = env
|
||||
@@ -70,6 +70,6 @@ public actor HookRunner {
|
||||
try await group.next()
|
||||
group.cancelAll()
|
||||
}
|
||||
self.lastRun = Date()
|
||||
lastRun = Date()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,18 +35,18 @@ public actor SpeechPipeline {
|
||||
transcriptionOptions: etiquette ? [.etiquetteReplacements] : [],
|
||||
reportingOptions: [.volatileResults],
|
||||
attributeOptions: [])
|
||||
self.transcriber = transcriberModule
|
||||
transcriber = transcriberModule
|
||||
|
||||
guard let analyzerFormat = await SpeechAnalyzer.bestAvailableAudioFormat(compatibleWith: [transcriberModule])
|
||||
else {
|
||||
throw SpeechPipelineError.analyzerFormatUnavailable
|
||||
}
|
||||
|
||||
self.analyzer = SpeechAnalyzer(modules: [transcriberModule])
|
||||
analyzer = SpeechAnalyzer(modules: [transcriberModule])
|
||||
let (stream, continuation) = AsyncStream<AnalyzerInput>.makeStream()
|
||||
self.inputContinuation = continuation
|
||||
inputContinuation = continuation
|
||||
|
||||
let inputNode = self.engine.inputNode
|
||||
let inputNode = engine.inputNode
|
||||
let inputFormat = inputNode.outputFormat(forBus: 0)
|
||||
inputNode.removeTap(onBus: 0)
|
||||
inputNode.installTap(onBus: 0, bufferSize: 2048, format: inputFormat) { [weak self] buffer, _ in
|
||||
@@ -55,11 +55,11 @@ public actor SpeechPipeline {
|
||||
Task { await self.handleBuffer(boxed.buffer, targetFormat: analyzerFormat) }
|
||||
}
|
||||
|
||||
self.engine.prepare()
|
||||
try self.engine.start()
|
||||
try await self.analyzer?.start(inputSequence: stream)
|
||||
engine.prepare()
|
||||
try engine.start()
|
||||
try await analyzer?.start(inputSequence: stream)
|
||||
|
||||
guard let transcriberForStream = self.transcriber else {
|
||||
guard let transcriberForStream = transcriber else {
|
||||
throw SpeechPipelineError.transcriberUnavailable
|
||||
}
|
||||
|
||||
@@ -82,18 +82,18 @@ public actor SpeechPipeline {
|
||||
}
|
||||
|
||||
public func stop() async {
|
||||
self.resultTask?.cancel()
|
||||
self.inputContinuation?.finish()
|
||||
self.engine.inputNode.removeTap(onBus: 0)
|
||||
self.engine.stop()
|
||||
try? await self.analyzer?.finalizeAndFinishThroughEndOfInput()
|
||||
resultTask?.cancel()
|
||||
inputContinuation?.finish()
|
||||
engine.inputNode.removeTap(onBus: 0)
|
||||
engine.stop()
|
||||
try? await analyzer?.finalizeAndFinishThroughEndOfInput()
|
||||
}
|
||||
|
||||
private func handleBuffer(_ buffer: AVAudioPCMBuffer, targetFormat: AVAudioFormat) async {
|
||||
do {
|
||||
let converted = try converter.convert(buffer, to: targetFormat)
|
||||
let input = AnalyzerInput(buffer: converted)
|
||||
self.inputContinuation?.yield(input)
|
||||
inputContinuation?.yield(input)
|
||||
} catch {
|
||||
// drop on conversion failure
|
||||
}
|
||||
|
||||
@@ -27,11 +27,11 @@ public struct Logger: Sendable {
|
||||
print("[\(level.rawValue.uppercased())] \(ts) | \(message)")
|
||||
}
|
||||
|
||||
public func trace(_ msg: String) { self.log(.trace, msg) }
|
||||
public func debug(_ msg: String) { self.log(.debug, msg) }
|
||||
public func info(_ msg: String) { self.log(.info, msg) }
|
||||
public func warn(_ msg: String) { self.log(.warn, msg) }
|
||||
public func error(_ msg: String) { self.log(.error, msg) }
|
||||
public func trace(_ msg: String) { log(.trace, msg) }
|
||||
public func debug(_ msg: String) { log(.debug, msg) }
|
||||
public func info(_ msg: String) { log(.info, msg) }
|
||||
public func warn(_ msg: String) { log(.warn, msg) }
|
||||
public func error(_ msg: String) { log(.error, msg) }
|
||||
}
|
||||
|
||||
extension LogLevel {
|
||||
|
||||
@@ -11,24 +11,24 @@ public actor TranscriptsStore {
|
||||
let dir = FileManager.default.homeDirectoryForCurrentUser
|
||||
.appendingPathComponent("Library/Application Support/swabble", isDirectory: true)
|
||||
try? FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
|
||||
self.fileURL = dir.appendingPathComponent("transcripts.log")
|
||||
fileURL = dir.appendingPathComponent("transcripts.log")
|
||||
if let data = try? Data(contentsOf: fileURL),
|
||||
let text = String(data: data, encoding: .utf8)
|
||||
{
|
||||
self.entries = text.split(separator: "\n").map(String.init).suffix(self.limit)
|
||||
entries = text.split(separator: "\n").map(String.init).suffix(limit)
|
||||
}
|
||||
}
|
||||
|
||||
public func append(text: String) {
|
||||
self.entries.append(text)
|
||||
if self.entries.count > self.limit {
|
||||
self.entries.removeFirst(self.entries.count - self.limit)
|
||||
entries.append(text)
|
||||
if entries.count > limit {
|
||||
entries.removeFirst(entries.count - limit)
|
||||
}
|
||||
let body = self.entries.joined(separator: "\n")
|
||||
try? body.write(to: self.fileURL, atomically: false, encoding: .utf8)
|
||||
let body = entries.joined(separator: "\n")
|
||||
try? body.write(to: fileURL, atomically: false, encoding: .utf8)
|
||||
}
|
||||
|
||||
public func latest() -> [String] { self.entries }
|
||||
public func latest() -> [String] { entries }
|
||||
}
|
||||
|
||||
extension String {
|
||||
|
||||
@@ -14,14 +14,14 @@ struct DoctorCommand: ParsableCommand {
|
||||
init() {}
|
||||
init(parsed: ParsedValues) {
|
||||
self.init()
|
||||
if let cfg = parsed.options["config"]?.last { self.configPath = cfg }
|
||||
if let cfg = parsed.options["config"]?.last { configPath = cfg }
|
||||
}
|
||||
|
||||
mutating func run() async throws {
|
||||
let auth = await SFSpeechRecognizer.authorizationStatus()
|
||||
print("Speech auth: \(auth)")
|
||||
do {
|
||||
_ = try ConfigLoader.load(at: self.configURL)
|
||||
_ = try ConfigLoader.load(at: configURL)
|
||||
print("Config: OK")
|
||||
} catch {
|
||||
print("Config missing or invalid; run setup")
|
||||
@@ -33,5 +33,5 @@ struct DoctorCommand: ParsableCommand {
|
||||
print("Mics found: \(session.devices.count)")
|
||||
}
|
||||
|
||||
private var configURL: URL? { self.configPath.map { URL(fileURLWithPath: $0) } }
|
||||
private var configURL: URL? { configPath.map { URL(fileURLWithPath: $0) } }
|
||||
}
|
||||
|
||||
@@ -47,16 +47,16 @@ struct MicSet: ParsableCommand {
|
||||
init() {}
|
||||
init(parsed: ParsedValues) {
|
||||
self.init()
|
||||
if let value = parsed.positional.first, let intVal = Int(value) { self.index = intVal }
|
||||
if let cfg = parsed.options["config"]?.last { self.configPath = cfg }
|
||||
if let value = parsed.positional.first, let intVal = Int(value) { index = intVal }
|
||||
if let cfg = parsed.options["config"]?.last { configPath = cfg }
|
||||
}
|
||||
|
||||
mutating func run() async throws {
|
||||
var cfg = try ConfigLoader.load(at: self.configURL)
|
||||
cfg.audio.deviceIndex = self.index
|
||||
try ConfigLoader.save(cfg, at: self.configURL)
|
||||
print("saved device index \(self.index)")
|
||||
var cfg = try ConfigLoader.load(at: configURL)
|
||||
cfg.audio.deviceIndex = index
|
||||
try ConfigLoader.save(cfg, at: configURL)
|
||||
print("saved device index \(index)")
|
||||
}
|
||||
|
||||
private var configURL: URL? { self.configPath.map { URL(fileURLWithPath: $0) } }
|
||||
private var configURL: URL? { configPath.map { URL(fileURLWithPath: $0) } }
|
||||
}
|
||||
|
||||
@@ -17,19 +17,19 @@ struct ServeCommand: ParsableCommand {
|
||||
|
||||
init(parsed: ParsedValues) {
|
||||
self.init()
|
||||
if parsed.flags.contains("noWake") { self.noWake = true }
|
||||
if let cfg = parsed.options["config"]?.last { self.configPath = cfg }
|
||||
if parsed.flags.contains("noWake") { noWake = true }
|
||||
if let cfg = parsed.options["config"]?.last { configPath = cfg }
|
||||
}
|
||||
|
||||
mutating func run() async throws {
|
||||
var cfg: SwabbleConfig
|
||||
do {
|
||||
cfg = try ConfigLoader.load(at: self.configURL)
|
||||
cfg = try ConfigLoader.load(at: configURL)
|
||||
} catch {
|
||||
cfg = SwabbleConfig()
|
||||
try ConfigLoader.save(cfg, at: self.configURL)
|
||||
try ConfigLoader.save(cfg, at: configURL)
|
||||
}
|
||||
if self.noWake {
|
||||
if noWake {
|
||||
cfg.wake.enabled = false
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ struct ServeCommand: ParsableCommand {
|
||||
}
|
||||
|
||||
private var configURL: URL? {
|
||||
self.configPath.map { URL(fileURLWithPath: $0) }
|
||||
configPath.map { URL(fileURLWithPath: $0) }
|
||||
}
|
||||
|
||||
private static func matchesWake(text: String, cfg: SwabbleConfig) -> Bool {
|
||||
|
||||
@@ -28,11 +28,11 @@ private enum LaunchdHelper {
|
||||
"KeepAlive": true,
|
||||
]
|
||||
let data = try PropertyListSerialization.data(fromPropertyList: plist, format: .xml, options: 0)
|
||||
try data.write(to: self.plistURL)
|
||||
try data.write(to: plistURL)
|
||||
}
|
||||
|
||||
static func removePlist() throws {
|
||||
try? FileManager.default.removeItem(at: self.plistURL)
|
||||
try? FileManager.default.removeItem(at: plistURL)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,14 +13,14 @@ struct SetupCommand: ParsableCommand {
|
||||
init() {}
|
||||
init(parsed: ParsedValues) {
|
||||
self.init()
|
||||
if let cfg = parsed.options["config"]?.last { self.configPath = cfg }
|
||||
if let cfg = parsed.options["config"]?.last { configPath = cfg }
|
||||
}
|
||||
|
||||
mutating func run() async throws {
|
||||
let cfg = SwabbleConfig()
|
||||
try ConfigLoader.save(cfg, at: self.configURL)
|
||||
print("wrote config to \(self.configURL?.path ?? SwabbleConfig.defaultPath.path)")
|
||||
try ConfigLoader.save(cfg, at: configURL)
|
||||
print("wrote config to \(configURL?.path ?? SwabbleConfig.defaultPath.path)")
|
||||
}
|
||||
|
||||
private var configURL: URL? { self.configPath.map { URL(fileURLWithPath: $0) } }
|
||||
private var configURL: URL? { configPath.map { URL(fileURLWithPath: $0) } }
|
||||
}
|
||||
|
||||
@@ -13,11 +13,11 @@ struct StatusCommand: ParsableCommand {
|
||||
init() {}
|
||||
init(parsed: ParsedValues) {
|
||||
self.init()
|
||||
if let cfg = parsed.options["config"]?.last { self.configPath = cfg }
|
||||
if let cfg = parsed.options["config"]?.last { configPath = cfg }
|
||||
}
|
||||
|
||||
mutating func run() async throws {
|
||||
let cfg = try? ConfigLoader.load(at: self.configURL)
|
||||
let cfg = try? ConfigLoader.load(at: configURL)
|
||||
let wake = cfg?.wake.word ?? "clawd"
|
||||
let wakeEnabled = cfg?.wake.enabled ?? false
|
||||
let latest = await TranscriptsStore.shared.latest().suffix(3)
|
||||
@@ -30,5 +30,5 @@ struct StatusCommand: ParsableCommand {
|
||||
}
|
||||
}
|
||||
|
||||
private var configURL: URL? { self.configPath.map { URL(fileURLWithPath: $0) } }
|
||||
private var configURL: URL? { configPath.map { URL(fileURLWithPath: $0) } }
|
||||
}
|
||||
|
||||
@@ -15,16 +15,16 @@ struct TestHookCommand: ParsableCommand {
|
||||
|
||||
init(parsed: ParsedValues) {
|
||||
self.init()
|
||||
if let positional = parsed.positional.first { self.text = positional }
|
||||
if let cfg = parsed.options["config"]?.last { self.configPath = cfg }
|
||||
if let positional = parsed.positional.first { text = positional }
|
||||
if let cfg = parsed.options["config"]?.last { configPath = cfg }
|
||||
}
|
||||
|
||||
mutating func run() async throws {
|
||||
let cfg = try ConfigLoader.load(at: self.configURL)
|
||||
let cfg = try ConfigLoader.load(at: configURL)
|
||||
let runner = HookRunner(config: cfg)
|
||||
try await runner.run(job: HookJob(text: self.text, timestamp: Date()))
|
||||
try await runner.run(job: HookJob(text: text, timestamp: Date()))
|
||||
print("hook invoked")
|
||||
}
|
||||
|
||||
private var configURL: URL? { self.configPath.map { URL(fileURLWithPath: $0) } }
|
||||
private var configURL: URL? { configPath.map { URL(fileURLWithPath: $0) } }
|
||||
}
|
||||
|
||||
@@ -24,12 +24,12 @@ struct TranscribeCommand: ParsableCommand {
|
||||
|
||||
init(parsed: ParsedValues) {
|
||||
self.init()
|
||||
if let positional = parsed.positional.first { self.inputFile = positional }
|
||||
if let loc = parsed.options["locale"]?.last { self.locale = loc }
|
||||
if parsed.flags.contains("censor") { self.censor = true }
|
||||
if let out = parsed.options["output"]?.last { self.outputFile = out }
|
||||
if let fmt = parsed.options["format"]?.last { self.format = fmt }
|
||||
if let len = parsed.options["maxLength"]?.last, let intVal = Int(len) { self.maxLength = intVal }
|
||||
if let positional = parsed.positional.first { inputFile = positional }
|
||||
if let loc = parsed.options["locale"]?.last { locale = loc }
|
||||
if parsed.flags.contains("censor") { censor = true }
|
||||
if let out = parsed.options["output"]?.last { outputFile = out }
|
||||
if let fmt = parsed.options["format"]?.last { format = fmt }
|
||||
if let len = parsed.options["maxLength"]?.last, let intVal = Int(len) { maxLength = intVal }
|
||||
}
|
||||
|
||||
mutating func run() async throws {
|
||||
@@ -51,7 +51,7 @@ struct TranscribeCommand: ParsableCommand {
|
||||
transcript += result.text
|
||||
}
|
||||
|
||||
let output = outputFormat.text(for: transcript, maxLength: self.maxLength)
|
||||
let output = outputFormat.text(for: transcript, maxLength: maxLength)
|
||||
if let path = outputFile {
|
||||
try output.write(to: URL(fileURLWithPath: path), atomically: false, encoding: .utf8)
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user