Remove verbose logging from cleanup and capture services
This commit is contained in:
parent
22b727ff97
commit
d1fe77f2aa
@ -19,21 +19,18 @@ class CustomModelManager: ObservableObject {
|
|||||||
func addCustomModel(_ model: CustomCloudModel) {
|
func addCustomModel(_ model: CustomCloudModel) {
|
||||||
customModels.append(model)
|
customModels.append(model)
|
||||||
saveCustomModels()
|
saveCustomModels()
|
||||||
logger.info("Added custom model: \(model.displayName)")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeCustomModel(withId id: UUID) {
|
func removeCustomModel(withId id: UUID) {
|
||||||
customModels.removeAll { $0.id == id }
|
customModels.removeAll { $0.id == id }
|
||||||
saveCustomModels()
|
saveCustomModels()
|
||||||
APIKeyManager.shared.deleteCustomModelAPIKey(forModelId: id)
|
APIKeyManager.shared.deleteCustomModelAPIKey(forModelId: id)
|
||||||
logger.info("Removed custom model with ID: \(id)")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateCustomModel(_ updatedModel: CustomCloudModel) {
|
func updateCustomModel(_ updatedModel: CustomCloudModel) {
|
||||||
if let index = customModels.firstIndex(where: { $0.id == updatedModel.id }) {
|
if let index = customModels.firstIndex(where: { $0.id == updatedModel.id }) {
|
||||||
customModels[index] = updatedModel
|
customModels[index] = updatedModel
|
||||||
saveCustomModels()
|
saveCustomModels()
|
||||||
logger.info("Updated custom model: \(updatedModel.displayName)")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +38,6 @@ class CustomModelManager: ObservableObject {
|
|||||||
|
|
||||||
private func loadCustomModels() {
|
private func loadCustomModels() {
|
||||||
guard let data = userDefaults.data(forKey: customModelsKey) else {
|
guard let data = userDefaults.data(forKey: customModelsKey) else {
|
||||||
logger.info("No custom models found in UserDefaults")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import AppKit
|
import AppKit
|
||||||
import Vision
|
import Vision
|
||||||
import os
|
|
||||||
import ScreenCaptureKit
|
import ScreenCaptureKit
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
@ -9,11 +8,6 @@ class ScreenCaptureService: ObservableObject {
|
|||||||
@Published var isCapturing = false
|
@Published var isCapturing = false
|
||||||
@Published var lastCapturedText: String?
|
@Published var lastCapturedText: String?
|
||||||
|
|
||||||
private let logger = Logger(
|
|
||||||
subsystem: "com.prakashjoshipax.voiceink",
|
|
||||||
category: "aienhancement"
|
|
||||||
)
|
|
||||||
|
|
||||||
private struct WindowCandidate {
|
private struct WindowCandidate {
|
||||||
let title: String
|
let title: String
|
||||||
let ownerName: String
|
let ownerName: String
|
||||||
@ -88,7 +82,6 @@ class ScreenCaptureService: ObservableObject {
|
|||||||
return NSImage(cgImage: cgImage, size: NSSize(width: cgImage.width, height: cgImage.height))
|
return NSImage(cgImage: cgImage, size: NSSize(width: cgImage.width, height: cgImage.height))
|
||||||
|
|
||||||
} catch {
|
} catch {
|
||||||
logger.notice("📸 Screen capture failed: \(error.localizedDescription, privacy: .public)")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -125,8 +118,7 @@ class ScreenCaptureService: ObservableObject {
|
|||||||
switch result {
|
switch result {
|
||||||
case .success(let text):
|
case .success(let text):
|
||||||
return text
|
return text
|
||||||
case .failure(let error):
|
case .failure:
|
||||||
logger.notice("📸 Text recognition failed: \(error.localizedDescription, privacy: .public)")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,11 +136,8 @@ class ScreenCaptureService: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
guard let windowInfo = getActiveWindowInfo() else {
|
guard let windowInfo = getActiveWindowInfo() else {
|
||||||
logger.notice("📸 No active window found")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.notice("📸 Capturing: \(windowInfo.title, privacy: .public) (\(windowInfo.ownerName, privacy: .public))")
|
|
||||||
|
|
||||||
var contextText = """
|
var contextText = """
|
||||||
Active Window: \(windowInfo.title)
|
Active Window: \(windowInfo.title)
|
||||||
@ -161,11 +150,8 @@ class ScreenCaptureService: ObservableObject {
|
|||||||
|
|
||||||
if let extractedText = extractedText, !extractedText.isEmpty {
|
if let extractedText = extractedText, !extractedText.isEmpty {
|
||||||
contextText += "Window Content:\n\(extractedText)"
|
contextText += "Window Content:\n\(extractedText)"
|
||||||
let preview = String(extractedText.prefix(100))
|
|
||||||
logger.notice("📸 Text extracted: \(preview, privacy: .public)\(extractedText.count > 100 ? "..." : "")")
|
|
||||||
} else {
|
} else {
|
||||||
contextText += "Window Content:\nNo text detected via OCR"
|
contextText += "Window Content:\nNo text detected via OCR"
|
||||||
logger.notice("📸 No text extracted from window")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await MainActor.run {
|
await MainActor.run {
|
||||||
@ -174,8 +160,7 @@ class ScreenCaptureService: ObservableObject {
|
|||||||
|
|
||||||
return contextText
|
return contextText
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.notice("📸 Window capture failed")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,181 +1,138 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import SwiftData
|
import SwiftData
|
||||||
import OSLog
|
|
||||||
|
|
||||||
/// A utility class that manages automatic cleanup of audio files while preserving transcript data
|
/// A utility class that manages automatic cleanup of audio files while preserving transcript data
|
||||||
class AudioCleanupManager {
|
class AudioCleanupManager {
|
||||||
static let shared = AudioCleanupManager()
|
static let shared = AudioCleanupManager()
|
||||||
|
|
||||||
private let logger = Logger(subsystem: "com.prakashjoshipax.voiceink", category: "AudioCleanupManager")
|
|
||||||
private var cleanupTimer: Timer?
|
private var cleanupTimer: Timer?
|
||||||
|
|
||||||
// Default cleanup settings
|
// Default cleanup settings
|
||||||
private let defaultRetentionDays = 7
|
private let defaultRetentionDays = 7
|
||||||
private let cleanupCheckInterval: TimeInterval = 86400 // Check once per day (in seconds)
|
private let cleanupCheckInterval: TimeInterval = 86400 // Check once per day (in seconds)
|
||||||
|
|
||||||
private init() {
|
private init() {}
|
||||||
logger.info("AudioCleanupManager initialized")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Start the automatic cleanup process
|
/// Start the automatic cleanup process
|
||||||
func startAutomaticCleanup(modelContext: ModelContext) {
|
func startAutomaticCleanup(modelContext: ModelContext) {
|
||||||
logger.info("Starting automatic audio cleanup")
|
|
||||||
|
|
||||||
// Cancel any existing timer
|
// Cancel any existing timer
|
||||||
cleanupTimer?.invalidate()
|
cleanupTimer?.invalidate()
|
||||||
|
|
||||||
// Perform initial cleanup
|
// Perform initial cleanup
|
||||||
Task {
|
Task {
|
||||||
await performCleanup(modelContext: modelContext)
|
await performCleanup(modelContext: modelContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Schedule regular cleanup
|
// Schedule regular cleanup
|
||||||
cleanupTimer = Timer.scheduledTimer(withTimeInterval: cleanupCheckInterval, repeats: true) { [weak self] _ in
|
cleanupTimer = Timer.scheduledTimer(withTimeInterval: cleanupCheckInterval, repeats: true) { [weak self] _ in
|
||||||
Task { [weak self] in
|
Task { [weak self] in
|
||||||
await self?.performCleanup(modelContext: modelContext)
|
await self?.performCleanup(modelContext: modelContext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info("Automatic cleanup scheduled")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stop the automatic cleanup process
|
/// Stop the automatic cleanup process
|
||||||
func stopAutomaticCleanup() {
|
func stopAutomaticCleanup() {
|
||||||
logger.info("Stopping automatic audio cleanup")
|
|
||||||
cleanupTimer?.invalidate()
|
cleanupTimer?.invalidate()
|
||||||
cleanupTimer = nil
|
cleanupTimer = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get information about the files that would be cleaned up
|
/// Get information about the files that would be cleaned up
|
||||||
func getCleanupInfo(modelContext: ModelContext) async -> (fileCount: Int, totalSize: Int64, transcriptions: [Transcription]) {
|
func getCleanupInfo(modelContext: ModelContext) async -> (fileCount: Int, totalSize: Int64, transcriptions: [Transcription]) {
|
||||||
logger.info("Analyzing potential audio cleanup")
|
|
||||||
|
|
||||||
// Get retention period from UserDefaults
|
// Get retention period from UserDefaults
|
||||||
let retentionDays = UserDefaults.standard.integer(forKey: "AudioRetentionPeriod")
|
let retentionDays = UserDefaults.standard.integer(forKey: "AudioRetentionPeriod")
|
||||||
let effectiveRetentionDays = retentionDays > 0 ? retentionDays : defaultRetentionDays
|
let effectiveRetentionDays = retentionDays > 0 ? retentionDays : defaultRetentionDays
|
||||||
|
|
||||||
// Calculate the cutoff date
|
// Calculate the cutoff date
|
||||||
let calendar = Calendar.current
|
let calendar = Calendar.current
|
||||||
guard let cutoffDate = calendar.date(byAdding: .day, value: -effectiveRetentionDays, to: Date()) else {
|
guard let cutoffDate = calendar.date(byAdding: .day, value: -effectiveRetentionDays, to: Date()) else {
|
||||||
logger.error("Failed to calculate cutoff date")
|
|
||||||
return (0, 0, [])
|
return (0, 0, [])
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
// Execute SwiftData operations on the main thread
|
// Execute SwiftData operations on the main thread
|
||||||
return try await MainActor.run {
|
return try await MainActor.run {
|
||||||
// Create a predicate to find transcriptions with audio files older than the cutoff date
|
// Create a predicate to find transcriptions with audio files older than the cutoff date
|
||||||
let descriptor = FetchDescriptor<Transcription>(
|
let descriptor = FetchDescriptor<Transcription>(
|
||||||
predicate: #Predicate<Transcription> { transcription in
|
predicate: #Predicate<Transcription> { transcription in
|
||||||
transcription.timestamp < cutoffDate &&
|
transcription.timestamp < cutoffDate &&
|
||||||
transcription.audioFileURL != nil
|
transcription.audioFileURL != nil
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
let transcriptions = try modelContext.fetch(descriptor)
|
let transcriptions = try modelContext.fetch(descriptor)
|
||||||
|
|
||||||
// Calculate stats (can be done on any thread)
|
// Calculate stats (can be done on any thread)
|
||||||
var fileCount = 0
|
var fileCount = 0
|
||||||
var totalSize: Int64 = 0
|
var totalSize: Int64 = 0
|
||||||
var eligibleTranscriptions: [Transcription] = []
|
var eligibleTranscriptions: [Transcription] = []
|
||||||
|
|
||||||
for transcription in transcriptions {
|
for transcription in transcriptions {
|
||||||
if let urlString = transcription.audioFileURL,
|
if let urlString = transcription.audioFileURL,
|
||||||
let url = URL(string: urlString),
|
let url = URL(string: urlString),
|
||||||
FileManager.default.fileExists(atPath: url.path) {
|
FileManager.default.fileExists(atPath: url.path) {
|
||||||
do {
|
if let attributes = try? FileManager.default.attributesOfItem(atPath: url.path),
|
||||||
// Get file attributes to determine size
|
let fileSize = attributes[.size] as? Int64 {
|
||||||
let attributes = try FileManager.default.attributesOfItem(atPath: url.path)
|
totalSize += fileSize
|
||||||
if let fileSize = attributes[.size] as? Int64 {
|
fileCount += 1
|
||||||
totalSize += fileSize
|
eligibleTranscriptions.append(transcription)
|
||||||
fileCount += 1
|
|
||||||
eligibleTranscriptions.append(transcription)
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
self.logger.error("Failed to get attributes for \(url.lastPathComponent): \(error.localizedDescription)")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.logger.info("Found \(fileCount) files eligible for cleanup, totaling \(self.formatFileSize(totalSize))")
|
|
||||||
return (fileCount, totalSize, eligibleTranscriptions)
|
return (fileCount, totalSize, eligibleTranscriptions)
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
logger.error("Error analyzing files for cleanup: \(error.localizedDescription)")
|
|
||||||
return (0, 0, [])
|
return (0, 0, [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform the cleanup operation
|
/// Perform the cleanup operation
|
||||||
private func performCleanup(modelContext: ModelContext) async {
|
private func performCleanup(modelContext: ModelContext) async {
|
||||||
logger.info("Performing audio cleanup")
|
|
||||||
|
|
||||||
// Get retention period from UserDefaults
|
// Get retention period from UserDefaults
|
||||||
let retentionDays = UserDefaults.standard.integer(forKey: "AudioRetentionPeriod")
|
let retentionDays = UserDefaults.standard.integer(forKey: "AudioRetentionPeriod")
|
||||||
let effectiveRetentionDays = retentionDays > 0 ? retentionDays : defaultRetentionDays
|
let effectiveRetentionDays = retentionDays > 0 ? retentionDays : defaultRetentionDays
|
||||||
|
|
||||||
// Check if automatic cleanup is enabled
|
// Check if automatic cleanup is enabled
|
||||||
let isCleanupEnabled = UserDefaults.standard.bool(forKey: "IsAudioCleanupEnabled")
|
let isCleanupEnabled = UserDefaults.standard.bool(forKey: "IsAudioCleanupEnabled")
|
||||||
guard isCleanupEnabled else {
|
guard isCleanupEnabled else { return }
|
||||||
logger.info("Audio cleanup is disabled, skipping")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info("Audio retention period: \(effectiveRetentionDays) days")
|
|
||||||
|
|
||||||
// Calculate the cutoff date
|
// Calculate the cutoff date
|
||||||
let calendar = Calendar.current
|
let calendar = Calendar.current
|
||||||
guard let cutoffDate = calendar.date(byAdding: .day, value: -effectiveRetentionDays, to: Date()) else {
|
guard let cutoffDate = calendar.date(byAdding: .day, value: -effectiveRetentionDays, to: Date()) else {
|
||||||
logger.error("Failed to calculate cutoff date")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info("Cutoff date for audio cleanup: \(cutoffDate)")
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
// Execute SwiftData operations on the main thread
|
// Execute SwiftData operations on the main thread
|
||||||
try await MainActor.run {
|
try await MainActor.run {
|
||||||
// Create a predicate to find transcriptions with audio files older than the cutoff date
|
// Create a predicate to find transcriptions with audio files older than the cutoff date
|
||||||
let descriptor = FetchDescriptor<Transcription>(
|
let descriptor = FetchDescriptor<Transcription>(
|
||||||
predicate: #Predicate<Transcription> { transcription in
|
predicate: #Predicate<Transcription> { transcription in
|
||||||
transcription.timestamp < cutoffDate &&
|
transcription.timestamp < cutoffDate &&
|
||||||
transcription.audioFileURL != nil
|
transcription.audioFileURL != nil
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
let transcriptions = try modelContext.fetch(descriptor)
|
let transcriptions = try modelContext.fetch(descriptor)
|
||||||
self.logger.info("Found \(transcriptions.count) transcriptions with audio files to clean up")
|
|
||||||
|
|
||||||
var deletedCount = 0
|
var deletedCount = 0
|
||||||
var errorCount = 0
|
|
||||||
|
|
||||||
for transcription in transcriptions {
|
for transcription in transcriptions {
|
||||||
if let urlString = transcription.audioFileURL,
|
if let urlString = transcription.audioFileURL,
|
||||||
let url = URL(string: urlString),
|
let url = URL(string: urlString),
|
||||||
FileManager.default.fileExists(atPath: url.path) {
|
FileManager.default.fileExists(atPath: url.path) {
|
||||||
do {
|
try? FileManager.default.removeItem(at: url)
|
||||||
// Delete the audio file
|
transcription.audioFileURL = nil
|
||||||
try FileManager.default.removeItem(at: url)
|
deletedCount += 1
|
||||||
|
|
||||||
// Update the transcription to remove the audio file reference
|
|
||||||
transcription.audioFileURL = nil
|
|
||||||
|
|
||||||
deletedCount += 1
|
|
||||||
self.logger.debug("Deleted audio file: \(url.lastPathComponent)")
|
|
||||||
} catch {
|
|
||||||
errorCount += 1
|
|
||||||
self.logger.error("Failed to delete audio file \(url.lastPathComponent): \(error.localizedDescription)")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if deletedCount > 0 || errorCount > 0 {
|
if deletedCount > 0 {
|
||||||
try modelContext.save()
|
try modelContext.save()
|
||||||
self.logger.info("Cleanup complete. Deleted \(deletedCount) files. Failed: \(errorCount)")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
logger.error("Error during audio cleanup: \(error.localizedDescription)")
|
// Silently fail - cleanup is non-critical
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,47 +143,33 @@ class AudioCleanupManager {
|
|||||||
|
|
||||||
/// Run cleanup on the specified transcriptions
|
/// Run cleanup on the specified transcriptions
|
||||||
func runCleanupForTranscriptions(modelContext: ModelContext, transcriptions: [Transcription]) async -> (deletedCount: Int, errorCount: Int) {
|
func runCleanupForTranscriptions(modelContext: ModelContext, transcriptions: [Transcription]) async -> (deletedCount: Int, errorCount: Int) {
|
||||||
logger.info("Running cleanup for \(transcriptions.count) specific transcriptions")
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
// Execute SwiftData operations on the main thread
|
// Execute SwiftData operations on the main thread
|
||||||
return try await MainActor.run {
|
return try await MainActor.run {
|
||||||
var deletedCount = 0
|
var deletedCount = 0
|
||||||
var errorCount = 0
|
var errorCount = 0
|
||||||
|
|
||||||
for transcription in transcriptions {
|
for transcription in transcriptions {
|
||||||
if let urlString = transcription.audioFileURL,
|
if let urlString = transcription.audioFileURL,
|
||||||
let url = URL(string: urlString),
|
let url = URL(string: urlString),
|
||||||
FileManager.default.fileExists(atPath: url.path) {
|
FileManager.default.fileExists(atPath: url.path) {
|
||||||
do {
|
do {
|
||||||
// Delete the audio file
|
|
||||||
try FileManager.default.removeItem(at: url)
|
try FileManager.default.removeItem(at: url)
|
||||||
|
|
||||||
// Update the transcription to remove the audio file reference
|
|
||||||
transcription.audioFileURL = nil
|
transcription.audioFileURL = nil
|
||||||
|
|
||||||
deletedCount += 1
|
deletedCount += 1
|
||||||
self.logger.debug("Deleted audio file: \(url.lastPathComponent)")
|
|
||||||
} catch {
|
} catch {
|
||||||
errorCount += 1
|
errorCount += 1
|
||||||
self.logger.error("Failed to delete audio file \(url.lastPathComponent): \(error.localizedDescription)")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if deletedCount > 0 || errorCount > 0 {
|
if deletedCount > 0 || errorCount > 0 {
|
||||||
do {
|
try? modelContext.save()
|
||||||
try modelContext.save()
|
|
||||||
self.logger.info("Cleanup complete. Deleted \(deletedCount) files. Failed: \(errorCount)")
|
|
||||||
} catch {
|
|
||||||
self.logger.error("Error saving model context after cleanup: \(error.localizedDescription)")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (deletedCount, errorCount)
|
return (deletedCount, errorCount)
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
logger.error("Error during targeted cleanup: \(error.localizedDescription)")
|
|
||||||
return (0, 0)
|
return (0, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,13 +49,6 @@ struct VoiceInkApp: App {
|
|||||||
// Attempt 1: Try persistent storage
|
// Attempt 1: Try persistent storage
|
||||||
if let persistentContainer = Self.createPersistentContainer(schema: schema, logger: logger) {
|
if let persistentContainer = Self.createPersistentContainer(schema: schema, logger: logger) {
|
||||||
container = persistentContainer
|
container = persistentContainer
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
// Print SwiftData storage location in debug builds only
|
|
||||||
if let url = persistentContainer.mainContext.container.configurations.first?.url {
|
|
||||||
print("💾 SwiftData storage location: \(url.path)")
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
// Attempt 2: Try in-memory storage
|
// Attempt 2: Try in-memory storage
|
||||||
else if let memoryContainer = Self.createInMemoryContainer(schema: schema, logger: logger) {
|
else if let memoryContainer = Self.createInMemoryContainer(schema: schema, logger: logger) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user