// NotesGenerator.swift // Handles AI-powered note generation using OpenAI import Foundation import OpenAI /// Generates meeting notes using OpenAI API class NotesGenerator { static let shared = NotesGenerator() private init() {} /// Generates meeting notes from transcript and user notes /// - Parameters: /// - transcript: The meeting transcript /// - userNotes: Additional notes from the user /// - userBlurb: Information about the user for context /// - systemPrompt: The system prompt for AI generation /// - Returns: Generated meeting notes func generateNotes(transcript: String, userNotes: String, userBlurb: String, systemPrompt: String) async throws -> String { guard let apiKey = KeychainHelper.shared.get(forKey: "openAIKey"), !apiKey.isEmpty else { throw NSError(domain: "NotesGenerator", code: 1, userInfo: [NSLocalizedDescriptionKey: "OpenAI API key not configured"]) } let openAI = OpenAI(apiToken: apiKey) // Compose system prompt with user blurb wrapped in XML tags for clarity let systemContent = "\(systemPrompt)\n\n\n\(userBlurb)\n" let systemMessage = ChatQuery.ChatCompletionMessageParam(role: .system, content: systemContent)! // Provide the model with structured XML-tagged input variables for improved parsing let userContent = "Generate concise and well-structured meeting notes using the information below.\n\n\n\(transcript)\n\n\n\n\(userNotes)\n" let userMessage = ChatQuery.ChatCompletionMessageParam(role: .user, content: userContent)! let query = ChatQuery(messages: [systemMessage, userMessage], model: .gpt4_1_mini) let result = try await openAI.chats(query: query) guard let generatedNotes = result.choices.first?.message.content else { throw NSError(domain: "NotesGenerator", code: 2, userInfo: [NSLocalizedDescriptionKey: "Failed to generate notes"]) } return generatedNotes } /// Validates if OpenAI API key is configured /// - Returns: True if API key exists, false otherwise func isConfigured() -> Bool { guard let key = KeychainHelper.shared.get(forKey: "openAIKey"), !key.isEmpty else { return false } return true } }