vOOice/VoiceInk/Services/SystemInfoService.swift

214 lines
6.9 KiB
Swift

import Foundation
import AppKit
import AVFoundation
class SystemInfoService {
static let shared = SystemInfoService()
private init() {}
func getSystemInfoString() -> String {
let info = """
=== VOICEINK SYSTEM INFORMATION ===
Generated: \(Date().formatted(date: .long, time: .standard))
APP INFORMATION:
App Version: \(getAppVersion())
Build Version: \(getBuildVersion())
License Status: \(getLicenseStatus())
OPERATING SYSTEM:
macOS Version: \(ProcessInfo.processInfo.operatingSystemVersionString)
HARDWARE INFORMATION:
Device Model: \(getMacModel())
CPU: \(getCPUInfo())
Memory: \(getMemoryInfo())
Architecture: \(getArchitecture())
AUDIO SETTINGS:
Input Mode: \(getAudioInputMode())
Current Audio Device: \(getCurrentAudioDevice())
Available Audio Devices: \(getAvailableAudioDevices())
HOTKEY SETTINGS:
Primary Hotkey: \(getPrimaryHotkey())
Secondary Hotkey: \(getSecondaryHotkey())
TRANSCRIPTION SETTINGS:
Selected Model: \(getCurrentTranscriptionModel())
Selected Language: \(getCurrentLanguage())
AI Enhancement: \(getAIEnhancementStatus())
AI Provider: \(getAIProvider())
AI Model: \(getAIModel())
PERMISSIONS:
Accessibility: \(getAccessibilityStatus())
Screen Recording: \(getScreenRecordingStatus())
Microphone: \(getMicrophoneStatus())
"""
return info
}
func copySystemInfoToClipboard() {
let info = getSystemInfoString()
let pasteboard = NSPasteboard.general
pasteboard.clearContents()
pasteboard.setString(info, forType: .string)
}
private func getAppVersion() -> String {
return Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown"
}
private func getBuildVersion() -> String {
return Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "Unknown"
}
private func getMacModel() -> String {
var size = 0
sysctlbyname("hw.model", nil, &size, nil, 0)
var machine = [CChar](repeating: 0, count: size)
sysctlbyname("hw.model", &machine, &size, nil, 0)
return String(cString: machine)
}
private func getCPUInfo() -> String {
var size = 0
sysctlbyname("machdep.cpu.brand_string", nil, &size, nil, 0)
var buffer = [CChar](repeating: 0, count: size)
sysctlbyname("machdep.cpu.brand_string", &buffer, &size, nil, 0)
return String(cString: buffer)
}
private func getMemoryInfo() -> String {
let totalMemory = ProcessInfo.processInfo.physicalMemory
return ByteCountFormatter.string(fromByteCount: Int64(totalMemory), countStyle: .memory)
}
private func getArchitecture() -> String {
#if arch(x86_64)
return "Intel x86_64"
#elseif arch(arm64)
return "Apple Silicon (ARM64)"
#else
return "Unknown"
#endif
}
private func getAudioInputMode() -> String {
if let mode = UserDefaults.standard.audioInputModeRawValue,
let audioMode = AudioInputMode(rawValue: mode) {
return audioMode.rawValue
}
return "System Default"
}
private func getCurrentAudioDevice() -> String {
let audioManager = AudioDeviceManager.shared
if let deviceID = audioManager.selectedDeviceID ?? audioManager.fallbackDeviceID,
let deviceName = audioManager.getDeviceName(deviceID: deviceID) {
return deviceName
}
return "System Default"
}
private func getAvailableAudioDevices() -> String {
let devices = AudioDeviceManager.shared.availableDevices
if devices.isEmpty {
return "None detected"
}
return devices.map { $0.name }.joined(separator: ", ")
}
private func getPrimaryHotkey() -> String {
if let hotkeyRaw = UserDefaults.standard.string(forKey: "selectedHotkey1"),
let hotkey = HotkeyManager.HotkeyOption(rawValue: hotkeyRaw) {
return hotkey.displayName
}
return "Right Command"
}
private func getSecondaryHotkey() -> String {
if let hotkeyRaw = UserDefaults.standard.string(forKey: "selectedHotkey2"),
let hotkey = HotkeyManager.HotkeyOption(rawValue: hotkeyRaw) {
return hotkey.displayName
}
return "None"
}
private func getCurrentTranscriptionModel() -> String {
if let modelName = UserDefaults.standard.string(forKey: "CurrentTranscriptionModel") {
if let model = PredefinedModels.models.first(where: { $0.name == modelName }) {
return model.displayName
}
return modelName
}
return "No model selected"
}
private func getAIEnhancementStatus() -> String {
let enhancementEnabled = UserDefaults.standard.bool(forKey: "isAIEnhancementEnabled")
return enhancementEnabled ? "Enabled" : "Disabled"
}
private func getAIProvider() -> String {
if let providerRaw = UserDefaults.standard.string(forKey: "selectedAIProvider") {
return providerRaw
}
return "None selected"
}
private func getAIModel() -> String {
if let providerRaw = UserDefaults.standard.string(forKey: "selectedAIProvider") {
let modelKey = "\(providerRaw)SelectedModel"
if let savedModel = UserDefaults.standard.string(forKey: modelKey), !savedModel.isEmpty {
return savedModel
}
return "Default (\(providerRaw))"
}
return "None selected"
}
private func getAccessibilityStatus() -> String {
return AXIsProcessTrusted() ? "Granted" : "Not Granted"
}
private func getScreenRecordingStatus() -> String {
return CGPreflightScreenCaptureAccess() ? "Granted" : "Not Granted"
}
private func getMicrophoneStatus() -> String {
switch AVCaptureDevice.authorizationStatus(for: .audio) {
case .authorized:
return "Granted"
case .denied:
return "Denied"
case .restricted:
return "Restricted"
case .notDetermined:
return "Not Determined"
@unknown default:
return "Unknown"
}
}
private func getLicenseStatus() -> String {
let userDefaults = UserDefaults.standard
// Check for existing license key and activation
if let _ = userDefaults.licenseKey {
if userDefaults.activationId != nil || !userDefaults.bool(forKey: "VoiceInkLicenseRequiresActivation") {
return "Licensed (Pro)"
}
}
return "Not Licensed"
}
private func getCurrentLanguage() -> String {
return UserDefaults.standard.string(forKey: "SelectedLanguage") ?? "en"
}
}