Added debugging for screen capture services

This commit is contained in:
Beingpax 2025-03-06 22:02:26 +05:45
parent 61453740cd
commit 214d71c29d
3 changed files with 64 additions and 60 deletions

View File

@ -468,7 +468,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 99; CURRENT_PROJECT_VERSION = 0.99;
DEVELOPMENT_ASSET_PATHS = "\"VoiceInk/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"VoiceInk/Preview Content\"";
DEVELOPMENT_TEAM = V6J6A3VWY2; DEVELOPMENT_TEAM = V6J6A3VWY2;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
@ -501,7 +501,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 99; CURRENT_PROJECT_VERSION = 0.99;
DEVELOPMENT_ASSET_PATHS = "\"VoiceInk/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"VoiceInk/Preview Content\"";
DEVELOPMENT_TEAM = V6J6A3VWY2; DEVELOPMENT_TEAM = V6J6A3VWY2;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;

View File

@ -10,8 +10,8 @@ enum EnhancementMode {
class AIEnhancementService: ObservableObject { class AIEnhancementService: ObservableObject {
private let logger = Logger( private let logger = Logger(
subsystem: "com.voiceink.enhancement", subsystem: "com.prakashjoshipax.VoiceInk",
category: "AI" category: "aienhancement"
) )
@Published var isEnhancementEnabled: Bool { @Published var isEnhancementEnabled: Bool {
@ -234,19 +234,27 @@ class AIEnhancementService: ObservableObject {
// Handle Ollama requests differently // Handle Ollama requests differently
if aiService.selectedProvider == .ollama { if aiService.selectedProvider == .ollama {
logger.info("AI Enhancement: Using Ollama for enhancement") logger.notice("📤 Request to Ollama")
logger.notice("🤖 System: \(systemMessage)")
logger.notice("📝 Sending: \(text)")
do { do {
return try await aiService.enhanceWithOllama(text: text, systemPrompt: systemMessage) let result = try await aiService.enhanceWithOllama(text: text, systemPrompt: systemMessage)
logger.notice("✅ Ollama enhancement successful")
logger.notice("📝 Received: \(result)")
return result
} catch let error as LocalAIError { } catch let error as LocalAIError {
logger.error("AI Enhancement: Ollama error - \(error.localizedDescription)")
switch error { switch error {
case .serviceUnavailable: case .serviceUnavailable:
logger.error("🔌 Ollama service unavailable")
throw EnhancementError.notConfigured throw EnhancementError.notConfigured
case .modelNotFound: case .modelNotFound:
logger.error("🤖 Ollama model not found")
throw EnhancementError.enhancementFailed throw EnhancementError.enhancementFailed
case .serverError: case .serverError:
logger.error("🔥 Ollama server error")
throw EnhancementError.serverError throw EnhancementError.serverError
default: default:
logger.error("❌ Ollama enhancement failed")
throw EnhancementError.enhancementFailed throw EnhancementError.enhancementFailed
} }
} }
@ -290,16 +298,13 @@ class AIEnhancementService: ObservableObject {
request.httpBody = try? JSONSerialization.data(withJSONObject: requestBody) request.httpBody = try? JSONSerialization.data(withJSONObject: requestBody)
do { do {
logger.info("AI Enhancement: Sending request to Gemini API (attempt \(retryCount + 1))") logger.notice("📤 Request to Gemini")
logger.debug(""" logger.notice("🤖 System: \(systemMessage)")
AI Enhancement Debug (Gemini): logger.notice("📝 Sending: \(text)")
System Message: \(systemMessage)
Original Text: \(text)
""")
let (data, response) = try await URLSession.shared.data(for: request) let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse else { guard let httpResponse = response as? HTTPURLResponse else {
logger.error("AI Enhancement: Invalid response received from Gemini") logger.error("❌ Invalid Gemini response")
throw EnhancementError.invalidResponse throw EnhancementError.invalidResponse
} }
@ -312,39 +317,35 @@ class AIEnhancementService: ObservableObject {
let parts = content["parts"] as? [[String: Any]], let parts = content["parts"] as? [[String: Any]],
let firstPart = parts.first, let firstPart = parts.first,
let enhancedText = firstPart["text"] as? String else { let enhancedText = firstPart["text"] as? String else {
logger.error("AI Enhancement: Failed to parse Gemini API response") logger.error("❌ Failed to parse Gemini response")
throw EnhancementError.enhancementFailed throw EnhancementError.enhancementFailed
} }
let result = enhancedText.trimmingCharacters(in: .whitespacesAndNewlines) let result = enhancedText.trimmingCharacters(in: .whitespacesAndNewlines)
logger.info("AI Enhancement: Successfully enhanced text using Gemini") logger.notice("✅ Gemini enhancement successful")
logger.debug(""" logger.notice("📝 Received: \(result)")
AI Enhancement Debug (Gemini):
Original Text: \(text)
Enhanced Text: \(result)
""")
return result return result
case 401: case 401:
logger.error("AI Enhancement: Authentication failed") logger.error("🔒 Authentication failed")
throw EnhancementError.authenticationFailed throw EnhancementError.authenticationFailed
case 429: case 429:
logger.error("AI Enhancement: Rate limit exceeded") logger.error(" Rate limit exceeded")
throw EnhancementError.rateLimitExceeded throw EnhancementError.rateLimitExceeded
case 500...599: case 500...599:
logger.error("AI Enhancement: Server error - Status code: \(httpResponse.statusCode)") logger.error("🔥 Server error (\(httpResponse.statusCode))")
throw EnhancementError.serverError throw EnhancementError.serverError
default: default:
logger.error("AI Enhancement: Unexpected status code: \(httpResponse.statusCode)") logger.error("❌ Unexpected status (\(httpResponse.statusCode))")
throw EnhancementError.apiError throw EnhancementError.apiError
} }
} catch let error as EnhancementError { } catch let error as EnhancementError {
throw error throw error
} catch { } catch {
logger.error("AI Enhancement: Network error - \(error.localizedDescription)") logger.error("❌ Network error: \(error.localizedDescription)")
if retryCount < maxRetries { if retryCount < maxRetries {
try await Task.sleep(nanoseconds: UInt64(pow(2.0, Double(retryCount)) * 1_000_000_000)) try await Task.sleep(nanoseconds: UInt64(pow(2.0, Double(retryCount)) * 1_000_000_000))
@ -376,16 +377,13 @@ class AIEnhancementService: ObservableObject {
request.httpBody = try? JSONSerialization.data(withJSONObject: requestBody) request.httpBody = try? JSONSerialization.data(withJSONObject: requestBody)
do { do {
logger.info("AI Enhancement: Sending request to Anthropic API (attempt \(retryCount + 1))") logger.notice("📤 Request to Anthropic")
logger.debug(""" logger.notice("🤖 System: \(systemMessage)")
AI Enhancement Debug (Anthropic): logger.notice("📝 Sending: \(text)")
System Message: \(systemMessage)
Original Text: \(text)
""")
let (data, response) = try await URLSession.shared.data(for: request) let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse else { guard let httpResponse = response as? HTTPURLResponse else {
logger.error("AI Enhancement: Invalid response received from Anthropic") logger.error("❌ Invalid Anthropic response")
throw EnhancementError.invalidResponse throw EnhancementError.invalidResponse
} }
@ -395,39 +393,35 @@ class AIEnhancementService: ObservableObject {
let content = jsonResponse["content"] as? [[String: Any]], let content = jsonResponse["content"] as? [[String: Any]],
let firstContent = content.first, let firstContent = content.first,
let enhancedText = firstContent["text"] as? String else { let enhancedText = firstContent["text"] as? String else {
logger.error("AI Enhancement: Failed to parse Anthropic API response") logger.error("❌ Failed to parse Anthropic response")
throw EnhancementError.enhancementFailed throw EnhancementError.enhancementFailed
} }
let result = enhancedText.trimmingCharacters(in: .whitespacesAndNewlines) let result = enhancedText.trimmingCharacters(in: .whitespacesAndNewlines)
logger.info("AI Enhancement: Successfully enhanced text using Anthropic") logger.notice("✅ Anthropic enhancement successful")
logger.debug(""" logger.notice("📝 Received: \(result)")
AI Enhancement Debug (Anthropic):
Original Text: \(text)
Enhanced Text: \(result)
""")
return result return result
case 401: case 401:
logger.error("AI Enhancement: Authentication failed") logger.error("🔒 Authentication failed")
throw EnhancementError.authenticationFailed throw EnhancementError.authenticationFailed
case 429: case 429:
logger.error("AI Enhancement: Rate limit exceeded") logger.error(" Rate limit exceeded")
throw EnhancementError.rateLimitExceeded throw EnhancementError.rateLimitExceeded
case 500...599: case 500...599:
logger.error("AI Enhancement: Server error - Status code: \(httpResponse.statusCode)") logger.error("🔥 Server error (\(httpResponse.statusCode))")
throw EnhancementError.serverError throw EnhancementError.serverError
default: default:
logger.error("AI Enhancement: Unexpected status code: \(httpResponse.statusCode)") logger.error("❌ Unexpected status (\(httpResponse.statusCode))")
throw EnhancementError.apiError throw EnhancementError.apiError
} }
} catch let error as EnhancementError { } catch let error as EnhancementError {
throw error throw error
} catch { } catch {
logger.error("AI Enhancement: Network error - \(error.localizedDescription)") logger.error("❌ Network error: \(error.localizedDescription)")
if retryCount < maxRetries { if retryCount < maxRetries {
try await Task.sleep(nanoseconds: UInt64(pow(2.0, Double(retryCount)) * 1_000_000_000)) try await Task.sleep(nanoseconds: UInt64(pow(2.0, Double(retryCount)) * 1_000_000_000))
@ -470,15 +464,16 @@ class AIEnhancementService: ObservableObject {
request.httpBody = try? JSONSerialization.data(withJSONObject: requestBody) request.httpBody = try? JSONSerialization.data(withJSONObject: requestBody)
do { do {
logger.info("AI Enhancement: Sending request to \(self.aiService.selectedProvider.rawValue) API (attempt \(retryCount + 1))") logger.notice("📤 Request to \(self.aiService.selectedProvider.rawValue)")
logger.notice("🤖 System: \(systemMessage)")
logger.notice("📝 Sending: \(text)")
let (data, response) = try await URLSession.shared.data(for: request) let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse else { guard let httpResponse = response as? HTTPURLResponse else {
logger.error("AI Enhancement: Invalid response received from \(self.aiService.selectedProvider.rawValue)") logger.error("❌ Invalid response")
throw EnhancementError.invalidResponse throw EnhancementError.invalidResponse
} }
// Handle different HTTP status codes
switch httpResponse.statusCode { switch httpResponse.statusCode {
case 200: case 200:
guard let jsonResponse = try? JSONSerialization.jsonObject(with: data) as? [String: Any], guard let jsonResponse = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
@ -486,40 +481,36 @@ class AIEnhancementService: ObservableObject {
let firstChoice = choices.first, let firstChoice = choices.first,
let message = firstChoice["message"] as? [String: Any], let message = firstChoice["message"] as? [String: Any],
let enhancedText = message["content"] as? String else { let enhancedText = message["content"] as? String else {
logger.error("AI Enhancement: Failed to parse \(self.aiService.selectedProvider.rawValue) API response") logger.error("❌ Failed to parse response")
throw EnhancementError.enhancementFailed throw EnhancementError.enhancementFailed
} }
let result = enhancedText.trimmingCharacters(in: .whitespacesAndNewlines) let result = enhancedText.trimmingCharacters(in: .whitespacesAndNewlines)
logger.info("AI Enhancement: Successfully enhanced text using \(self.aiService.selectedProvider.rawValue)") logger.notice("✅ Enhancement successful")
logger.debug(""" logger.notice("📝 Received: \(result)")
AI Enhancement Debug:
Original Text: \(text)
Enhanced Text: \(result)
""")
return result return result
case 401: case 401:
logger.error("AI Enhancement: Authentication failed") logger.error("🔒 Authentication failed")
throw EnhancementError.authenticationFailed throw EnhancementError.authenticationFailed
case 429: case 429:
logger.error("AI Enhancement: Rate limit exceeded") logger.error(" Rate limit exceeded")
throw EnhancementError.rateLimitExceeded throw EnhancementError.rateLimitExceeded
case 500...599: case 500...599:
logger.error("AI Enhancement: Server error - Status code: \(httpResponse.statusCode)") logger.error("🔥 Server error (\(httpResponse.statusCode))")
throw EnhancementError.serverError throw EnhancementError.serverError
default: default:
logger.error("AI Enhancement: Unexpected status code: \(httpResponse.statusCode)") logger.error("❌ Unexpected status (\(httpResponse.statusCode))")
throw EnhancementError.apiError throw EnhancementError.apiError
} }
} catch let error as EnhancementError { } catch let error as EnhancementError {
throw error throw error
} catch { } catch {
logger.error("AI Enhancement: Network error - \(error.localizedDescription)") logger.error("❌ Network error: \(error.localizedDescription)")
if retryCount < maxRetries { if retryCount < maxRetries {
try await Task.sleep(nanoseconds: UInt64(pow(2.0, Double(retryCount)) * 1_000_000_000)) try await Task.sleep(nanoseconds: UInt64(pow(2.0, Double(retryCount)) * 1_000_000_000))

View File

@ -1,11 +1,17 @@
import Foundation import Foundation
import AppKit import AppKit
import Vision import Vision
import os
class ScreenCaptureService: ObservableObject { 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 func getActiveWindowInfo() -> (title: String, ownerName: String, windowID: CGWindowID)? { private func getActiveWindowInfo() -> (title: String, ownerName: String, windowID: CGWindowID)? {
let options = CGWindowListOption([.optionOnScreenOnly, .excludeDesktopElements]) let options = CGWindowListOption([.optionOnScreenOnly, .excludeDesktopElements])
let windowListInfo = CGWindowListCopyWindowInfo(options, kCGNullWindowID) as? [[String: Any]] ?? [] let windowListInfo = CGWindowListCopyWindowInfo(options, kCGNullWindowID) as? [[String: Any]] ?? []
@ -86,11 +92,16 @@ class ScreenCaptureService: ObservableObject {
isCapturing = true isCapturing = true
defer { isCapturing = false } defer { isCapturing = false }
logger.notice("🎬 Starting screen capture")
// First get window info // First get window info
guard let windowInfo = getActiveWindowInfo() else { guard let windowInfo = getActiveWindowInfo() else {
logger.notice("❌ Failed to get window info")
return nil return nil
} }
logger.notice("🎯 Found window: \(windowInfo.title) (\(windowInfo.ownerName))")
// Start with window metadata // Start with window metadata
var contextText = """ var contextText = """
Active Window: \(windowInfo.title) Active Window: \(windowInfo.title)
@ -106,6 +117,8 @@ class ScreenCaptureService: ObservableObject {
} }
}) { }) {
contextText += "Window Content:\n\(extractedText)" contextText += "Window Content:\n\(extractedText)"
// Log immediately after text extraction
logger.notice("✅ Captured: \(contextText)")
} }
} }