Created
February 1, 2026 06:44
-
-
Save AkkeyLab/9b7a372709d68249dbeb05837d1dbf46 to your computer and use it in GitHub Desktop.
Example implementation of Foundation Models extracted from a real product
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // ContentView.swift | |
| // PersonaAnywhere | |
| // | |
| // Created by AkkeyLab on 2024/03/16. | |
| // | |
| // ⚠️ This file is provided for the purpose of sharing a practical example of using Foundation Models. | |
| // It contains code extracted from a real-world product and is not intended to function independently. | |
| import FoundationModels | |
| import OSLog | |
| import SwiftUI | |
| struct ContentView: View { | |
| @State private var troubleshootingAdvice: TroubleshootingAdvice? | |
| @State private var isAnalyzing: Bool = false | |
| var body: some View { | |
| Text("Foundation Models Sample") | |
| } | |
| private func analyzeLogsWithLLM() async { | |
| #if DEBUG | |
| debugPrint("Starting log analysis with LLM") | |
| #endif | |
| isAnalyzing = true | |
| defer { | |
| isAnalyzing = false | |
| } | |
| guard let store = try? OSLogStore(scope: .currentProcessIdentifier) else { | |
| return | |
| } | |
| let position = store.position(timeIntervalSinceLatestBoot: TimeInterval(-60)) | |
| guard let entries = try? store.getEntries(at: position) else { | |
| return | |
| } | |
| let logEntries = entries.compactMap { $0 as? OSLogEntryLog } | |
| guard !logEntries.isEmpty else { return } | |
| let networkStatus = await getNetworkStatus() | |
| let formattedLogText = logEntries | |
| .filter { [.info, .error, .fault].contains($0.level) } | |
| .sorted { $0.level.rawValue > $1.level.rawValue } | |
| .prefix(10) | |
| .map { log -> String in | |
| let level = switch log.level { | |
| case .error: "E" | |
| case .fault: "F" | |
| default: "I" | |
| } | |
| return "[\(level)]\(log.category):\(log.composedMessage.prefix(80))" | |
| } | |
| .joined(separator: "\n") | |
| let sessionStateText = switch sessionState { | |
| case .connecting: "connecting" | |
| case .connected: "connected" | |
| default: "disconnected" | |
| } | |
| let peerCount = sessionContainer.connectedPeers.count | |
| let prompt = """ | |
| Status:\(sessionStateText),Peers:\(peerCount),\(networkStatus) | |
| Logs: | |
| \(formattedLogText) | |
| """ | |
| #if DEBUG | |
| debugPrint("LLM Prompt:\n\(prompt)") | |
| #endif | |
| let langName = Locale.current.localizedString( | |
| forLanguageCode: Locale.current.language.languageCode?.identifier ?? "en" | |
| ) ?? "English" | |
| let instructions = Instructions( | |
| """ | |
| Support assistant for PersonaAnywhere (visionOS→Mac video streaming). | |
| USER PROFILE: Complete beginner, no technical knowledge. | |
| LANGUAGE RULES: | |
| - NEVER use: peer, session, protocol, handshake, timeout, buffer, latency, packet, socket, broadcast | |
| - ALWAYS use: Mac, connection, connect/disconnect, waiting, slow, data | |
| STYLE: Short sentences. Friendly tone. Max 2 steps per instruction. | |
| IMPORTANT: Always respond in \(langName) language. | |
| """ | |
| ) | |
| let session = LanguageModelSession(instructions: instructions) | |
| let response = try? await session.respond(to: prompt, generating: TroubleshootingAdvice.self) | |
| if let content = response?.content { | |
| troubleshootingAdvice = content | |
| } | |
| } | |
| private func getNetworkStatus() async -> String { | |
| await withCheckedContinuation { continuation in | |
| let monitor = NWPathMonitor() | |
| let queue = DispatchQueue(label: "network-status") | |
| monitor.pathUpdateHandler = { path in | |
| monitor.cancel() | |
| let status = [ | |
| "Net:\(path.status == .satisfied ? "OK" : "NG")", | |
| "WiFi:\(path.usesInterfaceType(.wifi) ? "Y" : "N")", | |
| "Constrained:\(path.isConstrained ? "Y" : "N")", | |
| ].joined(separator: ",") | |
| continuation.resume(returning: status) | |
| } | |
| monitor.start(queue: queue) | |
| } | |
| } | |
| } | |
| @Generable | |
| struct TroubleshootingAdvice { | |
| @Guide(description: "List of sections. Include only necessary sections (ideally 1-3 sections)", .maximumCount(3)) | |
| var sections: [AdviceSection] | |
| @Generable | |
| struct AdviceSection: Identifiable { | |
| @Guide(description: "Section title. (e.g., 'First, try this', 'If the issue persists', 'Workaround', 'Contact support')") | |
| var title: String | |
| @Guide(description: "Section body. Use • for bullets. Plain text only. Max 200 chars.") | |
| var content: String | |
| @Guide(description: "Section type indicating the priority and purpose of this advice.") | |
| var type: AdviceType | |
| @Generable | |
| enum AdviceType: String { | |
| case tryThis = "try_this" | |
| case ifNotFixed = "if_not_fixed" | |
| case workaround = "workaround" | |
| case contactSupport = "contact_support" | |
| } | |
| } | |
| } | |
| extension TroubleshootingAdvice.AdviceSection: Hashable { | |
| var id: String { hashValue.description } | |
| } | |
| #Preview(windowStyle: .automatic) { | |
| ContentView() | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment