Files

1 line
21 KiB
JSON

{"repo": "alanzhou001/sgodai", "files": {"macos/SgodAI-Mac/SgodAI-Mac/LocalBackend.swift": {"030283cdac9bbff41d999cda321bf108e48ea317": {"t": 1785745890.7922347, "n": 8166, "h": "f7b2861daedd32d1", "c": "import Foundation\nimport SwiftUI\n\n@MainActor\nfinal class LocalBackend: ObservableObject {\n enum Status {\n case checking\n case live(String)\n case staticFallback\n case unavailable(String)\n\n var title: String {\n switch self {\n case .checking:\n return \"Checking\"\n case .live:\n return \"Embedded API\"\n case .staticFallback:\n return \"Static Demo\"\n case .unavailable:\n return \"Offline\"\n }\n }\n\n var detail: String {\n switch self {\n case .checking:\n return \"Checking the local SgodAI API.\"\n case .live(let message):\n return message\n case .staticFallback:\n return \"The local API is not running; the bundled static interface is loaded.\"\n case .unavailable(let message):\n return message\n }\n }\n\n var symbol: String {\n switch self {\n case .checking:\n return \"clock\"\n case .live:\n return \"checkmark.circle\"\n case .staticFallback:\n return \"rectangle.on.rectangle\"\n case .unavailable:\n return \"exclamationmark.triangle\"\n }\n }\n\n var color: Color {\n switch self {\n case .checking:\n return .secondary\n case .live:\n return .green\n case .staticFallback:\n return .orange\n case .unavailable:\n return .red\n }\n }\n }\n\n @Published var status: Status = .checking\n @Published var isChecking = false\n @Published var reloadToken = 0\n @Published var webURL = URL(string: \"http://127.0.0.1:18765/\")!\n\n private let port = 18765\n private let localURL = URL(string: \"http://127.0.0.1:18765/\")!\n private let healthURL = URL(string: \"http://127.0.0.1:18765/api/system/health-check\")!\n private var backendProcess: Process?\n\n func bootstrap() async {\n startBundledBackendIfNeeded()\n await checkHealth()\n }\n\n func checkHealth() async {\n isChecking = true\n status = .checking\n defer { isChecking = false }\n\n do {\n var request = URLRequest(url: healthURL)\n request.timeoutInterval = 2.5\n let (data, response) = try await URLSession.shared.data(for: request)\n guard let http = response as? HTTPURLResponse, (200..<300).contains(http.statusCode) else {\n throw URLError(.badServerResponse)\n }\n let version = Self.apiVersion(from: data) ?? \"unknown\"\n webURL = localURL\n status = .live(\"Running embedded SgodAI Core Engine \\(version).\")\n reloadToken += 1\n } catch {\n if backendProcess != nil {\n try? await Task.sleep(for: .milliseconds(700))\n if await retryHealthCheck() {\n return\n }\n }\n if let staticURL = Bundle.main.url(forResource: \"index\", withExtension: \"html\", subdirectory: \"public\") {\n webURL = staticURL\n status = .staticFallback\n reloadToken += 1\n } else {\n status = .unavailable(\"Local API unavailable and bundled public/index.html was not found.\")\n }\n }\n }\n\n private func retryHealthCheck() async -> Bool {\n for _ in 0..<8 {\n do {\n var request = URLRequest(url: healthURL)\n request.timeoutInterval = 1.5\n let (data, response) = try await URLSession.shared.data(for: request)\n guard let http = response as? HTTPURLResponse, (200..<300).contains(http.statusCode) else {\n throw URLError(.badServerResponse)\n }\n let version = Self.apiVersion(from: data) ?? \"unknown\"\n webURL = localURL\n status = .live(\"Running embedded SgodAI Core Engine \\(version).\")\n reloadToken += 1\n return true\n } catch {\n try? await Task.sleep(for: .milliseconds(550))\n }\n }\n return false\n }\n\n private func startBundledBackendIfNeeded() {\n if backendProcess?.isRunning == true {\n return\n }\n guard let executable = Bundle.main.url(forResource: \"sgodai-backend\", withExtension: nil, subdirectory: \"backend\") else {\n return\n }\n\n let support = applicationSupportDirectory()\n let dataDir = support.appendingPathComponent(\"data\", isDirectory: true)\n let logsDir = support.appendingPathComponent(\"logs\", isDirectory: true)\n let envFile = support.appendingPathComponent(\".env\")\n try? FileManager.default.createDirectory(at: dataDir, withIntermediateDirectories: true)\n try? FileManager.default.createDirectory(at: logsDir, withIntermediateDirectories: true)\n createEnvPlaceholderIfNeeded(at: envFile)\n\n let process = Process()\n process.executableURL = executable\n process.currentDirectoryURL = Bundle.main.resourceURL\n process.environment = backendEnvironment(dataDir: dataDir, envFile: envFile)\n\n let logURL = logsDir.appendingPathComponent(\"backend.log\")\n if !FileManager.default.fileExists(atPath: logURL.path) {\n FileManager.default.createFile(atPath: logURL.path, contents: nil)\n }\n if let logHandle = try? FileHandle(forWritingTo: logURL) {\n _ = try? logHandle.seekToEnd()\n process.standardOutput = logHandle\n process.standardError = logHandle\n }\n\n do {\n try process.run()\n backendProcess = process\n } catch {\n status = .unavailable(\"Embedded backend failed to start: \\(error.localizedDescription)\")\n }\n }\n\n private func backendEnvironment(dataDir: URL, envFile: URL) -> [String: String] {\n var env = ProcessInfo.processInfo.environment\n env[\"SGODAI_HOST\"] = \"127.0.0.1\"\n env[\"SGODAI_PORT\"] = String(port)\n env[\"SGODAI_PUBLIC_DIR\"] = Bundle.main.resourceURL?.appendingPathComponent(\"public\").path\n env[\"SGODAI_CONFIG_DIR\"] = Bundle.main.resourceURL?.appendingPathComponent(\"configs\").path\n env[\"SGODAI_DATA_DIR\"] = dataDir.path\n env[\"SGODAI_DB_PATH\"] = dataDir.appendingPathComponent(\"sgodai.sqlite\").path\n env[\"SGODAI_ENV_FILE\"] = envFile.path\n env[\"SGODAI_LOG_LEVEL\"] = \"info\"\n env[\"PYTHONUNBUFFERED\"] = \"1\"\n return env\n }\n\n private func applicationSupportDirectory() -> URL {\n let base = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0]\n let directory = base.appendingPathComponent(\"SgodAI\", isDirectory: true)\n try? FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)\n return directory\n }\n\n private func createEnvPlaceholderIfNeeded(at url: URL) {\n guard !FileManager.default.fileExists(atPath: url.path) else { return }\n let template = \"\"\"\n # SgodAI desktop environment.\n # Fill these when you need DeepSeek or email from the installed app.\n DEEPSEEK_API_KEY=\n SMTP_HOST=smtp.qq.com\n SMTP_PORT=465\n SMTP_USE_SSL=true\n SMTP_USERNAME=\n SMTP_PASSWORD=\n SMTP_FROM=\n SMTP_FROM_NAME=SgodAI Market Radar\n \"\"\"\n try? template.write(to: url, atomically: true, encoding: .utf8)\n }\n\n private static func apiVersion(from data: Data) -> String? {\n guard\n let root = try? JSONSerialization.jsonObject(with: data) as? [String: Any],\n let components = root[\"components\"] as? [String: Any],\n let api = components[\"api\"] as? [String: Any],\n let version = api[\"version\"] as? String\n else {\n return nil\n }\n return version\n }\n\n deinit {\n backendProcess?.terminate()\n }\n}\n"}, "8b41c92ee3dcf950715c36fd40c81cfb542a8ca9": {"t": 1785757708.5032816, "n": 8166, "h": "f7b2861daedd32d1", "c": "import Foundation\nimport SwiftUI\n\n@MainActor\nfinal class LocalBackend: ObservableObject {\n enum Status {\n case checking\n case live(String)\n case staticFallback\n case unavailable(String)\n\n var title: String {\n switch self {\n case .checking:\n return \"Checking\"\n case .live:\n return \"Embedded API\"\n case .staticFallback:\n return \"Static Demo\"\n case .unavailable:\n return \"Offline\"\n }\n }\n\n var detail: String {\n switch self {\n case .checking:\n return \"Checking the local SgodAI API.\"\n case .live(let message):\n return message\n case .staticFallback:\n return \"The local API is not running; the bundled static interface is loaded.\"\n case .unavailable(let message):\n return message\n }\n }\n\n var symbol: String {\n switch self {\n case .checking:\n return \"clock\"\n case .live:\n return \"checkmark.circle\"\n case .staticFallback:\n return \"rectangle.on.rectangle\"\n case .unavailable:\n return \"exclamationmark.triangle\"\n }\n }\n\n var color: Color {\n switch self {\n case .checking:\n return .secondary\n case .live:\n return .green\n case .staticFallback:\n return .orange\n case .unavailable:\n return .red\n }\n }\n }\n\n @Published var status: Status = .checking\n @Published var isChecking = false\n @Published var reloadToken = 0\n @Published var webURL = URL(string: \"http://127.0.0.1:18765/\")!\n\n private let port = 18765\n private let localURL = URL(string: \"http://127.0.0.1:18765/\")!\n private let healthURL = URL(string: \"http://127.0.0.1:18765/api/system/health-check\")!\n private var backendProcess: Process?\n\n func bootstrap() async {\n startBundledBackendIfNeeded()\n await checkHealth()\n }\n\n func checkHealth() async {\n isChecking = true\n status = .checking\n defer { isChecking = false }\n\n do {\n var request = URLRequest(url: healthURL)\n request.timeoutInterval = 2.5\n let (data, response) = try await URLSession.shared.data(for: request)\n guard let http = response as? HTTPURLResponse, (200..<300).contains(http.statusCode) else {\n throw URLError(.badServerResponse)\n }\n let version = Self.apiVersion(from: data) ?? \"unknown\"\n webURL = localURL\n status = .live(\"Running embedded SgodAI Core Engine \\(version).\")\n reloadToken += 1\n } catch {\n if backendProcess != nil {\n try? await Task.sleep(for: .milliseconds(700))\n if await retryHealthCheck() {\n return\n }\n }\n if let staticURL = Bundle.main.url(forResource: \"index\", withExtension: \"html\", subdirectory: \"public\") {\n webURL = staticURL\n status = .staticFallback\n reloadToken += 1\n } else {\n status = .unavailable(\"Local API unavailable and bundled public/index.html was not found.\")\n }\n }\n }\n\n private func retryHealthCheck() async -> Bool {\n for _ in 0..<8 {\n do {\n var request = URLRequest(url: healthURL)\n request.timeoutInterval = 1.5\n let (data, response) = try await URLSession.shared.data(for: request)\n guard let http = response as? HTTPURLResponse, (200..<300).contains(http.statusCode) else {\n throw URLError(.badServerResponse)\n }\n let version = Self.apiVersion(from: data) ?? \"unknown\"\n webURL = localURL\n status = .live(\"Running embedded SgodAI Core Engine \\(version).\")\n reloadToken += 1\n return true\n } catch {\n try? await Task.sleep(for: .milliseconds(550))\n }\n }\n return false\n }\n\n private func startBundledBackendIfNeeded() {\n if backendProcess?.isRunning == true {\n return\n }\n guard let executable = Bundle.main.url(forResource: \"sgodai-backend\", withExtension: nil, subdirectory: \"backend\") else {\n return\n }\n\n let support = applicationSupportDirectory()\n let dataDir = support.appendingPathComponent(\"data\", isDirectory: true)\n let logsDir = support.appendingPathComponent(\"logs\", isDirectory: true)\n let envFile = support.appendingPathComponent(\".env\")\n try? FileManager.default.createDirectory(at: dataDir, withIntermediateDirectories: true)\n try? FileManager.default.createDirectory(at: logsDir, withIntermediateDirectories: true)\n createEnvPlaceholderIfNeeded(at: envFile)\n\n let process = Process()\n process.executableURL = executable\n process.currentDirectoryURL = Bundle.main.resourceURL\n process.environment = backendEnvironment(dataDir: dataDir, envFile: envFile)\n\n let logURL = logsDir.appendingPathComponent(\"backend.log\")\n if !FileManager.default.fileExists(atPath: logURL.path) {\n FileManager.default.createFile(atPath: logURL.path, contents: nil)\n }\n if let logHandle = try? FileHandle(forWritingTo: logURL) {\n _ = try? logHandle.seekToEnd()\n process.standardOutput = logHandle\n process.standardError = logHandle\n }\n\n do {\n try process.run()\n backendProcess = process\n } catch {\n status = .unavailable(\"Embedded backend failed to start: \\(error.localizedDescription)\")\n }\n }\n\n private func backendEnvironment(dataDir: URL, envFile: URL) -> [String: String] {\n var env = ProcessInfo.processInfo.environment\n env[\"SGODAI_HOST\"] = \"127.0.0.1\"\n env[\"SGODAI_PORT\"] = String(port)\n env[\"SGODAI_PUBLIC_DIR\"] = Bundle.main.resourceURL?.appendingPathComponent(\"public\").path\n env[\"SGODAI_CONFIG_DIR\"] = Bundle.main.resourceURL?.appendingPathComponent(\"configs\").path\n env[\"SGODAI_DATA_DIR\"] = dataDir.path\n env[\"SGODAI_DB_PATH\"] = dataDir.appendingPathComponent(\"sgodai.sqlite\").path\n env[\"SGODAI_ENV_FILE\"] = envFile.path\n env[\"SGODAI_LOG_LEVEL\"] = \"info\"\n env[\"PYTHONUNBUFFERED\"] = \"1\"\n return env\n }\n\n private func applicationSupportDirectory() -> URL {\n let base = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0]\n let directory = base.appendingPathComponent(\"SgodAI\", isDirectory: true)\n try? FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)\n return directory\n }\n\n private func createEnvPlaceholderIfNeeded(at url: URL) {\n guard !FileManager.default.fileExists(atPath: url.path) else { return }\n let template = \"\"\"\n # SgodAI desktop environment.\n # Fill these when you need DeepSeek or email from the installed app.\n DEEPSEEK_API_KEY=\n SMTP_HOST=smtp.qq.com\n SMTP_PORT=465\n SMTP_USE_SSL=true\n SMTP_USERNAME=\n SMTP_PASSWORD=\n SMTP_FROM=\n SMTP_FROM_NAME=SgodAI Market Radar\n \"\"\"\n try? template.write(to: url, atomically: true, encoding: .utf8)\n }\n\n private static func apiVersion(from data: Data) -> String? {\n guard\n let root = try? JSONSerialization.jsonObject(with: data) as? [String: Any],\n let components = root[\"components\"] as? [String: Any],\n let api = components[\"api\"] as? [String: Any],\n let version = api[\"version\"] as? String\n else {\n return nil\n }\n return version\n }\n\n deinit {\n backendProcess?.terminate()\n }\n}\n"}, "01bee09e779630676845303bebeb3a5dea2f5478": {"t": 1785757709.8008544, "n": 3597, "h": "790fafd660d2166b", "c": "import Foundation\nimport SwiftUI\n\n@MainActor\nfinal class LocalBackend: ObservableObject {\n enum Status {\n case checking\n case live(String)\n case staticFallback\n case unavailable(String)\n\n var title: String {\n switch self {\n case .checking:\n return \"Checking\"\n case .live:\n return \"Local API\"\n case .staticFallback:\n return \"Static Demo\"\n case .unavailable:\n return \"Offline\"\n }\n }\n\n var detail: String {\n switch self {\n case .checking:\n return \"Checking the local SgodAI API.\"\n case .live(let message):\n return message\n case .staticFallback:\n return \"The local API is not running; the bundled static interface is loaded.\"\n case .unavailable(let message):\n return message\n }\n }\n\n var symbol: String {\n switch self {\n case .checking:\n return \"clock\"\n case .live:\n return \"checkmark.circle\"\n case .staticFallback:\n return \"rectangle.on.rectangle\"\n case .unavailable:\n return \"exclamationmark.triangle\"\n }\n }\n\n var color: Color {\n switch self {\n case .checking:\n return .secondary\n case .live:\n return .green\n case .staticFallback:\n return .orange\n case .unavailable:\n return .red\n }\n }\n }\n\n @Published var status: Status = .checking\n @Published var isChecking = false\n @Published var reloadToken = 0\n @Published var webURL = URL(string: \"http://127.0.0.1:8000/\")!\n\n private let localURL = URL(string: \"http://127.0.0.1:8000/\")!\n private let healthURL = URL(string: \"http://127.0.0.1:8000/api/system/health-check\")!\n\n func bootstrap() async {\n await checkHealth()\n }\n\n func checkHealth() async {\n isChecking = true\n status = .checking\n defer { isChecking = false }\n\n do {\n var request = URLRequest(url: healthURL)\n request.timeoutInterval = 2.5\n let (data, response) = try await URLSession.shared.data(for: request)\n guard let http = response as? HTTPURLResponse, (200..<300).contains(http.statusCode) else {\n throw URLError(.badServerResponse)\n }\n let version = Self.apiVersion(from: data) ?? \"unknown\"\n webURL = localURL\n status = .live(\"Connected to SgodAI local API \\(version).\")\n reloadToken += 1\n } catch {\n if let staticURL = Bundle.main.url(forResource: \"index\", withExtension: \"html\", subdirectory: \"public\") {\n webURL = staticURL\n status = .staticFallback\n reloadToken += 1\n } else {\n status = .unavailable(\"Local API unavailable and bundled public/index.html was not found.\")\n }\n }\n }\n\n private static func apiVersion(from data: Data) -> String? {\n guard\n let root = try? JSONSerialization.jsonObject(with: data) as? [String: Any],\n let components = root[\"components\"] as? [String: Any],\n let api = components[\"api\"] as? [String: Any],\n let version = api[\"version\"] as? String\n else {\n return nil\n }\n return version\n }\n}\n"}}}}