[
  {
    "path": ".gitignore",
    "content": ".DS_Store\n*.swp\ntags\nxcshareddata\nproject.xcworkspace\n.ackrc\n*.codekit3\n\n# Xcode\n#\n# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore\n\n## User settings\nxcuserdata/\n\n## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)\n*.xcscmblueprint\n*.xccheckout\n\n## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)\nbuild/\nDerivedData/\n*.moved-aside\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\n\n## Obj-C/Swift specific\n*.hmap\n\n## App packaging\n*.ipa\n*.dSYM.zip\n*.dSYM\n\n## Playgrounds\ntimeline.xctimeline\nplayground.xcworkspace\n\n# Swift Package Manager\n#\n# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.\n# Packages/\n# Package.pins\n# Package.resolved\n# *.xcodeproj\n#\n# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata\n# hence it is not needed unless you have added a package configuration file to your project\n# .swiftpm\n\n.build/\n\n# CocoaPods\n#\n# We recommend against adding the Pods directory to your .gitignore. However\n# you should judge for yourself, the pros and cons are mentioned at:\n# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control\n#\n# Pods/\n#\n# Add this line if you want to avoid checking in source code from the Xcode workspace\n# *.xcworkspace\n\n# Carthage\n#\n# Add this line if you want to avoid checking in source code from Carthage dependencies.\n# Carthage/Checkouts\n\nCarthage/Build/\n\n# Accio dependency management\nDependencies/\n.accio/\n\n# fastlane\n#\n# It is recommended to not store the screenshots in the git repo.\n# Instead, use fastlane to re-generate the screenshots whenever they are needed.\n# For more information about the recommended setup visit:\n# https://docs.fastlane.tools/best-practices/source-control/#source-control\n\nfastlane/report.xml\nfastlane/Preview.html\nfastlane/screenshots/**/*.png\nfastlane/test_output\n\n# Code Injection\n#\n# After new code Injection tools there's a generated folder /iOSInjectionProject\n# https://github.com/johnno1962/injectionforxcode\n\niOSInjectionProject/\n"
  },
  {
    "path": "AIProxyAnthropic/AIProxyAnthropic/AIProxyAnthropicApp.swift",
    "content": "//\n//  AIProxyAnthropicApp.swift\n//  AIProxyAnthropic\n//\n//  Created by Todd Hamilton on 6/17/24.\n//\n\nimport SwiftUI\n\n@main\nstruct AIProxyAnthropicApp: App {\n    var body: some Scene {\n        WindowGroup {\n            ContentView()\n        }\n    }\n}\n"
  },
  {
    "path": "AIProxyAnthropic/AIProxyAnthropic/AppConstants.swift",
    "content": "//\n//  AppConstants.swift\n//  AIProxyAnthropic\n//\n//  Created by Todd Hamilton on 8/14/24.\n//\n\nimport AIProxy\n\n#error(\n    \"\"\"\n    Uncomment one of the methods below. To build and run on device you must follow the AIProxy integration guide.\n    Please see https://www.aiproxy.pro/docs/integration-guide.html\")\n    \"\"\"\n)\n\n/* Uncomment for BYOK use cases */\nlet anthropicService = AIProxy.anthropicDirectService(\n    unprotectedAPIKey: \"your-anthropic-key\"\n)\n\n/* Uncomment for all other production use cases */\n//let anthropicService = AIProxy.anthropicService(\n//    partialKey: \"partial-key-from-your-developer-dashboard\",\n//    serviceURL: \"service-url-from-your-developer-dashboard\"\n//)\n"
  },
  {
    "path": "AIProxyAnthropic/AIProxyAnthropic/Assets.xcassets/AccentColor.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyAnthropic/AIProxyAnthropic/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyAnthropic/AIProxyAnthropic/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyAnthropic/AIProxyAnthropic/Assets.xcassets/anthropic.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"anthropic.jpeg\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyAnthropic/AIProxyAnthropic/Assets.xcassets/climber.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"climber.jpg\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyAnthropic/AIProxyAnthropic/ContentView.swift",
    "content": "//\n//  ContentView.swift\n//  AIProxyAnthropic\n//\n//  Created by Todd Hamilton on 6/17/24.\n//\n\nimport SwiftUI\n\nstruct ContentView: View {\n    var body: some View {\n        NavigationStack{\n            \n            VStack(spacing:24){\n                VStack{\n                    Image(\"anthropic\")\n                        .resizable()\n                        .scaledToFit()\n                        .frame(width: /*@START_MENU_TOKEN@*/100/*@END_MENU_TOKEN@*/)\n                        .cornerRadius(14)\n                        .foregroundColor(.primary)\n                    Text(\"Anthropic\")\n                        .bold()\n                        .font(.largeTitle)\n                    Text(\"AIProxy Sample\")\n                        .font(.subheadline)\n                        .foregroundColor(.secondary)\n                }\n                .frame(maxWidth:.infinity,alignment:.center)\n                \n                VStack{\n                    NavigationLink(\"Message Request Example\",destination: MessageRequestView())\n                        .bold()\n                        .controlSize(.large)\n                        .tint(.brown)\n                        .buttonStyle(.bordered)\n                    NavigationLink(\"Vision Example\",destination: VisionView())\n                        .bold()\n                        .controlSize(.large)\n                        .tint(.brown)\n                        .buttonStyle(.bordered)\n                    NavigationLink(\"Tools Example\",destination: ToolsView())\n                        .bold()\n                        .controlSize(.large)\n                        .tint(.brown)\n                        .buttonStyle(.bordered)\n                }\n            }\n        }\n    }\n}\n\n#Preview {\n    ContentView()\n}\n"
  },
  {
    "path": "AIProxyAnthropic/AIProxyAnthropic/MessageRequestView.swift",
    "content": "//\n//  MessageRequestView.swift\n//  AIProxyAnthropic\n//\n//  Created by Todd Hamilton on 8/14/24.\n//\n\nimport SwiftUI\nimport AIProxy\n\nstruct MessageRequestView: View {\n    \n    @State private var prompt = \"\"\n    @State private var result = \"\"\n    @State private var isLoading = false\n    @State private var showingAlert = false\n    \n    func generate() async throws {\n        isLoading = true\n        defer { isLoading = false }\n        do {\n            let response = try await anthropicService.messageRequest(body: AnthropicMessageRequestBody(\n                maxTokens: 1024,\n                messages: [\n                    AnthropicInputMessage(content: [.text(prompt)], role: .user)\n                ],\n                model: \"claude-3-5-sonnet-20240620\"\n            ))\n            for content in response.content {\n                switch content {\n                case .text(let message):\n                    print(\"Claude sent a message: \\(message)\")\n                    result = message\n                    showingAlert = true\n                case .toolUse(id: _, name: let toolName, input: let toolInput):\n                    print(\"Claude used a tool \\(toolName) with input: \\(toolInput)\")\n                }\n            }\n        }  catch AIProxyError.unsuccessfulRequest(let statusCode, let responseBody) {\n            print(\"Received non-200 status code: \\(statusCode) with response body: \\(responseBody)\")\n        } catch {\n            print(error.localizedDescription)\n        }\n    }\n    \n    var body: some View {\n        VStack {\n            VStack{\n                ContentUnavailableView(\n                    \"Generate Message\",\n                    systemImage: \"doc.plaintext.fill\",\n                    description: Text(\"Write a prompt below\")\n                )\n            }\n            .alert(isPresented: $showingAlert) {\n                Alert(\n                    title: Text(\"Result\"),\n                    message: Text(result),\n                    dismissButton: .default(Text(\"Close\"))\n                )\n            }\n\n            Spacer()\n            \n            VStack(spacing:12){\n                TextField(\"Type a prompt\", text:$prompt)\n                    .submitLabel(.go)\n                    .padding(12)\n                    .background(Color(.systemBackground))\n                    .cornerRadius(8)\n                    .shadow(color:.primary, radius: 1)\n                    .onSubmit {\n                        Task{ try await generate() }\n                    }\n                Button{\n                    Task{ try await generate() }\n                }label:{\n                    if isLoading {\n                        ProgressView()\n                            .controlSize(.regular)\n                            .frame(maxWidth:.infinity)\n                    } else {\n                        Text(\"Generate Message\")\n                            .bold()\n                            .frame(maxWidth:.infinity)\n                    }\n                }\n                .controlSize(.large)\n                .buttonStyle(.borderedProminent)\n                .disabled(isLoading ? true : false)\n            }\n        }\n        .padding()\n        .navigationTitle(\"Message Example\")\n        .navigationBarTitleDisplayMode(.inline)\n    }\n}\n\n#Preview {\n    MessageRequestView()\n}\n"
  },
  {
    "path": "AIProxyAnthropic/AIProxyAnthropic/Preview Content/Preview Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyAnthropic/AIProxyAnthropic/ToolsView.swift",
    "content": "//\n//  ToolsView.swift\n//  AIProxyAnthropic\n//\n//  Created by Todd Hamilton on 8/14/24.\n//\n\nimport SwiftUI\nimport AIProxy\n\nstruct ToolsView: View {\n    \n    @State private var prompt = \"\"\n    @State private var result = \"\"\n    @State private var isLoading = false\n    @State private var showingAlert = false\n    \n    var body: some View {\n        VStack {\n            VStack{\n                ContentUnavailableView(\n                    \"Stock Symbol Lookup\",\n                    systemImage: \"chart.line.uptrend.xyaxis\",\n                    description: Text(\"Type the name of the company you want the symbol for.\")\n                )\n            }\n            .alert(isPresented: $showingAlert) {\n                Alert(\n                    title: Text(\"Result\"),\n                    message: Text(result),\n                    dismissButton: .default(Text(\"Close\"))\n                )\n            }\n\n            Spacer()\n            \n            VStack(spacing:12){\n                TextField(\"Type a company\", text:$prompt)\n                    .submitLabel(.go)\n                    .padding(12)\n                    .background(Color(.systemBackground))\n                    .cornerRadius(8)\n                    .shadow(color:.primary, radius: 1)\n                    .onSubmit {\n                        Task{ try await generate() }\n                    }\n                Button{\n                    Task{ try await generate() }\n                }label:{\n                    if isLoading {\n                        ProgressView()\n                            .controlSize(.regular)\n                            .frame(maxWidth:.infinity)\n                    } else {\n                        Text(\"Look Up\")\n                            .bold()\n                            .frame(maxWidth:.infinity)\n                    }\n                }\n                .controlSize(.large)\n                .buttonStyle(.borderedProminent)\n                .disabled(isLoading ? true : false)\n            }\n        }\n        .padding()\n        .navigationTitle(\"Tools Example\")\n        .navigationBarTitleDisplayMode(.inline)\n    }\n    \n    func generate() async throws {\n        isLoading = true\n        defer { isLoading = false }\n        do {\n            let requestBody = AnthropicMessageRequestBody(\n                maxTokens: 1024,\n                messages: [\n                    .init(\n                        content: [.text(prompt)],\n                        role: .user\n                    )\n                ],\n                model: \"claude-3-5-sonnet-20240620\",\n                tools: [\n                    .init(\n                        description: \"Call this function when the user wants a stock symbol\",\n                        inputSchema: [\n                            \"type\": \"object\",\n                            \"properties\": [\n                                \"ticker\": [\n                                    \"type\": \"string\",\n                                    \"description\": \"The stock ticker symbol, e.g. AAPL for Apple Inc.\"\n                                ]\n                            ],\n                            \"required\": [\"ticker\"]\n                        ],\n                        name: \"get_stock_symbol\"\n                    )\n                ]\n            )\n            let response = try await anthropicService.messageRequest(body: requestBody)\n            \n            for content in response.content {\n                switch content {\n                case .text(let message):\n                    print(\"Claude sent a message: \\(message)\")\n                case .toolUse(id: _, name: let toolName, input: let toolInput):\n                    print(\"Claude used a tool \\(toolName) with input: \\(toolInput)\")\n                    result = toolInput.description\n                    showingAlert = true\n                }\n            }\n        }  catch AIProxyError.unsuccessfulRequest(let statusCode, let responseBody) {\n            print(\"Received non-200 status code: \\(statusCode) with response body: \\(responseBody)\")\n        } catch {\n            print(error.localizedDescription)\n        }\n    }\n}\n\n#Preview {\n    ToolsView()\n}\n"
  },
  {
    "path": "AIProxyAnthropic/AIProxyAnthropic/VisionView.swift",
    "content": "//\n//  VisionView.swift\n//  AIProxyAnthropic\n//\n//  Created by Todd Hamilton on 8/14/24.\n//\n\nimport SwiftUI\nimport AIProxy\n\nstruct VisionView: View {\n    \n    @State private var prompt:String = \"\"\n    @State private var result:String = \"\"\n    @State private var showingAlert = false\n    @State private var isLoading = false\n    \n    func generate() async throws {\n        \n        guard let image = UIImage(named: \"climber\") else {\n            print(\"Could not find an image named 'climber' in your app assets\")\n            return\n        }\n\n        guard let jpegData = AIProxy.encodeImageAsJpeg(image: image, compressionQuality: 0.8) else {\n            print(\"Could not convert image to jpeg\")\n            return\n        }\n        \n        isLoading = true\n        defer { isLoading = false }\n        do {\n            let response = try await anthropicService.messageRequest(body: AnthropicMessageRequestBody(\n                maxTokens: 1024,\n                messages: [\n                    AnthropicInputMessage(content: [\n                        .text(\"Provide a very short description of this image\"),\n                        .image(mediaType: .jpeg, data: jpegData.base64EncodedString())\n                    ], role: .user)\n                ],\n                model: \"claude-3-5-sonnet-20240620\"\n            ))\n            for content in response.content {\n                switch content {\n                case .text(let message):\n                    print(\"Claude sent a message: \\(message)\")\n                    result = message\n                    showingAlert = true\n                case .toolUse(id: _, name: let toolName, input: let toolInput):\n                    print(\"Claude used a tool \\(toolName) with input: \\(toolInput)\")\n                }\n            }\n        }  catch AIProxyError.unsuccessfulRequest(let statusCode, let responseBody) {\n            print(\"Received non-200 status code: \\(statusCode) with response body: \\(responseBody)\")\n        } catch {\n            print(error.localizedDescription)\n        }\n    }\n    \n    var body: some View {\n        VStack{\n            VStack{\n                Image(\"climber\")\n                    .resizable()\n                    .scaledToFit()\n                    .frame(maxWidth: .infinity)\n            }\n            .frame(maxHeight: .infinity)\n            .alert(isPresented: $showingAlert){\n                Alert(\n                    title: Text(\"Result\"),\n                    message: Text(\"\\(result)\"),\n                    dismissButton: .default(Text(\"Close\"))\n                )\n            }\n            \n            Spacer()\n            \n            VStack(spacing:12){\n                Button{\n                    Task {\n                        try await generate()\n                    }\n                }label: {\n                    if isLoading {\n                        ProgressView()\n                            .controlSize(.regular)\n                            .frame(maxWidth:.infinity)\n                    } else {\n                        Text(\"Describe Image\")\n                            .bold()\n                            .frame(maxWidth:.infinity)\n                    }\n                }\n                .controlSize(.large)\n                .buttonStyle(.borderedProminent)\n                .disabled(isLoading ? true : false)\n            }\n        }\n        .padding()\n        .navigationTitle(\"Vision Example\")\n        .navigationBarTitleDisplayMode(.inline)\n    }\n}\n\n#Preview {\n    VisionView()\n}\n"
  },
  {
    "path": "AIProxyAnthropic/AIProxyAnthropic.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 56;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t2C06E1442C20DFDB0024133C /* AIProxyAnthropicApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C06E1432C20DFDB0024133C /* AIProxyAnthropicApp.swift */; };\n\t\t2C06E1462C20DFDB0024133C /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C06E1452C20DFDB0024133C /* ContentView.swift */; };\n\t\t2C06E1482C20DFDD0024133C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2C06E1472C20DFDD0024133C /* Assets.xcassets */; };\n\t\t2C06E14B2C20DFDD0024133C /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2C06E14A2C20DFDD0024133C /* Preview Assets.xcassets */; };\n\t\t2CCB20382C6D13EE003A8B25 /* AppConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCB20372C6D13EE003A8B25 /* AppConstants.swift */; };\n\t\t2CCB203B2C6D13F4003A8B25 /* AIProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 2CCB203A2C6D13F4003A8B25 /* AIProxy */; };\n\t\t2CCB203D2C6D1464003A8B25 /* MessageRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCB203C2C6D1464003A8B25 /* MessageRequestView.swift */; };\n\t\t2CCB203F2C6D27D9003A8B25 /* VisionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCB203E2C6D27D9003A8B25 /* VisionView.swift */; };\n\t\t2CCB20412C6D3072003A8B25 /* ToolsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCB20402C6D3072003A8B25 /* ToolsView.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t2C06E1402C20DFDB0024133C /* AIProxyAnthropic.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AIProxyAnthropic.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t2C06E1432C20DFDB0024133C /* AIProxyAnthropicApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AIProxyAnthropicApp.swift; sourceTree = \"<group>\"; };\n\t\t2C06E1452C20DFDB0024133C /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = \"<group>\"; };\n\t\t2C06E1472C20DFDD0024133C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t2C06E14A2C20DFDD0024133C /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = \"Preview Assets.xcassets\"; sourceTree = \"<group>\"; };\n\t\t2CCB20372C6D13EE003A8B25 /* AppConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConstants.swift; sourceTree = \"<group>\"; };\n\t\t2CCB203C2C6D1464003A8B25 /* MessageRequestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestView.swift; sourceTree = \"<group>\"; };\n\t\t2CCB203E2C6D27D9003A8B25 /* VisionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisionView.swift; sourceTree = \"<group>\"; };\n\t\t2CCB20402C6D3072003A8B25 /* ToolsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolsView.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t2C06E13D2C20DFDB0024133C /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2CCB203B2C6D13F4003A8B25 /* AIProxy in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t2C06E1372C20DFDB0024133C = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2C06E1422C20DFDB0024133C /* AIProxyAnthropic */,\n\t\t\t\t2C06E1412C20DFDB0024133C /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2C06E1412C20DFDB0024133C /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2C06E1402C20DFDB0024133C /* AIProxyAnthropic.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2C06E1422C20DFDB0024133C /* AIProxyAnthropic */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2C06E1432C20DFDB0024133C /* AIProxyAnthropicApp.swift */,\n\t\t\t\t2C06E1452C20DFDB0024133C /* ContentView.swift */,\n\t\t\t\t2CCB203C2C6D1464003A8B25 /* MessageRequestView.swift */,\n\t\t\t\t2CCB203E2C6D27D9003A8B25 /* VisionView.swift */,\n\t\t\t\t2CCB20402C6D3072003A8B25 /* ToolsView.swift */,\n\t\t\t\t2CCB20372C6D13EE003A8B25 /* AppConstants.swift */,\n\t\t\t\t2C06E1472C20DFDD0024133C /* Assets.xcassets */,\n\t\t\t\t2C06E1492C20DFDD0024133C /* Preview Content */,\n\t\t\t);\n\t\t\tpath = AIProxyAnthropic;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2C06E1492C20DFDD0024133C /* Preview Content */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2C06E14A2C20DFDD0024133C /* Preview Assets.xcassets */,\n\t\t\t);\n\t\t\tpath = \"Preview Content\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t2C06E13F2C20DFDB0024133C /* AIProxyAnthropic */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 2C06E14E2C20DFDD0024133C /* Build configuration list for PBXNativeTarget \"AIProxyAnthropic\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t2C06E13C2C20DFDB0024133C /* Sources */,\n\t\t\t\t2C06E13D2C20DFDB0024133C /* Frameworks */,\n\t\t\t\t2C06E13E2C20DFDB0024133C /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = AIProxyAnthropic;\n\t\t\tpackageProductDependencies = (\n\t\t\t\t2CCB203A2C6D13F4003A8B25 /* AIProxy */,\n\t\t\t);\n\t\t\tproductName = AIProxyAnthropic;\n\t\t\tproductReference = 2C06E1402C20DFDB0024133C /* AIProxyAnthropic.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t2C06E1382C20DFDB0024133C /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = 1;\n\t\t\t\tLastSwiftUpdateCheck = 1540;\n\t\t\t\tLastUpgradeCheck = 1540;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t2C06E13F2C20DFDB0024133C = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 15.4;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 2C06E13B2C20DFDB0024133C /* Build configuration list for PBXProject \"AIProxyAnthropic\" */;\n\t\t\tcompatibilityVersion = \"Xcode 14.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 2C06E1372C20DFDB0024133C;\n\t\t\tpackageReferences = (\n\t\t\t\t2CCB20392C6D13F4003A8B25 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */,\n\t\t\t);\n\t\t\tproductRefGroup = 2C06E1412C20DFDB0024133C /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t2C06E13F2C20DFDB0024133C /* AIProxyAnthropic */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t2C06E13E2C20DFDB0024133C /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2C06E14B2C20DFDD0024133C /* Preview Assets.xcassets in Resources */,\n\t\t\t\t2C06E1482C20DFDD0024133C /* Assets.xcassets in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t2C06E13C2C20DFDB0024133C /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2CCB20412C6D3072003A8B25 /* ToolsView.swift in Sources */,\n\t\t\t\t2CCB203D2C6D1464003A8B25 /* MessageRequestView.swift in Sources */,\n\t\t\t\t2C06E1462C20DFDB0024133C /* ContentView.swift in Sources */,\n\t\t\t\t2CCB20382C6D13EE003A8B25 /* AppConstants.swift in Sources */,\n\t\t\t\t2CCB203F2C6D27D9003A8B25 /* VisionView.swift in Sources */,\n\t\t\t\t2C06E1442C20DFDB0024133C /* AIProxyAnthropicApp.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t2C06E14C2C20DFDD0024133C /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.5;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"DEBUG $(inherited)\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2C06E14D2C20DFDD0024133C /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.5;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t2C06E14F2C20DFDD0024133C /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"AIProxyAnthropic/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 553LMX46SJ;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.toddham.AIProxySampleApp;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2C06E1502C20DFDD0024133C /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"AIProxyAnthropic/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 553LMX46SJ;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.toddham.AIProxySampleApp;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t2C06E13B2C20DFDB0024133C /* Build configuration list for PBXProject \"AIProxyAnthropic\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2C06E14C2C20DFDD0024133C /* Debug */,\n\t\t\t\t2C06E14D2C20DFDD0024133C /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t2C06E14E2C20DFDD0024133C /* Build configuration list for PBXNativeTarget \"AIProxyAnthropic\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2C06E14F2C20DFDD0024133C /* Debug */,\n\t\t\t\t2C06E1502C20DFDD0024133C /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCRemoteSwiftPackageReference section */\n\t\t2CCB20392C6D13F4003A8B25 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/lzell/AIProxySwift\";\n\t\t\trequirement = {\n\t\t\t\tbranch = main;\n\t\t\t\tkind = branch;\n\t\t\t};\n\t\t};\n/* End XCRemoteSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */\n\t\t2CCB203A2C6D13F4003A8B25 /* AIProxy */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 2CCB20392C6D13F4003A8B25 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */;\n\t\t\tproductName = AIProxy;\n\t\t};\n/* End XCSwiftPackageProductDependency section */\n\t};\n\trootObject = 2C06E1382C20DFDB0024133C /* Project object */;\n}\n"
  },
  {
    "path": "AIProxyDeepL/AIProxyDeepL/AIProxyDeepLApp.swift",
    "content": "//\n//  AIProxyDeepLApp.swift\n//  AIProxyDeepL\n//\n//  Created by Todd Hamilton on 8/14/24.\n//\n\nimport SwiftUI\n\n@main\nstruct AIProxyDeepLApp: App {\n    var body: some Scene {\n        WindowGroup {\n            ContentView()\n        }\n    }\n}\n"
  },
  {
    "path": "AIProxyDeepL/AIProxyDeepL/AppConstants.swift",
    "content": "//\n//  AppConstants.swift\n//  AIProxyDeepL\n//\n//  Created by Todd Hamilton on 8/14/24.\n//\n\nimport AIProxy\n\n#error(\n    \"\"\"\n    Uncomment one of the methods below. To build and run on device you must follow the AIProxy integration guide.\n    Please see https://www.aiproxy.pro/docs/integration-guide.html\")\n    \"\"\"\n)\n\n/* Uncomment for BYOK use cases */\nlet deepLService = AIProxy.deepLDirectService(\n    unprotectedAPIKey: \"your-deepL-key\",\n    accountType: .free\n)\n\n/* Uncomment for all other production use cases */\n//let deepLService = AIProxy.deepLService(\n//    partialKey: \"partial-key-from-your-developer-dashboard\",\n//    serviceURL: \"service-url-from-your-developer-dashboard\"\n//)\n"
  },
  {
    "path": "AIProxyDeepL/AIProxyDeepL/Assets.xcassets/AccentColor.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyDeepL/AIProxyDeepL/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyDeepL/AIProxyDeepL/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyDeepL/AIProxyDeepL/Assets.xcassets/deepl.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"deepl.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyDeepL/AIProxyDeepL/ContentView.swift",
    "content": "//\n//  ContentView.swift\n//  AIProxyDeepL\n//\n//  Created by Todd Hamilton on 8/14/24.\n//\n\nimport SwiftUI\n\nstruct ContentView: View {\n    var body: some View {\n        NavigationStack{\n            \n            VStack(spacing:48){\n                VStack{\n                    Image(\"deepl\")\n                        .resizable()\n                        .scaledToFit()\n                        .frame(width: /*@START_MENU_TOKEN@*/100/*@END_MENU_TOKEN@*/)\n                        .cornerRadius(14)\n                        .foregroundColor(.primary)\n                    Text(\"DeepL\")\n                        .bold()\n                        .font(.largeTitle)\n                    Text(\"AIProxy Sample\")\n                        .font(.subheadline)\n                        .foregroundColor(.secondary)\n                }\n                .frame(maxWidth:.infinity,alignment:.center)\n                \n                VStack{\n                    NavigationLink(\"Translation Example\",destination: TranslationView())\n                        .bold()\n                        .controlSize(.large)\n                        .tint(.blue)\n                        .buttonStyle(.bordered)\n                    \n                }\n            }\n        }\n    }\n}\n\n#Preview {\n    ContentView()\n}\n"
  },
  {
    "path": "AIProxyDeepL/AIProxyDeepL/Preview Content/Preview Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyDeepL/AIProxyDeepL/TranslationView.swift",
    "content": "//\n//  TranslationView.swift\n//  AIProxyDeepL\n//\n//  Created by Todd Hamilton on 8/14/24.\n//\n\nimport SwiftUI\nimport AIProxy\n\nstruct TranslationView: View {\n    \n    @State private var prompt = \"\"\n    @State private var result = \"\"\n    @State private var isLoading = false\n    @State private var showingAlert = false\n    \n    func generate() async throws {\n        isLoading = true\n        defer { isLoading = false }\n        do {\n            let body = DeepLTranslateRequestBody(targetLang: \"ES\", text: [prompt])\n            let response = try await deepLService.translateRequest(body: body)\n            // Do something with `response.translations`\n            result = response.translations.first?.text ?? \"\"\n            showingAlert = true\n        }  catch AIProxyError.unsuccessfulRequest(let statusCode, let responseBody) {\n            print(\"Received non-200 status code: \\(statusCode) with response body: \\(responseBody)\")\n        } catch {\n            print(\"Could not create translation: \\(error.localizedDescription)\")\n        }\n    }\n    \n    var body: some View {\n        VStack {\n            VStack{\n                ContentUnavailableView(\n                    \"Translate to Spanish\",\n                    systemImage: \"captions.bubble.fill\",\n                    description: Text(\"Write text you want to translate below\")\n                )\n            }\n            .alert(isPresented: $showingAlert) {\n                Alert(\n                    title: Text(\"Result\"),\n                    message: Text(result),\n                    dismissButton: .default(Text(\"Close\"))\n                )\n            }\n\n            Spacer()\n            \n            VStack(spacing:12){\n                TextField(\"Type your text here\", text:$prompt)\n                    .submitLabel(.go)\n                    .padding(12)\n                    .background(Color(.systemBackground))\n                    .cornerRadius(8)\n                    .shadow(color:.primary, radius: 1)\n                    .onSubmit {\n                        Task{ try await generate() }\n                    }\n                Button{\n                    Task{ try await generate() }\n                }label:{\n                    if isLoading {\n                        ProgressView()\n                            .controlSize(.regular)\n                            .frame(maxWidth:.infinity)\n                    } else {\n                        Text(\"Translate\")\n                            .bold()\n                            .frame(maxWidth:.infinity)\n                    }\n                }\n                .controlSize(.large)\n                .buttonStyle(.borderedProminent)\n                .disabled(isLoading ? true : false)\n            }\n        }\n        .padding()\n        .navigationTitle(\"Translate Example\")\n        .navigationBarTitleDisplayMode(.inline)\n    }\n}\n\n#Preview {\n    TranslationView()\n}\n"
  },
  {
    "path": "AIProxyDeepL/AIProxyDeepL.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 56;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t2CCB204F2C6D5FB8003A8B25 /* AIProxyDeepLApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCB204E2C6D5FB8003A8B25 /* AIProxyDeepLApp.swift */; };\n\t\t2CCB20512C6D5FB8003A8B25 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCB20502C6D5FB8003A8B25 /* ContentView.swift */; };\n\t\t2CCB20532C6D5FBA003A8B25 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2CCB20522C6D5FBA003A8B25 /* Assets.xcassets */; };\n\t\t2CCB20562C6D5FBA003A8B25 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2CCB20552C6D5FBA003A8B25 /* Preview Assets.xcassets */; };\n\t\t2CCB205E2C6D5FC1003A8B25 /* AIProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 2CCB205D2C6D5FC1003A8B25 /* AIProxy */; };\n\t\t2CCB20602C6D6012003A8B25 /* TranslationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCB205F2C6D6012003A8B25 /* TranslationView.swift */; };\n\t\t2CCB20622C6D60B1003A8B25 /* AppConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCB20612C6D60B1003A8B25 /* AppConstants.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t2CCB204B2C6D5FB8003A8B25 /* AIProxyDeepL.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AIProxyDeepL.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t2CCB204E2C6D5FB8003A8B25 /* AIProxyDeepLApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AIProxyDeepLApp.swift; sourceTree = \"<group>\"; };\n\t\t2CCB20502C6D5FB8003A8B25 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = \"<group>\"; };\n\t\t2CCB20522C6D5FBA003A8B25 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t2CCB20552C6D5FBA003A8B25 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = \"Preview Assets.xcassets\"; sourceTree = \"<group>\"; };\n\t\t2CCB205F2C6D6012003A8B25 /* TranslationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranslationView.swift; sourceTree = \"<group>\"; };\n\t\t2CCB20612C6D60B1003A8B25 /* AppConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConstants.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t2CCB20482C6D5FB8003A8B25 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2CCB205E2C6D5FC1003A8B25 /* AIProxy in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t2CCB20422C6D5FB8003A8B25 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CCB204D2C6D5FB8003A8B25 /* AIProxyDeepL */,\n\t\t\t\t2CCB204C2C6D5FB8003A8B25 /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2CCB204C2C6D5FB8003A8B25 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CCB204B2C6D5FB8003A8B25 /* AIProxyDeepL.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2CCB204D2C6D5FB8003A8B25 /* AIProxyDeepL */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CCB204E2C6D5FB8003A8B25 /* AIProxyDeepLApp.swift */,\n\t\t\t\t2CCB20502C6D5FB8003A8B25 /* ContentView.swift */,\n\t\t\t\t2CCB205F2C6D6012003A8B25 /* TranslationView.swift */,\n\t\t\t\t2CCB20612C6D60B1003A8B25 /* AppConstants.swift */,\n\t\t\t\t2CCB20522C6D5FBA003A8B25 /* Assets.xcassets */,\n\t\t\t\t2CCB20542C6D5FBA003A8B25 /* Preview Content */,\n\t\t\t);\n\t\t\tpath = AIProxyDeepL;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2CCB20542C6D5FBA003A8B25 /* Preview Content */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CCB20552C6D5FBA003A8B25 /* Preview Assets.xcassets */,\n\t\t\t);\n\t\t\tpath = \"Preview Content\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t2CCB204A2C6D5FB8003A8B25 /* AIProxyDeepL */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 2CCB20592C6D5FBA003A8B25 /* Build configuration list for PBXNativeTarget \"AIProxyDeepL\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t2CCB20472C6D5FB8003A8B25 /* Sources */,\n\t\t\t\t2CCB20482C6D5FB8003A8B25 /* Frameworks */,\n\t\t\t\t2CCB20492C6D5FB8003A8B25 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = AIProxyDeepL;\n\t\t\tpackageProductDependencies = (\n\t\t\t\t2CCB205D2C6D5FC1003A8B25 /* AIProxy */,\n\t\t\t);\n\t\t\tproductName = AIProxyDeepL;\n\t\t\tproductReference = 2CCB204B2C6D5FB8003A8B25 /* AIProxyDeepL.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t2CCB20432C6D5FB8003A8B25 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = 1;\n\t\t\t\tLastSwiftUpdateCheck = 1540;\n\t\t\t\tLastUpgradeCheck = 1540;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t2CCB204A2C6D5FB8003A8B25 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 15.4;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 2CCB20462C6D5FB8003A8B25 /* Build configuration list for PBXProject \"AIProxyDeepL\" */;\n\t\t\tcompatibilityVersion = \"Xcode 14.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 2CCB20422C6D5FB8003A8B25;\n\t\t\tpackageReferences = (\n\t\t\t\t2CCB205C2C6D5FC1003A8B25 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */,\n\t\t\t);\n\t\t\tproductRefGroup = 2CCB204C2C6D5FB8003A8B25 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t2CCB204A2C6D5FB8003A8B25 /* AIProxyDeepL */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t2CCB20492C6D5FB8003A8B25 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2CCB20562C6D5FBA003A8B25 /* Preview Assets.xcassets in Resources */,\n\t\t\t\t2CCB20532C6D5FBA003A8B25 /* Assets.xcassets in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t2CCB20472C6D5FB8003A8B25 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2CCB20622C6D60B1003A8B25 /* AppConstants.swift in Sources */,\n\t\t\t\t2CCB20602C6D6012003A8B25 /* TranslationView.swift in Sources */,\n\t\t\t\t2CCB20512C6D5FB8003A8B25 /* ContentView.swift in Sources */,\n\t\t\t\t2CCB204F2C6D5FB8003A8B25 /* AIProxyDeepLApp.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t2CCB20572C6D5FBA003A8B25 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.5;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"DEBUG $(inherited)\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2CCB20582C6D5FBA003A8B25 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.5;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t2CCB205A2C6D5FBA003A8B25 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"AIProxyDeepL/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 553LMX46SJ;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.toddham.AIProxySampleApp;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2CCB205B2C6D5FBA003A8B25 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"AIProxyDeepL/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 553LMX46SJ;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.toddham.AIProxySampleApp;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t2CCB20462C6D5FB8003A8B25 /* Build configuration list for PBXProject \"AIProxyDeepL\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2CCB20572C6D5FBA003A8B25 /* Debug */,\n\t\t\t\t2CCB20582C6D5FBA003A8B25 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t2CCB20592C6D5FBA003A8B25 /* Build configuration list for PBXNativeTarget \"AIProxyDeepL\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2CCB205A2C6D5FBA003A8B25 /* Debug */,\n\t\t\t\t2CCB205B2C6D5FBA003A8B25 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCRemoteSwiftPackageReference section */\n\t\t2CCB205C2C6D5FC1003A8B25 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/lzell/AIProxySwift\";\n\t\t\trequirement = {\n\t\t\t\tbranch = main;\n\t\t\t\tkind = branch;\n\t\t\t};\n\t\t};\n/* End XCRemoteSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */\n\t\t2CCB205D2C6D5FC1003A8B25 /* AIProxy */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 2CCB205C2C6D5FC1003A8B25 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */;\n\t\t\tproductName = AIProxy;\n\t\t};\n/* End XCSwiftPackageProductDependency section */\n\t};\n\trootObject = 2CCB20432C6D5FB8003A8B25 /* Project object */;\n}\n"
  },
  {
    "path": "AIProxyFal/AIProxyFal/AIProxyFalApp.swift",
    "content": "//\n//  AIProxyFalApp.swift\n//  AIProxyFal\n//\n//  Created by Todd Hamilton on 6/13/24.\n//\n\nimport SwiftUI\n\n@main\nstruct AIProxyFalApp: App {\n    var body: some Scene {\n        WindowGroup {\n            ContentView()\n        }\n    }\n}\n"
  },
  {
    "path": "AIProxyFal/AIProxyFal/AppConstants.swift",
    "content": "//\n//  AppConstants.swift\n//  AIProxyFal\n//\n//  Created by Todd Hamilton on 9/17/24.\n//\n\nimport AIProxy\n\n#error(\n    \"\"\"\n    Uncomment one of the methods below. To build and run on device you must follow the AIProxy integration guide.\n    Please see https://www.aiproxy.pro/docs/integration-guide.html\")\n    \"\"\"\n)\n\n/* Uncomment for BYOK use cases */\nlet falService = AIProxy.falDirectService(\n    unprotectedAPIKey: \"your-fal-key\"\n)\n\n/* Uncomment for all other production use cases */\n//let falService = AIProxy.falService(\n//    partialKey: \"partial-key-from-your-developer-dashboard\",\n//    serviceURL: \"service-url-from-your-developer-dashboard\"\n//)\n"
  },
  {
    "path": "AIProxyFal/AIProxyFal/Assets.xcassets/AccentColor.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyFal/AIProxyFal/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyFal/AIProxyFal/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyFal/AIProxyFal/Assets.xcassets/fal.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"fal.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyFal/AIProxyFal/ContentView.swift",
    "content": "//\n//  ContentView.swift\n//  AIProxyFal\n//\n//  Created by Todd Hamilton on 6/13/24.\n//\n\nimport SwiftUI\n\nstruct ContentView: View {\n    var body: some View {\n        NavigationStack{\n            \n            VStack(spacing:24){\n                VStack{\n                    Image(\"fal\")\n                        .resizable()\n                        .scaledToFit()\n                        .frame(width: /*@START_MENU_TOKEN@*/100/*@END_MENU_TOKEN@*/)\n                        .cornerRadius(14)\n                        .foregroundColor(.primary)\n                    Text(\"Fal\")\n                        .bold()\n                        .font(.largeTitle)\n                    Text(\"AIProxy Sample\")\n                        .font(.subheadline)\n                        .foregroundColor(.secondary)\n                }\n                .frame(maxWidth:.infinity,alignment:.center)\n                \n                VStack{\n                    NavigationLink(\"Text to Image with FastSDXL\",destination: TextToImageView())\n                        .bold()\n                        .controlSize(.large)\n                        .tint(.indigo)\n                        .buttonStyle(.bordered)\n                }\n            }\n        }\n    }\n}\n\n#Preview {\n    ContentView()\n}\n"
  },
  {
    "path": "AIProxyFal/AIProxyFal/Preview Content/Preview Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyFal/AIProxyFal/TextToImageView.swift",
    "content": "//\n//  ImageGenView.swift\n//  AIProxyFal\n//\n//  Created by Todd Hamilton on 6/13/24.\n//\n\nimport SwiftUI\nimport AIProxy\n\nstruct TextToImageView: View {\n    \n    @State private var prompt: String = \"\"\n    @State private var imageUrl: String?\n    @State private var isLoading: Bool = false\n    \n    private func generate() async throws {\n        \n        let input = FalFastSDXLInputSchema(\n            prompt: prompt,\n            enableSafetyChecker: false\n        )\n        isLoading = true  // Start loading\n        defer { isLoading = false }\n        do {\n            let output = try await falService.createFastSDXLImage(input: input)\n            print(\"\"\"\n                  The first output image is at \\(output.images?.first?.url?.absoluteString ?? \"\")\n                  It took \\(output.timings?.inference ?? Double.nan) seconds to generate.\n                  \"\"\")\n            imageUrl = output.images?.first?.url?.absoluteString\n        }  catch AIProxyError.unsuccessfulRequest(let statusCode, let responseBody) {\n            print(\"Received non-200 status code: \\(statusCode) with response body: \\(responseBody)\")\n        } catch {\n            print(\"Could not create Fal SDXL image: \\(error.localizedDescription)\")\n        }\n    }\n    \n    var body: some View {\n        VStack{\n                \n            VStack{\n                if (imageUrl != nil) {\n                    AsyncImage(url: URL(string: imageUrl!)) { phase in\n                        if let image = phase.image {\n                            image\n                                .resizable()\n                                .aspectRatio(contentMode: .fit)\n                        } else if phase.error != nil {\n                            Text(\"Failed to load image\")\n                                .foregroundColor(.red)\n                        } else {\n                            ProgressView()\n                        }\n                    }\n                } else{\n                    ContentUnavailableView(\n                        \"Generate an image\",\n                        systemImage: \"photo.fill\",\n                        description: Text(\"Write a prompt below\")\n                    )\n                }\n            }\n            .frame(maxHeight: .infinity)\n            \n            Spacer()\n            \n            VStack(spacing:12){\n                TextField(\"Type a prompt\", text:$prompt)\n                    .submitLabel(.go)\n                    .padding(12)\n                    .background(Color(.systemBackground))\n                    .cornerRadius(8)\n                    .shadow(color:.primary, radius: 1)\n                    .onSubmit {\n                        Task{ try await generate() }\n                    }\n                Button{\n                    Task{ try await generate() }\n                }label:{\n                    if isLoading {\n                        ProgressView()\n                            .controlSize(.regular)\n                            .frame(maxWidth:.infinity)\n                    } else {\n                        Text(\"Generate Image\")\n                            .bold()\n                            .frame(maxWidth:.infinity)\n                    }\n                }\n                .controlSize(.large)\n                .buttonStyle(.borderedProminent)\n                .disabled(isLoading ? true : false)\n            }\n        }\n        .padding()\n        .navigationTitle(\"Generate Image\")\n        .navigationBarTitleDisplayMode(.inline)\n    }\n}\n\n#Preview {\n    TextToImageView()\n}\n"
  },
  {
    "path": "AIProxyFal/AIProxyFal.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 56;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t2C20F29C2CB0EB31001ECE32 /* AIProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 2C20F29B2CB0EB31001ECE32 /* AIProxy */; };\n\t\t2C63D7772D232C03008CFE5B /* AIProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 2C63D7762D232C03008CFE5B /* AIProxy */; };\n\t\t2C885B432CB1CD0A00C23BAD /* AIProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 2C885B422CB1CD0A00C23BAD /* AIProxy */; };\n\t\t2CD964C92C1BD144006DAD57 /* AIProxyFalApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD964C82C1BD144006DAD57 /* AIProxyFalApp.swift */; };\n\t\t2CD964CB2C1BD144006DAD57 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD964CA2C1BD144006DAD57 /* ContentView.swift */; };\n\t\t2CD964CD2C1BD145006DAD57 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2CD964CC2C1BD145006DAD57 /* Assets.xcassets */; };\n\t\t2CD964D02C1BD145006DAD57 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2CD964CF2C1BD145006DAD57 /* Preview Assets.xcassets */; };\n\t\t2CD964D72C1BD186006DAD57 /* TextToImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD964D62C1BD186006DAD57 /* TextToImageView.swift */; };\n\t\t2CDD52932C9A2A940052700C /* AppConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CDD52922C9A2A940052700C /* AppConstants.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t2CD964C52C1BD144006DAD57 /* AIProxyFal.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AIProxyFal.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t2CD964C82C1BD144006DAD57 /* AIProxyFalApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AIProxyFalApp.swift; sourceTree = \"<group>\"; };\n\t\t2CD964CA2C1BD144006DAD57 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = \"<group>\"; };\n\t\t2CD964CC2C1BD145006DAD57 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t2CD964CF2C1BD145006DAD57 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = \"Preview Assets.xcassets\"; sourceTree = \"<group>\"; };\n\t\t2CD964D62C1BD186006DAD57 /* TextToImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextToImageView.swift; sourceTree = \"<group>\"; };\n\t\t2CDD52922C9A2A940052700C /* AppConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConstants.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t2CD964C22C1BD144006DAD57 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2C63D7772D232C03008CFE5B /* AIProxy in Frameworks */,\n\t\t\t\t2C20F29C2CB0EB31001ECE32 /* AIProxy in Frameworks */,\n\t\t\t\t2C885B432CB1CD0A00C23BAD /* AIProxy in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t2CD964BC2C1BD144006DAD57 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CD964C72C1BD144006DAD57 /* AIProxyFal */,\n\t\t\t\t2CD964C62C1BD144006DAD57 /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2CD964C62C1BD144006DAD57 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CD964C52C1BD144006DAD57 /* AIProxyFal.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2CD964C72C1BD144006DAD57 /* AIProxyFal */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CD964C82C1BD144006DAD57 /* AIProxyFalApp.swift */,\n\t\t\t\t2CD964CA2C1BD144006DAD57 /* ContentView.swift */,\n\t\t\t\t2CD964D62C1BD186006DAD57 /* TextToImageView.swift */,\n\t\t\t\t2CDD52922C9A2A940052700C /* AppConstants.swift */,\n\t\t\t\t2CD964CC2C1BD145006DAD57 /* Assets.xcassets */,\n\t\t\t\t2CD964CE2C1BD145006DAD57 /* Preview Content */,\n\t\t\t);\n\t\t\tpath = AIProxyFal;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2CD964CE2C1BD145006DAD57 /* Preview Content */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CD964CF2C1BD145006DAD57 /* Preview Assets.xcassets */,\n\t\t\t);\n\t\t\tpath = \"Preview Content\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t2CD964C42C1BD144006DAD57 /* AIProxyFal */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 2CD964D32C1BD145006DAD57 /* Build configuration list for PBXNativeTarget \"AIProxyFal\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t2CD964C12C1BD144006DAD57 /* Sources */,\n\t\t\t\t2CD964C22C1BD144006DAD57 /* Frameworks */,\n\t\t\t\t2CD964C32C1BD144006DAD57 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = AIProxyFal;\n\t\t\tpackageProductDependencies = (\n\t\t\t\t2C20F29B2CB0EB31001ECE32 /* AIProxy */,\n\t\t\t\t2C885B422CB1CD0A00C23BAD /* AIProxy */,\n\t\t\t\t2C63D7762D232C03008CFE5B /* AIProxy */,\n\t\t\t);\n\t\t\tproductName = AIProxyFal;\n\t\t\tproductReference = 2CD964C52C1BD144006DAD57 /* AIProxyFal.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t2CD964BD2C1BD144006DAD57 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = 1;\n\t\t\t\tLastSwiftUpdateCheck = 1540;\n\t\t\t\tLastUpgradeCheck = 1540;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t2CD964C42C1BD144006DAD57 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 15.4;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 2CD964C02C1BD144006DAD57 /* Build configuration list for PBXProject \"AIProxyFal\" */;\n\t\t\tcompatibilityVersion = \"Xcode 14.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 2CD964BC2C1BD144006DAD57;\n\t\t\tpackageReferences = (\n\t\t\t\t2C63D7752D232C03008CFE5B /* XCRemoteSwiftPackageReference \"AIProxySwift\" */,\n\t\t\t);\n\t\t\tproductRefGroup = 2CD964C62C1BD144006DAD57 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t2CD964C42C1BD144006DAD57 /* AIProxyFal */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t2CD964C32C1BD144006DAD57 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2CD964D02C1BD145006DAD57 /* Preview Assets.xcassets in Resources */,\n\t\t\t\t2CD964CD2C1BD145006DAD57 /* Assets.xcassets in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t2CD964C12C1BD144006DAD57 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2CD964D72C1BD186006DAD57 /* TextToImageView.swift in Sources */,\n\t\t\t\t2CD964CB2C1BD144006DAD57 /* ContentView.swift in Sources */,\n\t\t\t\t2CD964C92C1BD144006DAD57 /* AIProxyFalApp.swift in Sources */,\n\t\t\t\t2CDD52932C9A2A940052700C /* AppConstants.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t2CD964D12C1BD145006DAD57 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.5;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"DEBUG $(inherited)\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2CD964D22C1BD145006DAD57 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.5;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t2CD964D42C1BD145006DAD57 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"AIProxyFal/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 553LMX46SJ;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.toddham.AIProxyFal;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2CD964D52C1BD145006DAD57 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"AIProxyFal/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 553LMX46SJ;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.toddham.AIProxyFal;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t2CD964C02C1BD144006DAD57 /* Build configuration list for PBXProject \"AIProxyFal\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2CD964D12C1BD145006DAD57 /* Debug */,\n\t\t\t\t2CD964D22C1BD145006DAD57 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t2CD964D32C1BD145006DAD57 /* Build configuration list for PBXNativeTarget \"AIProxyFal\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2CD964D42C1BD145006DAD57 /* Debug */,\n\t\t\t\t2CD964D52C1BD145006DAD57 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCRemoteSwiftPackageReference section */\n\t\t2C63D7752D232C03008CFE5B /* XCRemoteSwiftPackageReference \"AIProxySwift\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/lzell/AIProxySwift\";\n\t\t\trequirement = {\n\t\t\t\tbranch = main;\n\t\t\t\tkind = branch;\n\t\t\t};\n\t\t};\n/* End XCRemoteSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */\n\t\t2C20F29B2CB0EB31001ECE32 /* AIProxy */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tproductName = AIProxy;\n\t\t};\n\t\t2C63D7762D232C03008CFE5B /* AIProxy */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 2C63D7752D232C03008CFE5B /* XCRemoteSwiftPackageReference \"AIProxySwift\" */;\n\t\t\tproductName = AIProxy;\n\t\t};\n\t\t2C885B422CB1CD0A00C23BAD /* AIProxy */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tproductName = AIProxy;\n\t\t};\n/* End XCSwiftPackageProductDependency section */\n\t};\n\trootObject = 2CD964BD2C1BD144006DAD57 /* Project object */;\n}\n"
  },
  {
    "path": "AIProxyGemini/AIProxyGemini/AIProxyGeminiApp.swift",
    "content": "//\n//  AIProxyGeminiApp.swift\n//  AIProxyGemini\n//\n//  Created by Todd Hamilton on 10/18/24.\n//\n\nimport SwiftUI\n\n@main\nstruct AIProxyGeminiApp: App {\n    var body: some Scene {\n        WindowGroup {\n            ContentView()\n        }\n    }\n}\n"
  },
  {
    "path": "AIProxyGemini/AIProxyGemini/AppConstants.swift",
    "content": "//\n//  AppConstants.swift\n//  AIProxyGemini\n//\n//  Created by Todd Hamilton on 10/18/24.\n//\n\nimport AIProxy\n\n#error(\n    \"\"\"\n    Uncomment one of the methods below. To build and run on device you must follow the AIProxy integration guide.\n    Please see https://www.aiproxy.pro/docs/integration-guide.html\")\n    \"\"\"\n)\n\n/* Uncomment for BYOK use cases */\nlet geminiService = AIProxy.geminiDirectService(\n    unprotectedAPIKey: \"your-gemini-key\"\n)\n\n/* Uncomment for all other production use cases */\n//let geminiService = AIProxy.geminiService(\n//    partialKey: \"partial-key-from-your-developer-dashboard\",\n//    serviceURL: \"service-url-from-your-developer-dashboard\"\n//)\n"
  },
  {
    "path": "AIProxyGemini/AIProxyGemini/Assets.xcassets/AccentColor.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyGemini/AIProxyGemini/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ],\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"tinted\"\n        }\n      ],\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyGemini/AIProxyGemini/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyGemini/AIProxyGemini/Assets.xcassets/icon.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"gemini.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyGemini/AIProxyGemini/ContentView.swift",
    "content": "//\n//  ContentView.swift\n//  AIProxyGemini\n//\n//  Created by Todd Hamilton on 10/18/24.\n//\n\nimport SwiftUI\n\nstruct ContentView: View {\n    var body: some View {\n        NavigationStack{\n            VStack(spacing:24){\n                VStack{\n                    Image(\"icon\")\n                        .resizable()\n                        .scaledToFit()\n                        .frame(width: /*@START_MENU_TOKEN@*/100/*@END_MENU_TOKEN@*/)\n                        .cornerRadius(14)\n                        .foregroundColor(.primary)\n                    Text(\"Gemini\")\n                        .bold()\n                        .font(.largeTitle)\n                    Text(\"AIProxy Sample\")\n                        .font(.subheadline)\n                        .foregroundColor(.secondary)\n                }\n                .frame(maxWidth:.infinity,alignment:.center)\n                \n                VStack{\n                    NavigationLink(\"Text Generation\",destination: TextGenerationView())\n                }\n                .bold()\n                .controlSize(.large)\n                .tint(.teal)\n                .buttonStyle(.bordered)\n            }\n        }\n    }\n}\n\n#Preview {\n    ContentView()\n}\n"
  },
  {
    "path": "AIProxyGemini/AIProxyGemini/Preview Content/Preview Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyGemini/AIProxyGemini/TextGenerationView.swift",
    "content": "//\n//  TextGenerationView.swift\n//  AIProxyGemini\n//\n//  Created by Todd Hamilton on 10/18/24.\n//\n\nimport SwiftUI\nimport AIProxy\n\nstruct TextGenerationView: View {\n    \n    @State private var prompt = \"\"\n    @State private var result = \"\"\n    @State private var isLoading = false\n    @State private var showingAlert = false\n    \n    func generate() async throws {\n        isLoading = true\n        defer { isLoading = false }\n        do {\n            let requestBody = GeminiGenerateContentRequestBody(\n                model: \"gemini-1.5-flash\",\n                contents: [\n                    .init(\n                        parts: [.text(\"Tell me a joke\")]\n                    )\n                ]\n            )\n            let response = try await geminiService.generateContentRequest(body: requestBody)\n            for part in response.candidates?.first?.content?.parts ?? [] {\n                switch part {\n                case .text(let text):\n                    print(\"Gemini sent: \\(text)\")\n                    result = text\n                }\n            }\n            if let usage = response.usageMetadata {\n                print(\n                    \"\"\"\n                    Used:\n                     \\(usage.promptTokenCount ?? 0) prompt tokens\n                     \\(usage.cachedContentTokenCount ?? 0) cached tokens\n                     \\(usage.candidatesTokenCount ?? 0) candidate tokens\n                     \\(usage.totalTokenCount ?? 0) total tokens\n                    \"\"\"\n                )\n            }\n            \n            showingAlert = true\n        }  catch AIProxyError.unsuccessfulRequest(let statusCode, let responseBody) {\n            print(\"Received \\(statusCode) status code with response body: \\(responseBody)\")\n        } catch {\n            print(\"Could not create Gemini generate content request: \\(error.localizedDescription)\")\n        }\n    }\n    \n    var body: some View {\n        VStack {\n            VStack{\n                ContentUnavailableView(\n                    \"Generate Text\",\n                    systemImage: \"doc.plaintext.fill\",\n                    description: Text(\"Write a prompt below\")\n                )\n            }\n            .alert(isPresented: $showingAlert) {\n                Alert(\n                    title: Text(\"Result\"),\n                    message: Text(result),\n                    dismissButton: .default(Text(\"Close\"))\n                )\n            }\n\n            Spacer()\n            \n            VStack(spacing:12){\n                TextField(\"Type a prompt\", text:$prompt)\n                    .submitLabel(.go)\n                    .padding(12)\n                    .background(Color(.systemBackground))\n                    .cornerRadius(8)\n                    .shadow(color:.primary, radius: 1)\n                    .onSubmit {\n                        Task{ try await generate() }\n                    }\n                Button{\n                    Task{ try await generate() }\n                }label:{\n                    if isLoading {\n                        ProgressView()\n                            .controlSize(.regular)\n                            .frame(maxWidth:.infinity)\n                    } else {\n                        Text(\"Generate Text\")\n                            .bold()\n                            .frame(maxWidth:.infinity)\n                    }\n                }\n                .controlSize(.large)\n                .buttonStyle(.borderedProminent)\n                .disabled(isLoading ? true : false)\n            }\n        }\n        .padding()\n        .navigationTitle(\"Chat Completion\")\n        .navigationBarTitleDisplayMode(.inline)\n    }\n}\n\n#Preview {\n    TextGenerationView()\n}\n"
  },
  {
    "path": "AIProxyGemini/AIProxyGemini.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 77;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t2C7496D32CC2C9720069337D /* AIProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 2C7496D22CC2C9720069337D /* AIProxy */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t2C7496A42CC2C82B0069337D /* AIProxyGemini.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AIProxyGemini.app; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFileSystemSynchronizedRootGroup section */\n\t\t2C7496A62CC2C82B0069337D /* AIProxyGemini */ = {\n\t\t\tisa = PBXFileSystemSynchronizedRootGroup;\n\t\t\tpath = AIProxyGemini;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXFileSystemSynchronizedRootGroup section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t2C7496A12CC2C82B0069337D /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2C7496D32CC2C9720069337D /* AIProxy in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t2C74969B2CC2C82B0069337D = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2C7496A62CC2C82B0069337D /* AIProxyGemini */,\n\t\t\t\t2C7496A52CC2C82B0069337D /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2C7496A52CC2C82B0069337D /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2C7496A42CC2C82B0069337D /* AIProxyGemini.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t2C7496A32CC2C82B0069337D /* AIProxyGemini */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 2C7496B22CC2C82D0069337D /* Build configuration list for PBXNativeTarget \"AIProxyGemini\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t2C7496A02CC2C82B0069337D /* Sources */,\n\t\t\t\t2C7496A12CC2C82B0069337D /* Frameworks */,\n\t\t\t\t2C7496A22CC2C82B0069337D /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tfileSystemSynchronizedGroups = (\n\t\t\t\t2C7496A62CC2C82B0069337D /* AIProxyGemini */,\n\t\t\t);\n\t\t\tname = AIProxyGemini;\n\t\t\tpackageProductDependencies = (\n\t\t\t\t2C7496D22CC2C9720069337D /* AIProxy */,\n\t\t\t);\n\t\t\tproductName = AIProxyGemini;\n\t\t\tproductReference = 2C7496A42CC2C82B0069337D /* AIProxyGemini.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t2C74969C2CC2C82B0069337D /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = 1;\n\t\t\t\tLastSwiftUpdateCheck = 1600;\n\t\t\t\tLastUpgradeCheck = 1600;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t2C7496A32CC2C82B0069337D = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 16.0;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 2C74969F2CC2C82B0069337D /* Build configuration list for PBXProject \"AIProxyGemini\" */;\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 2C74969B2CC2C82B0069337D;\n\t\t\tminimizedProjectReferenceProxies = 1;\n\t\t\tpackageReferences = (\n\t\t\t\t2C7496D12CC2C9720069337D /* XCRemoteSwiftPackageReference \"AIProxySwift\" */,\n\t\t\t);\n\t\t\tpreferredProjectObjectVersion = 77;\n\t\t\tproductRefGroup = 2C7496A52CC2C82B0069337D /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t2C7496A32CC2C82B0069337D /* AIProxyGemini */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t2C7496A22CC2C82B0069337D /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t2C7496A02CC2C82B0069337D /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t2C7496B02CC2C82D0069337D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 18.0;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"DEBUG $(inherited)\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2C7496B12CC2C82D0069337D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 18.0;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t2C7496B32CC2C82D0069337D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"AIProxyGemini/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 553LMX46SJ;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.toddham.bootstrap;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2C7496B42CC2C82D0069337D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"AIProxyGemini/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 553LMX46SJ;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.toddham.bootstrap;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t2C74969F2CC2C82B0069337D /* Build configuration list for PBXProject \"AIProxyGemini\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2C7496B02CC2C82D0069337D /* Debug */,\n\t\t\t\t2C7496B12CC2C82D0069337D /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t2C7496B22CC2C82D0069337D /* Build configuration list for PBXNativeTarget \"AIProxyGemini\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2C7496B32CC2C82D0069337D /* Debug */,\n\t\t\t\t2C7496B42CC2C82D0069337D /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCRemoteSwiftPackageReference section */\n\t\t2C7496D12CC2C9720069337D /* XCRemoteSwiftPackageReference \"AIProxySwift\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/lzell/AIProxySwift\";\n\t\t\trequirement = {\n\t\t\t\tbranch = main;\n\t\t\t\tkind = branch;\n\t\t\t};\n\t\t};\n/* End XCRemoteSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */\n\t\t2C7496D22CC2C9720069337D /* AIProxy */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 2C7496D12CC2C9720069337D /* XCRemoteSwiftPackageReference \"AIProxySwift\" */;\n\t\t\tproductName = AIProxy;\n\t\t};\n/* End XCSwiftPackageProductDependency section */\n\t};\n\trootObject = 2C74969C2CC2C82B0069337D /* Project object */;\n}\n"
  },
  {
    "path": "AIProxyGroq/AIProxyGroq/AIProxyGroqApp.swift",
    "content": "//\n//  AIProxyGroqApp.swift\n//  AIProxyGroq\n//\n//  Created by Todd Hamilton on 10/1/24.\n//\n\nimport SwiftUI\n\n@main\nstruct AIProxyGroqApp: App {\n    var body: some Scene {\n        WindowGroup {\n            ContentView()\n        }\n    }\n}\n"
  },
  {
    "path": "AIProxyGroq/AIProxyGroq/AppConstants.swift",
    "content": "//\n//  AppConstants.swift\n//  AIProxyGroq\n//\n//  Created by Todd Hamilton on 10/1/24.\n//\n\nimport AIProxy\n\n#error(\n    \"\"\"\n    Uncomment one of the methods below. To build and run on device you must follow the AIProxy integration guide.\n    Please see https://www.aiproxy.pro/docs/integration-guide.html\")\n    \"\"\"\n)\n\n/* Uncomment for BYOK use cases */\nlet groqService = AIProxy.groqDirectService(\n    unprotectedAPIKey: \"your-groq-key\"\n)\n\n/* Uncomment for all other production use cases */\n//let groqService = AIProxy.groqService(\n//    partialKey: \"partial-key-from-your-developer-dashboard\",\n//    serviceURL: \"service-url-from-your-developer-dashboard\"\n//)\n"
  },
  {
    "path": "AIProxyGroq/AIProxyGroq/Assets.xcassets/AccentColor.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyGroq/AIProxyGroq/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ],\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"tinted\"\n        }\n      ],\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyGroq/AIProxyGroq/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyGroq/AIProxyGroq/Assets.xcassets/groq.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"groq.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyGroq/AIProxyGroq/ChatView.swift",
    "content": "//\n//  ChatView.swift\n//  AIProxyGroq\n//\n//  Created by Todd Hamilton on 10/1/24.\n//\n\nimport SwiftUI\nimport AIProxy\n\nstruct ChatView: View {\n    \n    @State private var prompt = \"\"\n    @State private var result = \"\"\n    @State private var isLoading = false\n    @State private var showingAlert = false\n    \n    func generate() async throws {\n        isLoading = true\n        defer { isLoading = false }\n        do {\n            let response = try await groqService.chatCompletionRequest(body: .init(\n                messages: [.assistant(content: prompt)],\n                model: \"mixtral-8x7b-32768\"\n            ))\n            print(response.choices.first?.message.content ?? \"\")\n            result = response.choices.first?.message.content ?? \"\"\n            showingAlert = true\n        }  catch AIProxyError.unsuccessfulRequest(let statusCode, let responseBody) {\n            print(\"Received non-200 status code: \\(statusCode) with response body: \\(responseBody)\")\n        } catch {\n            print(error.localizedDescription)\n        }\n    }\n    \n    var body: some View {\n        VStack {\n            VStack{\n                ContentUnavailableView(\n                    \"Generate Text\",\n                    systemImage: \"doc.plaintext.fill\",\n                    description: Text(\"Write a prompt below\")\n                )\n            }\n            .alert(isPresented: $showingAlert) {\n                Alert(\n                    title: Text(\"Result\"),\n                    message: Text(result),\n                    dismissButton: .default(Text(\"Close\"))\n                )\n            }\n\n            Spacer()\n            \n            VStack(spacing:12){\n                TextField(\"Type a prompt\", text:$prompt)\n                    .submitLabel(.go)\n                    .padding(12)\n                    .background(Color(.systemBackground))\n                    .cornerRadius(8)\n                    .shadow(color:.primary, radius: 1)\n                    .onSubmit {\n                        Task{ try await generate() }\n                    }\n                Button{\n                    Task{ try await generate() }\n                }label:{\n                    if isLoading {\n                        ProgressView()\n                            .controlSize(.regular)\n                            .frame(maxWidth:.infinity)\n                    } else {\n                        Text(\"Generate Text\")\n                            .bold()\n                            .frame(maxWidth:.infinity)\n                    }\n                }\n                .controlSize(.large)\n                .buttonStyle(.borderedProminent)\n                .disabled(isLoading ? true : false)\n            }\n        }\n        .padding()\n        .navigationTitle(\"Chat Completion\")\n        .navigationBarTitleDisplayMode(.inline)\n    }\n}\n\n\n#Preview {\n    ChatView()\n}\n"
  },
  {
    "path": "AIProxyGroq/AIProxyGroq/ContentView.swift",
    "content": "//\n//  ContentView.swift\n//  AIProxyGroq\n//\n//  Created by Todd Hamilton on 10/1/24.\n//\n\nimport SwiftUI\n\nstruct ContentView: View {\n    var body: some View {\n        NavigationStack{\n            VStack(spacing:24){\n                VStack{\n                    Image(\"groq\")\n                        .resizable()\n                        .scaledToFit()\n                        .frame(width: /*@START_MENU_TOKEN@*/100/*@END_MENU_TOKEN@*/)\n                        .cornerRadius(14)\n                        .foregroundColor(.primary)\n                    Text(\"Groq\")\n                        .bold()\n                        .font(.largeTitle)\n                    Text(\"AIProxy Sample\")\n                        .font(.subheadline)\n                        .foregroundColor(.secondary)\n                }\n                .frame(maxWidth:.infinity,alignment:.center)\n                \n                VStack{\n                    NavigationLink(\"Chat Completion\",destination: ChatView())\n                    NavigationLink(\"Streaming Chat Completion\",destination: StreamingChatView())\n                }\n                .bold()\n                .controlSize(.large)\n                .tint(.red)\n                .buttonStyle(.bordered)\n            }\n        }\n    }\n}\n\n#Preview {\n    ContentView()\n}\n"
  },
  {
    "path": "AIProxyGroq/AIProxyGroq/Preview Content/Preview Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyGroq/AIProxyGroq/StreamingChatView.swift",
    "content": "//\n//  StreamingChatView.swift\n//  AIProxyGroq\n//\n//  Created by Todd Hamilton on 10/1/24.\n//\n\n\nimport SwiftUI\nimport AIProxy\n\nstruct StreamingChatView: View {\n    \n    @State private var prompt = \"\"\n    @State private var result = \"\"\n    @State private var isLoading = false\n    @State private var showingAlert = false\n    \n    func generate() async throws {\n        isLoading = true\n        defer { isLoading = false }\n        do {\n            let stream = try await groqService.streamingChatCompletionRequest(body: .init(\n                    messages: [.assistant(content: prompt)],\n                    model: \"mixtral-8x7b-32768\"\n                )\n            )\n            for try await chunk in stream {\n                print(chunk.choices.first?.delta.content ?? \"\")\n            }\n        }  catch AIProxyError.unsuccessfulRequest(let statusCode, let responseBody) {\n            print(\"Received \\(statusCode) status code with response body: \\(responseBody)\")\n        } catch {\n            print(error.localizedDescription)\n        }\n    }\n    \n    var body: some View {\n        VStack {\n            VStack{\n                ContentUnavailableView(\n                    \"Generate Text\",\n                    systemImage: \"doc.plaintext.fill\",\n                    description: Text(\"Write a prompt below\")\n                )\n            }\n            .alert(isPresented: $showingAlert) {\n                Alert(\n                    title: Text(\"Result\"),\n                    message: Text(\"View the streaming response in the Xcode console.\"),\n                    dismissButton: .default(Text(\"Close\"))\n                )\n            }\n\n            Spacer()\n            \n            VStack(spacing:12){\n                TextField(\"Type a prompt\", text:$prompt)\n                    .submitLabel(.go)\n                    .padding(12)\n                    .background(Color(.systemBackground))\n                    .cornerRadius(8)\n                    .shadow(color:.primary, radius: 1)\n                    .onSubmit {\n                        showingAlert = true\n                        Task{ try await generate() }\n                    }\n                Button{\n                    showingAlert = true\n                    Task{ try await generate() }\n                }label:{\n                    if isLoading {\n                        ProgressView()\n                            .controlSize(.regular)\n                            .frame(maxWidth:.infinity)\n                    } else {\n                        Text(\"Generate Text\")\n                            .bold()\n                            .frame(maxWidth:.infinity)\n                    }\n                }\n                .controlSize(.large)\n                .buttonStyle(.borderedProminent)\n                .disabled(isLoading ? true : false)\n            }\n        }\n        .padding()\n        .navigationTitle(\"Streaming Chat Completion\")\n        .navigationBarTitleDisplayMode(.inline)\n    }\n}\n\n#Preview {\n    ChatView()\n}\n"
  },
  {
    "path": "AIProxyGroq/AIProxyGroq.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 77;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t2C7E8C082CAC7CAA00A70D1C /* AIProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 2C7E8C072CAC7CAA00A70D1C /* AIProxy */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t2C7E8BF52CAC7B7E00A70D1C /* AIProxyGroq.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AIProxyGroq.app; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFileSystemSynchronizedRootGroup section */\n\t\t2C7E8BF72CAC7B7E00A70D1C /* AIProxyGroq */ = {\n\t\t\tisa = PBXFileSystemSynchronizedRootGroup;\n\t\t\tpath = AIProxyGroq;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXFileSystemSynchronizedRootGroup section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t2C7E8BF22CAC7B7E00A70D1C /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2C7E8C082CAC7CAA00A70D1C /* AIProxy in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t2C7E8BEC2CAC7B7E00A70D1C = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2C7E8BF72CAC7B7E00A70D1C /* AIProxyGroq */,\n\t\t\t\t2C7E8BF62CAC7B7E00A70D1C /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2C7E8BF62CAC7B7E00A70D1C /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2C7E8BF52CAC7B7E00A70D1C /* AIProxyGroq.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t2C7E8BF42CAC7B7E00A70D1C /* AIProxyGroq */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 2C7E8C032CAC7B7F00A70D1C /* Build configuration list for PBXNativeTarget \"AIProxyGroq\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t2C7E8BF12CAC7B7E00A70D1C /* Sources */,\n\t\t\t\t2C7E8BF22CAC7B7E00A70D1C /* Frameworks */,\n\t\t\t\t2C7E8BF32CAC7B7E00A70D1C /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tfileSystemSynchronizedGroups = (\n\t\t\t\t2C7E8BF72CAC7B7E00A70D1C /* AIProxyGroq */,\n\t\t\t);\n\t\t\tname = AIProxyGroq;\n\t\t\tpackageProductDependencies = (\n\t\t\t\t2C7E8C072CAC7CAA00A70D1C /* AIProxy */,\n\t\t\t);\n\t\t\tproductName = AIProxyGroq;\n\t\t\tproductReference = 2C7E8BF52CAC7B7E00A70D1C /* AIProxyGroq.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t2C7E8BED2CAC7B7E00A70D1C /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = 1;\n\t\t\t\tLastSwiftUpdateCheck = 1600;\n\t\t\t\tLastUpgradeCheck = 1600;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t2C7E8BF42CAC7B7E00A70D1C = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 16.0;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 2C7E8BF02CAC7B7E00A70D1C /* Build configuration list for PBXProject \"AIProxyGroq\" */;\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 2C7E8BEC2CAC7B7E00A70D1C;\n\t\t\tminimizedProjectReferenceProxies = 1;\n\t\t\tpackageReferences = (\n\t\t\t\t2C7E8C062CAC7CAA00A70D1C /* XCRemoteSwiftPackageReference \"AIProxySwift\" */,\n\t\t\t);\n\t\t\tpreferredProjectObjectVersion = 77;\n\t\t\tproductRefGroup = 2C7E8BF62CAC7B7E00A70D1C /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t2C7E8BF42CAC7B7E00A70D1C /* AIProxyGroq */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t2C7E8BF32CAC7B7E00A70D1C /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t2C7E8BF12CAC7B7E00A70D1C /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t2C7E8C012CAC7B7F00A70D1C /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 18.0;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"DEBUG $(inherited)\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2C7E8C022CAC7B7F00A70D1C /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 18.0;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t2C7E8C042CAC7B7F00A70D1C /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"AIProxyGroq/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 553LMX46SJ;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.toddham.bootstrap;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2C7E8C052CAC7B7F00A70D1C /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"AIProxyGroq/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 553LMX46SJ;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.toddham.bootstrap;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t2C7E8BF02CAC7B7E00A70D1C /* Build configuration list for PBXProject \"AIProxyGroq\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2C7E8C012CAC7B7F00A70D1C /* Debug */,\n\t\t\t\t2C7E8C022CAC7B7F00A70D1C /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t2C7E8C032CAC7B7F00A70D1C /* Build configuration list for PBXNativeTarget \"AIProxyGroq\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2C7E8C042CAC7B7F00A70D1C /* Debug */,\n\t\t\t\t2C7E8C052CAC7B7F00A70D1C /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCRemoteSwiftPackageReference section */\n\t\t2C7E8C062CAC7CAA00A70D1C /* XCRemoteSwiftPackageReference \"AIProxySwift\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/lzell/AIProxySwift\";\n\t\t\trequirement = {\n\t\t\t\tbranch = main;\n\t\t\t\tkind = branch;\n\t\t\t};\n\t\t};\n/* End XCRemoteSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */\n\t\t2C7E8C072CAC7CAA00A70D1C /* AIProxy */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 2C7E8C062CAC7CAA00A70D1C /* XCRemoteSwiftPackageReference \"AIProxySwift\" */;\n\t\t\tproductName = AIProxy;\n\t\t};\n/* End XCSwiftPackageProductDependency section */\n\t};\n\trootObject = 2C7E8BED2CAC7B7E00A70D1C /* Project object */;\n}\n"
  },
  {
    "path": "AIProxyOpenAI/AIProxyOpenAI/AIProxyOpenAIApp.swift",
    "content": "//\n//  AIProxyOpenAIApp.swift\n//  AIProxyOpenAI\n//\n//  Created by Todd Hamilton on 6/14/24.\n//\n\nimport SwiftUI\n\n@main\nstruct AIProxyOpenAIApp: App {\n    var body: some Scene {\n        WindowGroup {\n            ContentView()\n        }\n    }\n}\n"
  },
  {
    "path": "AIProxyOpenAI/AIProxyOpenAI/AppConstants.swift",
    "content": "//\n//  AppConstants.swift\n//  AIProxyOpenAI\n//\n//  Created by Todd Hamilton on 6/14/24.\n//\n\nimport AIProxy\n\n#error(\n    \"\"\"\n    Uncomment one of the methods below. To build and run on device you must follow the AIProxy integration guide.\n    Please see https://www.aiproxy.pro/docs/integration-guide.html\")\n    \"\"\"\n)\n\n/* Uncomment for BYOK use cases */\nlet openAIService = AIProxy.openAIDirectService(\n    unprotectedAPIKey: \"your-openai-key\"\n)\n\n/* Uncomment for all other production use cases */\n//let openAIService = AIProxy.openAIService(\n//    partialKey: \"partial-key-from-your-developer-dashboard\",\n//    serviceURL: \"service-url-from-your-developer-dashboard\"\n//)\n"
  },
  {
    "path": "AIProxyOpenAI/AIProxyOpenAI/Assets.xcassets/AccentColor.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyOpenAI/AIProxyOpenAI/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyOpenAI/AIProxyOpenAI/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyOpenAI/AIProxyOpenAI/Assets.xcassets/openai.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"openai.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyOpenAI/AIProxyOpenAI/Assets.xcassets/surfer.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"surfer.jpeg\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyOpenAI/AIProxyOpenAI/ChatView.swift",
    "content": "//\n//  ChatView.swift\n//  AIProxyOpenAI\n//\n//  Created by Todd Hamilton on 6/14/24.\n//\n\nimport SwiftUI\nimport AIProxy\n\nstruct ChatView: View {\n    \n    @State private var prompt = \"\"\n    @State private var result = \"\"\n    @State private var isLoading = false\n    @State private var showingAlert = false\n    \n    func generate() async throws {\n        isLoading = true\n        defer { isLoading = false }\n        do {\n            let response = try await openAIService.chatCompletionRequest(body: .init(\n                model: \"gpt-4o\",\n                messages: [.system(content: .text(prompt))]\n            ))\n            result = (response.choices.first?.message.content)!\n            showingAlert = true\n        }  catch AIProxyError.unsuccessfulRequest(let statusCode, let responseBody) {\n            print(\"Received non-200 status code: \\(statusCode) with response body: \\(String(describing: responseBody))\")\n        } catch {\n            print(error.localizedDescription)\n        }\n    }\n    \n    var body: some View {\n        VStack {\n            VStack{\n                ContentUnavailableView(\n                    \"Generate Text\",\n                    systemImage: \"doc.plaintext.fill\",\n                    description: Text(\"Write a prompt below\")\n                )\n            }\n            .alert(isPresented: $showingAlert) {\n                Alert(\n                    title: Text(\"Result\"),\n                    message: Text(result),\n                    dismissButton: .default(Text(\"Close\"))\n                )\n            }\n\n            Spacer()\n            \n            VStack(spacing:12){\n                TextField(\"Type a prompt\", text:$prompt)\n                    .submitLabel(.go)\n                    .padding(12)\n                    .background(Color(.systemBackground))\n                    .cornerRadius(8)\n                    .shadow(color:.primary, radius: 1)\n                    .onSubmit {\n                        Task{ try await generate() }\n                    }\n                Button{\n                    Task{ try await generate() }\n                }label:{\n                    if isLoading {\n                        ProgressView()\n                            .controlSize(.regular)\n                            .frame(maxWidth:.infinity)\n                    } else {\n                        Text(\"Generate Text\")\n                            .bold()\n                            .frame(maxWidth:.infinity)\n                    }\n                }\n                .controlSize(.large)\n                .buttonStyle(.borderedProminent)\n                .disabled(isLoading ? true : false)\n            }\n        }\n        .padding()\n        .navigationTitle(\"Chat Completion\")\n        .navigationBarTitleDisplayMode(.inline)\n    }\n}\n\n#Preview {\n    ChatView()\n}\n"
  },
  {
    "path": "AIProxyOpenAI/AIProxyOpenAI/ContentView.swift",
    "content": "//\n//  ContentView.swift\n//  AIProxyOpenAI\n//\n//  Created by Todd Hamilton on 6/14/24.\n//\n\nimport SwiftUI\n\nstruct ContentView: View {\n    var body: some View {\n        NavigationStack{\n            \n            VStack(spacing:48){\n                VStack{\n                    Image(\"openai\")\n                        .resizable()\n                        .scaledToFit()\n                        .frame(width: /*@START_MENU_TOKEN@*/100/*@END_MENU_TOKEN@*/)\n                        .cornerRadius(14)\n                        .foregroundColor(.primary)\n                    Text(\"OpenAI\")\n                        .bold()\n                        .font(.largeTitle)\n                    Text(\"AIProxy Sample\")\n                        .font(.subheadline)\n                        .foregroundColor(.secondary)\n                }\n                .frame(maxWidth:.infinity,alignment:.center)\n                \n                VStack{\n                    NavigationLink(\"Chat Example\",destination: ChatView())\n                    NavigationLink(\"Streaming Chat Example\",destination: ChatView())\n                    NavigationLink(\"Multi-Modal Chat Example\",destination: MultiModalChatView())\n                    NavigationLink(\"DALLE Example\",destination: DalleView())\n                    NavigationLink(\"Text-to-Speech Example\",destination: TextToSpeechView())\n                }\n                .bold()\n                .controlSize(.large)\n                .buttonStyle(.bordered)\n                .tint(.purple)\n            }\n        }\n    }\n}\n\n#Preview {\n    ContentView()\n}\n"
  },
  {
    "path": "AIProxyOpenAI/AIProxyOpenAI/DalleView.swift",
    "content": "//\n//  DalleView.swift\n//  AIProxyOpenAI\n//\n//  Created by Todd Hamilton on 8/13/24.\n//\n\nimport SwiftUI\nimport AIProxy\n\nstruct DalleView: View {\n    \n    @State private var prompt = \"\"\n    @State private var imageUrl: String?\n    @State private var isLoading = false\n    \n    func generate() async throws {\n        isLoading = true  // Start loading\n        defer { isLoading = false }\n        do {\n            let requestBody = OpenAICreateImageRequestBody(\n                prompt: prompt,\n                model: \"dall-e-3\"\n            )\n            let response = try await openAIService.createImageRequest(body: requestBody)\n            imageUrl = response.data.first?.url?.absoluteString ?? \"\"\n//            print(response.data.first?.url ?? \"\")\n        }  catch AIProxyError.unsuccessfulRequest(let statusCode, let responseBody) {\n            print(\"Received non-200 status code: \\(statusCode) with response body: \\(responseBody)\")\n        } catch {\n            print(error.localizedDescription)\n        }\n    }\n    \n    var body: some View {\n        VStack{\n                \n            VStack{\n                if (imageUrl != nil) {\n                    AsyncImage(url: URL(string: imageUrl!)) { phase in\n                        if let image = phase.image {\n                            image\n                                .resizable()\n                                .aspectRatio(contentMode: .fit)\n                        } else if phase.error != nil {\n                            Text(\"Failed to load image\")\n                                .foregroundColor(.red)\n                        } else {\n                            ProgressView()\n                        }\n                    }\n                } else{\n                    ContentUnavailableView(\n                        \"Generate an image\",\n                        systemImage: \"photo.fill\",\n                        description: Text(\"Write a prompt below\")\n                    )\n                }\n            }\n            .frame(maxHeight: .infinity)\n            \n            Spacer()\n            \n            VStack(spacing:12){\n                TextField(\"Type a prompt\", text:$prompt)\n                    .submitLabel(.go)\n                    .padding(12)\n                    .background(Color(.systemBackground))\n                    .cornerRadius(8)\n                    .shadow(color:.primary, radius: 1)\n                    .onSubmit {\n                        Task{ try await generate() }\n                    }\n                Button{\n                    Task{ try await generate() }\n                }label:{\n                    if isLoading {\n                        ProgressView()\n                            .controlSize(.regular)\n                            .frame(maxWidth:.infinity)\n                    } else {\n                        Text(\"Generate Text\")\n                            .bold()\n                            .frame(maxWidth:.infinity)\n                    }\n                }\n                .controlSize(.large)\n                .buttonStyle(.borderedProminent)\n                .disabled(isLoading ? true : false)\n            }\n        }\n        .padding()\n        .navigationTitle(\"Generate Image\")\n        .navigationBarTitleDisplayMode(.inline)\n    }\n}\n\n#Preview {\n    DalleView()\n}\n"
  },
  {
    "path": "AIProxyOpenAI/AIProxyOpenAI/MultiModalChatView.swift",
    "content": "//\n//  MultiModalChatView.swift\n//  AIProxyOpenAI\n//\n//  Created by Todd Hamilton on 6/14/24.\n//\n\nimport SwiftUI\nimport AIProxy\nimport UIKit\n\nstruct MultiModalChatView: View {\n    \n    @State private var prompt:String = \"\"\n    @State private var result:String = \"\"\n    @State private var showingAlert = false\n    @State private var isLoading = false\n    \n    var body: some View {\n        VStack{\n            VStack{\n                Image(\"surfer\")\n                    .resizable()\n                    .scaledToFit()\n                    .frame(maxWidth: .infinity)\n            }\n            .frame(maxHeight: .infinity)\n            .alert(isPresented: $showingAlert){\n                Alert(\n                    title: Text(\"Result\"),\n                    message: Text(\"\\(result)\"),\n                    dismissButton: .default(Text(\"Close\"))\n                )\n            }\n            \n            Spacer()\n            \n            VStack(spacing:12){\n                Button{\n                    Task {\n                        try await generate()\n                    }\n                }label: {\n                    if isLoading {\n                        ProgressView()\n                            .controlSize(.regular)\n                            .frame(maxWidth:.infinity)\n                    } else {\n                        Text(\"Describe Image\")\n                            .bold()\n                            .frame(maxWidth:.infinity)\n                    }\n                }\n                .controlSize(.large)\n                .buttonStyle(.borderedProminent)\n                .disabled(isLoading ? true : false)\n            }\n        }\n        .padding()\n        .navigationTitle(\"Describe Image\")\n        .navigationBarTitleDisplayMode(.inline)\n    }\n    \n    func generate() async throws {\n        isLoading = true\n        defer { isLoading = false }\n        \n        let image = UIImage(named: \"surfer\")\n        let localURL = createOpenAILocalURL(forImage: image!)\n        \n        do {\n            let response = try await openAIService.chatCompletionRequest(body: .init(\n                model: \"gpt-4o\",\n                messages: [\n                    .system(\n                        content: .text(\"Tell me what you see\")\n                    ),\n                    .user(\n                        content: .parts(\n                            [\n                                .text(\"What do you see?\"),\n                                .imageURL(localURL!)\n                            ]\n                        )\n                    )\n                ]\n            ))\n            result = (response.choices.first?.message.content)!\n            showingAlert = true\n        }  catch AIProxyError.unsuccessfulRequest(let statusCode, let responseBody) {\n            print(\"Received non-200 status code: \\(statusCode) with response body: \\(String(describing: responseBody))\")\n        } catch {\n            print(error.localizedDescription)\n        }\n    }\n    \n    func createOpenAILocalURL(forImage image: UIImage) -> URL? {\n        // Attempt to get JPEG data from the UIImage\n        guard let jpegData = image.jpegData(compressionQuality: 1.0) else {\n            return nil\n        }\n        \n        // Encode the JPEG data to a base64 string\n        let base64String = jpegData.base64EncodedString()\n        \n        // Create the data URL string\n        let urlString = \"data:image/jpeg;base64,\\(base64String)\"\n        \n        // Return the URL constructed from the data URL string\n        return URL(string: urlString)\n    }\n \n}\n\n#Preview {\n    MultiModalChatView()\n}\n\nprivate extension CGImage {\n    var jpegData: Data? {\n        let uiImage = UIImage(cgImage: self)\n        return uiImage.jpegData(compressionQuality: 1.0)\n    }\n}\n\n\n\n\n"
  },
  {
    "path": "AIProxyOpenAI/AIProxyOpenAI/Preview Content/Preview Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyOpenAI/AIProxyOpenAI/StreamingChatView.swift",
    "content": "//\n//  StreamingChatView.swift\n//  AIProxyOpenAI\n//\n//  Created by Todd Hamilton on 8/13/24.\n//\n\nimport SwiftUI\nimport AIProxy\n\nstruct StreamingChatView: View {\n    \n    @State private var prompt = \"\"\n    @State private var result = \"\"\n    @State private var isLoading = false\n    @State private var showingAlert = false\n    \n    func generate() async throws {\n        \n        let requestBody = OpenAIChatCompletionRequestBody(\n            model: \"gpt-4o\",\n            messages: [.user(content: .text(prompt))]\n        )\n        isLoading = true\n        defer { isLoading = false }\n        do {\n            let stream = try await openAIService.streamingChatCompletionRequest(body: requestBody)\n            for try await chunk in stream {\n                print(chunk.choices.first?.delta.content ?? \"\")\n            }\n        }  catch AIProxyError.unsuccessfulRequest(let statusCode, let responseBody) {\n            print(\"Received non-200 status code: \\(statusCode) with response body: \\(responseBody)\")\n        } catch {\n            print(error.localizedDescription)\n        }\n    }\n    \n    var body: some View {\n        VStack {\n            VStack{\n                ContentUnavailableView(\n                    \"Generate Text\",\n                    systemImage: \"doc.plaintext.fill\",\n                    description: Text(\"Write a prompt below\")\n                )\n            }\n            .alert(isPresented: $showingAlert) {\n                Alert(\n                    title: Text(\"Result\"),\n                    message: Text(\"View the streaming response in the Xcode console.\"),\n                    dismissButton: .default(Text(\"Close\"))\n                )\n            }\n\n            Spacer()\n            \n            VStack(spacing:12){\n                TextField(\"Type a prompt\", text:$prompt)\n                    .submitLabel(.go)\n                    .padding(12)\n                    .background(Color(.systemBackground))\n                    .cornerRadius(8)\n                    .shadow(color:.primary, radius: 1)\n                    .onSubmit {\n                        Task{ try await generate() }\n                    }\n                Button{\n                    showingAlert = true\n                    Task{ try await generate() }\n                }label:{\n                    if isLoading {\n                        ProgressView()\n                            .controlSize(.regular)\n                            .frame(maxWidth:.infinity)\n                    } else {\n                        Text(\"Generate Text\")\n                            .bold()\n                            .frame(maxWidth:.infinity)\n                    }\n                }\n                .controlSize(.large)\n                .buttonStyle(.borderedProminent)\n                .disabled(isLoading ? true : false)\n            }\n        }\n        .padding()\n        .navigationTitle(\"Streaming Chat Completion\")\n        .navigationBarTitleDisplayMode(.inline)\n    }\n}\n\n#Preview {\n    StreamingChatView()\n}\n"
  },
  {
    "path": "AIProxyOpenAI/AIProxyOpenAI/TextToSpeechView.swift",
    "content": "//\n//  TextToSpeechView.swift\n//  AIProxyOpenAI\n//\n//  Created by Todd Hamilton on 10/9/24.\n//\n\nimport SwiftUI\nimport AIProxy\nimport AVKit\n\nstruct TextToSpeechView: View {\n    \n    @State private var prompt = \"\"\n    @State private var result = \"\"\n    @State private var isLoading = false\n    @State var audioPlayer: AVAudioPlayer!\n    \n    // List of available voices\n    let voices = [\"nova\", \"aria\", \"bella\", \"emma\"] // Replace with actual voice names from OpenAI\n    @State private var selectedVoice = \"nova\" // Default selected voice\n    \n    func generate() async throws {\n        isLoading = true\n        defer { isLoading = false }\n        do {\n            let requestBody = OpenAITextToSpeechRequestBody(\n                input: prompt,\n                voice: OpenAITextToSpeechRequestBody.Voice(rawValue: selectedVoice) ?? .nova\n            )\n\n            let mpegData = try await openAIService.createTextToSpeechRequest(body: requestBody)\n\n            // Do not use a local `let` or `var` for AVAudioPlayer.\n            // You need the lifecycle of the player to live beyond the scope of this function.\n            // Instead, use file scope or set the player as a member of a reference type with long life.\n            // For example, at the top of this file you may define:\n            //\n            //   fileprivate var audioPlayer: AVAudioPlayer? = nil\n            //\n            // And then use the code below to play the TTS result:\n            audioPlayer = try AVAudioPlayer(data: mpegData)\n            audioPlayer?.prepareToPlay()\n            audioPlayer?.play()\n        }  catch AIProxyError.unsuccessfulRequest(let statusCode, let responseBody) {\n            print(\"Received \\(statusCode) status code with response body: \\(responseBody)\")\n        } catch {\n            print(\"Could not create ElevenLabs TTS audio: \\(error.localizedDescription)\")\n        }\n    }\n    \n    var body: some View {\n        VStack {\n            VStack{\n                ContentUnavailableView(\n                    \"Text-to-Speech\",\n                    systemImage: \"doc.plaintext.fill\",\n                    description: Text(\"Write a prompt and select a voice\")\n                )\n            }\n\n            Spacer()\n            \n            VStack(spacing:12){\n                TextField(\"Type a prompt\", text:$prompt)\n                    .submitLabel(.go)\n                    .padding(12)\n                    .background(Color(.systemBackground))\n                    .cornerRadius(8)\n                    .shadow(color:.primary, radius: 1)\n                    .onSubmit {\n                        Task{ try await generate() }\n                    }\n                \n                // Voice Picker\n                Picker(\"Select Voice\", selection: $selectedVoice) {\n                    ForEach(voices, id: \\.self) {\n                        Text($0.capitalized)\n                    }\n                }\n                .pickerStyle(.segmented)\n                .padding()\n                \n                Button{\n                    Task{ try await generate() }\n                }label:{\n                    if isLoading {\n                        ProgressView()\n                            .controlSize(.regular)\n                            .frame(maxWidth:.infinity)\n                    } else {\n                        Text(\"Generate Speech\")\n                            .bold()\n                            .frame(maxWidth:.infinity)\n                    }\n                }\n                .controlSize(.large)\n                .buttonStyle(.borderedProminent)\n                .disabled(isLoading ? true : false)\n            }\n        }\n        .padding()\n        .navigationTitle(\"Text-to-Speech\")\n        .navigationBarTitleDisplayMode(.inline)\n    }\n}\n\n#Preview {\n    TextToSpeechView()\n}\n"
  },
  {
    "path": "AIProxyOpenAI/AIProxyOpenAI.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 56;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t2C16EC352CB720580016790F /* TextToSpeechView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C16EC342CB720580016790F /* TextToSpeechView.swift */; };\n\t\t2CCB20342C6C03AF003A8B25 /* StreamingChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCB20332C6C03AF003A8B25 /* StreamingChatView.swift */; };\n\t\t2CCB20362C6C0419003A8B25 /* DalleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCB20352C6C0419003A8B25 /* DalleView.swift */; };\n\t\t2CD964F02C1CA33B006DAD57 /* AIProxyOpenAIApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD964EF2C1CA33B006DAD57 /* AIProxyOpenAIApp.swift */; };\n\t\t2CD964F22C1CA33B006DAD57 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD964F12C1CA33B006DAD57 /* ContentView.swift */; };\n\t\t2CD964F42C1CA33D006DAD57 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2CD964F32C1CA33D006DAD57 /* Assets.xcassets */; };\n\t\t2CD964F72C1CA33D006DAD57 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2CD964F62C1CA33D006DAD57 /* Preview Assets.xcassets */; };\n\t\t2CD964FE2C1CA3DC006DAD57 /* MultiModalChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD964FD2C1CA3DC006DAD57 /* MultiModalChatView.swift */; };\n\t\t2CD965002C1CA3F3006DAD57 /* ChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD964FF2C1CA3F3006DAD57 /* ChatView.swift */; };\n\t\t2CD965032C1CA4BB006DAD57 /* AIProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 2CD965022C1CA4BB006DAD57 /* AIProxy */; };\n\t\t2CD965052C1CA4CF006DAD57 /* AppConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD965042C1CA4CF006DAD57 /* AppConstants.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t2C16EC342CB720580016790F /* TextToSpeechView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextToSpeechView.swift; sourceTree = \"<group>\"; };\n\t\t2CCB20332C6C03AF003A8B25 /* StreamingChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StreamingChatView.swift; sourceTree = \"<group>\"; };\n\t\t2CCB20352C6C0419003A8B25 /* DalleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DalleView.swift; sourceTree = \"<group>\"; };\n\t\t2CD964EC2C1CA33B006DAD57 /* AIProxyOpenAI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AIProxyOpenAI.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t2CD964EF2C1CA33B006DAD57 /* AIProxyOpenAIApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AIProxyOpenAIApp.swift; sourceTree = \"<group>\"; };\n\t\t2CD964F12C1CA33B006DAD57 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = \"<group>\"; };\n\t\t2CD964F32C1CA33D006DAD57 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t2CD964F62C1CA33D006DAD57 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = \"Preview Assets.xcassets\"; sourceTree = \"<group>\"; };\n\t\t2CD964FD2C1CA3DC006DAD57 /* MultiModalChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiModalChatView.swift; sourceTree = \"<group>\"; };\n\t\t2CD964FF2C1CA3F3006DAD57 /* ChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatView.swift; sourceTree = \"<group>\"; };\n\t\t2CD965042C1CA4CF006DAD57 /* AppConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConstants.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t2CD964E92C1CA33B006DAD57 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2CD965032C1CA4BB006DAD57 /* AIProxy in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t2CD964E32C1CA33B006DAD57 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CD964EE2C1CA33B006DAD57 /* AIProxyOpenAI */,\n\t\t\t\t2CD964ED2C1CA33B006DAD57 /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2CD964ED2C1CA33B006DAD57 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CD964EC2C1CA33B006DAD57 /* AIProxyOpenAI.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2CD964EE2C1CA33B006DAD57 /* AIProxyOpenAI */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CD964EF2C1CA33B006DAD57 /* AIProxyOpenAIApp.swift */,\n\t\t\t\t2CD964F12C1CA33B006DAD57 /* ContentView.swift */,\n\t\t\t\t2CD964FF2C1CA3F3006DAD57 /* ChatView.swift */,\n\t\t\t\t2CCB20332C6C03AF003A8B25 /* StreamingChatView.swift */,\n\t\t\t\t2CD964FD2C1CA3DC006DAD57 /* MultiModalChatView.swift */,\n\t\t\t\t2CCB20352C6C0419003A8B25 /* DalleView.swift */,\n\t\t\t\t2C16EC342CB720580016790F /* TextToSpeechView.swift */,\n\t\t\t\t2CD965042C1CA4CF006DAD57 /* AppConstants.swift */,\n\t\t\t\t2CD964F32C1CA33D006DAD57 /* Assets.xcassets */,\n\t\t\t\t2CD964F52C1CA33D006DAD57 /* Preview Content */,\n\t\t\t);\n\t\t\tpath = AIProxyOpenAI;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2CD964F52C1CA33D006DAD57 /* Preview Content */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CD964F62C1CA33D006DAD57 /* Preview Assets.xcassets */,\n\t\t\t);\n\t\t\tpath = \"Preview Content\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t2CD964EB2C1CA33B006DAD57 /* AIProxyOpenAI */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 2CD964FA2C1CA33D006DAD57 /* Build configuration list for PBXNativeTarget \"AIProxyOpenAI\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t2CD964E82C1CA33B006DAD57 /* Sources */,\n\t\t\t\t2CD964E92C1CA33B006DAD57 /* Frameworks */,\n\t\t\t\t2CD964EA2C1CA33B006DAD57 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = AIProxyOpenAI;\n\t\t\tpackageProductDependencies = (\n\t\t\t\t2CD965022C1CA4BB006DAD57 /* AIProxy */,\n\t\t\t);\n\t\t\tproductName = AIProxyOpenAI;\n\t\t\tproductReference = 2CD964EC2C1CA33B006DAD57 /* AIProxyOpenAI.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t2CD964E42C1CA33B006DAD57 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = 1;\n\t\t\t\tLastSwiftUpdateCheck = 1540;\n\t\t\t\tLastUpgradeCheck = 1540;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t2CD964EB2C1CA33B006DAD57 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 15.4;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 2CD964E72C1CA33B006DAD57 /* Build configuration list for PBXProject \"AIProxyOpenAI\" */;\n\t\t\tcompatibilityVersion = \"Xcode 14.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 2CD964E32C1CA33B006DAD57;\n\t\t\tpackageReferences = (\n\t\t\t\t2CD965012C1CA4BB006DAD57 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */,\n\t\t\t);\n\t\t\tproductRefGroup = 2CD964ED2C1CA33B006DAD57 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t2CD964EB2C1CA33B006DAD57 /* AIProxyOpenAI */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t2CD964EA2C1CA33B006DAD57 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2CD964F72C1CA33D006DAD57 /* Preview Assets.xcassets in Resources */,\n\t\t\t\t2CD964F42C1CA33D006DAD57 /* Assets.xcassets in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t2CD964E82C1CA33B006DAD57 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2CD965052C1CA4CF006DAD57 /* AppConstants.swift in Sources */,\n\t\t\t\t2CCB20362C6C0419003A8B25 /* DalleView.swift in Sources */,\n\t\t\t\t2CD965002C1CA3F3006DAD57 /* ChatView.swift in Sources */,\n\t\t\t\t2CD964FE2C1CA3DC006DAD57 /* MultiModalChatView.swift in Sources */,\n\t\t\t\t2C16EC352CB720580016790F /* TextToSpeechView.swift in Sources */,\n\t\t\t\t2CD964F22C1CA33B006DAD57 /* ContentView.swift in Sources */,\n\t\t\t\t2CD964F02C1CA33B006DAD57 /* AIProxyOpenAIApp.swift in Sources */,\n\t\t\t\t2CCB20342C6C03AF003A8B25 /* StreamingChatView.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t2CD964F82C1CA33D006DAD57 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.5;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"DEBUG $(inherited)\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2CD964F92C1CA33D006DAD57 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.5;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t2CD964FB2C1CA33D006DAD57 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"AIProxyOpenAI/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 553LMX46SJ;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.toddham.bootstrap;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2CD964FC2C1CA33D006DAD57 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"AIProxyOpenAI/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 553LMX46SJ;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.toddham.bootstrap;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t2CD964E72C1CA33B006DAD57 /* Build configuration list for PBXProject \"AIProxyOpenAI\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2CD964F82C1CA33D006DAD57 /* Debug */,\n\t\t\t\t2CD964F92C1CA33D006DAD57 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t2CD964FA2C1CA33D006DAD57 /* Build configuration list for PBXNativeTarget \"AIProxyOpenAI\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2CD964FB2C1CA33D006DAD57 /* Debug */,\n\t\t\t\t2CD964FC2C1CA33D006DAD57 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCRemoteSwiftPackageReference section */\n\t\t2CD965012C1CA4BB006DAD57 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/lzell/AIProxySwift\";\n\t\t\trequirement = {\n\t\t\t\tbranch = main;\n\t\t\t\tkind = branch;\n\t\t\t};\n\t\t};\n/* End XCRemoteSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */\n\t\t2CD965022C1CA4BB006DAD57 /* AIProxy */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 2CD965012C1CA4BB006DAD57 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */;\n\t\t\tproductName = AIProxy;\n\t\t};\n/* End XCSwiftPackageProductDependency section */\n\t};\n\trootObject = 2CD964E42C1CA33B006DAD57 /* Project object */;\n}\n"
  },
  {
    "path": "AIProxyReplicate/AIProxyReplicate/AIProxyReplicateApp.swift",
    "content": "//\n//  AIProxyReplicateApp.swift\n//  AIProxyReplicate\n//\n//  Created by Todd Hamilton on 6/13/24.\n//\n\nimport SwiftUI\n\n@main\nstruct AIProxyReplicateApp: App {\n    var body: some Scene {\n        WindowGroup {\n            ContentView()\n        }\n    }\n}\n"
  },
  {
    "path": "AIProxyReplicate/AIProxyReplicate/AppConstants.swift",
    "content": "//\n//  AppConstants.swift\n//  AIProxyReplicate\n//\n//  Created by Todd Hamilton on 6/13/24.\n//\n\nimport AIProxy\n\n#error(\n    \"\"\"\n    Uncomment one of the methods below. To build and run on device you must follow the AIProxy integration guide.\n    Please see https://www.aiproxy.pro/docs/integration-guide.html\")\n    \"\"\"\n)\n\n/* Uncomment for BYOK use cases */\nlet replicateService = AIProxy.replicateDirectService(\n    unprotectedAPIKey: \"your-replicate-key\"\n)\n\n/* Uncomment for all other production use cases */\n//let replicateService = AIProxy.replicateService(\n//    partialKey: \"partial-key-from-your-developer-dashboard\",\n//    serviceURL: \"service-url-from-your-developer-dashboard\"\n//)\n"
  },
  {
    "path": "AIProxyReplicate/AIProxyReplicate/Assets.xcassets/AccentColor.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyReplicate/AIProxyReplicate/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyReplicate/AIProxyReplicate/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyReplicate/AIProxyReplicate/Assets.xcassets/replicate.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"replicate.jpeg\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyReplicate/AIProxyReplicate/ContentView.swift",
    "content": "//\n//  ContentView.swift\n//  AIProxyReplicate\n//\n//  Created by Todd Hamilton on 6/13/24.\n//\n\nimport SwiftUI\n\nstruct ContentView: View {\n    var body: some View {\n        NavigationStack{\n            VStack(spacing:24){\n                VStack{\n                    Image(\"replicate\")\n                        .resizable()\n                        .scaledToFit()\n                        .frame(width: /*@START_MENU_TOKEN@*/100/*@END_MENU_TOKEN@*/)\n                        .cornerRadius(14)\n                        .foregroundColor(.primary)\n                    Text(\"Replicate\")\n                        .bold()\n                        .font(.largeTitle)\n                    Text(\"AIProxy Samples\")\n                        .font(.subheadline)\n                        .foregroundColor(.secondary)\n                }\n                .frame(maxWidth:.infinity,alignment:.center)\n                \n                VStack{\n                    NavigationLink(\"Generate Image Example\",destination: ImageGenView())\n                        .bold()\n                        .controlSize(.large)\n                        .tint(.pink)\n                        .buttonStyle(.bordered)\n                }\n            }\n        }\n    }\n}\n\n#Preview {\n    ContentView()\n}\n\n"
  },
  {
    "path": "AIProxyReplicate/AIProxyReplicate/ImageGenView.swift",
    "content": "//\n//  ImageGenView.swift\n//  AIProxyReplicate\n//\n//  Created by Todd Hamilton on 6/13/24.\n//\n\nimport SwiftUI\nimport AIProxy\n\nstruct ImageGenView: View {\n    \n    @State private var prompt = \"\"\n    @State private var imageUrl: URL?\n    @State private var isLoading = false\n\n    func generate() async throws {\n        isLoading = true  // Start loading\n        defer { isLoading = false }\n        do {\n            let input = ReplicateSDXLInputSchema(\n                prompt: prompt\n            )\n            let output = try await replicateService.createSDXLImage(\n                input: input\n            )\n            print(\"Done creating SDXL image: \", output.first ?? \"\")\n            imageUrl = output.first\n        }  catch AIProxyError.unsuccessfulRequest(let statusCode, let responseBody) {\n            print(\"Received non-200 status code: \\(statusCode) with response body: \\(responseBody)\")\n        } catch {\n            print(\"Could not create SDXL image: \\(error.localizedDescription)\")\n        }\n    }\n    \n    var body: some View {\n        VStack{\n                \n            VStack{\n                if (imageUrl != nil) {\n                    AsyncImage(url: imageUrl) { phase in\n                        if let image = phase.image {\n                            image\n                                .resizable()\n                                .aspectRatio(contentMode: .fit)\n                        } else if phase.error != nil {\n                            Text(\"Failed to load image\")\n                                .foregroundColor(.red)\n                        } else {\n                            ProgressView()\n                        }\n                    }\n                } else{\n                    ContentUnavailableView(\n                        \"Generate an image\",\n                        systemImage: \"photo.fill\",\n                        description: Text(\"Write a prompt below\")\n                    )\n                }\n            }\n            .frame(maxHeight: .infinity)\n            \n            Spacer()\n            \n            VStack(spacing:12){\n                TextField(\"Type a prompt\", text:$prompt)\n                    .submitLabel(.go)\n                    .padding(12)\n                    .background(.white)\n                    .cornerRadius(8)\n                    .shadow(radius: 1)\n                    .onSubmit {\n                        Task{ try await generate() }\n                    }\n                Button{\n                    Task{ try await generate() }\n                }label:{\n                    if isLoading {\n                        ProgressView()\n                            .controlSize(.regular)\n                            .frame(maxWidth:.infinity)\n                    } else {\n                        Text(\"Generate Text\")\n                            .bold()\n                            .frame(maxWidth:.infinity)\n                    }\n                }\n                .controlSize(.large)\n                .buttonStyle(.borderedProminent)\n                .disabled(isLoading ? true : false)\n            }\n        }\n        .padding()\n        .navigationTitle(\"Generate Image\")\n        .navigationBarTitleDisplayMode(.inline)\n    }\n}\n\n#Preview {\n    ImageGenView()\n}\n"
  },
  {
    "path": "AIProxyReplicate/AIProxyReplicate/Preview Content/Preview Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyReplicate/AIProxyReplicate.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 56;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t2C205C532C7F62330030E7AC /* AIProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 2C205C522C7F62330030E7AC /* AIProxy */; };\n\t\t2CD964872C1B98F5006DAD57 /* AIProxyReplicateApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD964862C1B98F5006DAD57 /* AIProxyReplicateApp.swift */; };\n\t\t2CD964892C1B98F5006DAD57 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD964882C1B98F5006DAD57 /* ContentView.swift */; };\n\t\t2CD9648B2C1B98F7006DAD57 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2CD9648A2C1B98F7006DAD57 /* Assets.xcassets */; };\n\t\t2CD9648E2C1B98F7006DAD57 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2CD9648D2C1B98F7006DAD57 /* Preview Assets.xcassets */; };\n\t\t2CD9649C2C1B995F006DAD57 /* ImageGenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD9649B2C1B995F006DAD57 /* ImageGenView.swift */; };\n\t\t2CD964E02C1BDC53006DAD57 /* AppConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD964DF2C1BDC53006DAD57 /* AppConstants.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t2CD964832C1B98F5006DAD57 /* AIProxyReplicate.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AIProxyReplicate.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t2CD964862C1B98F5006DAD57 /* AIProxyReplicateApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AIProxyReplicateApp.swift; sourceTree = \"<group>\"; };\n\t\t2CD964882C1B98F5006DAD57 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = \"<group>\"; };\n\t\t2CD9648A2C1B98F7006DAD57 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t2CD9648D2C1B98F7006DAD57 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = \"Preview Assets.xcassets\"; sourceTree = \"<group>\"; };\n\t\t2CD9649B2C1B995F006DAD57 /* ImageGenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageGenView.swift; sourceTree = \"<group>\"; };\n\t\t2CD964DF2C1BDC53006DAD57 /* AppConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConstants.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t2CD964802C1B98F5006DAD57 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2C205C532C7F62330030E7AC /* AIProxy in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t2CD9647A2C1B98F5006DAD57 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CD964852C1B98F5006DAD57 /* AIProxyReplicate */,\n\t\t\t\t2CD964842C1B98F5006DAD57 /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2CD964842C1B98F5006DAD57 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CD964832C1B98F5006DAD57 /* AIProxyReplicate.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2CD964852C1B98F5006DAD57 /* AIProxyReplicate */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CD964862C1B98F5006DAD57 /* AIProxyReplicateApp.swift */,\n\t\t\t\t2CD964882C1B98F5006DAD57 /* ContentView.swift */,\n\t\t\t\t2CD9649B2C1B995F006DAD57 /* ImageGenView.swift */,\n\t\t\t\t2CD964DF2C1BDC53006DAD57 /* AppConstants.swift */,\n\t\t\t\t2CD9648A2C1B98F7006DAD57 /* Assets.xcassets */,\n\t\t\t\t2CD9648C2C1B98F7006DAD57 /* Preview Content */,\n\t\t\t);\n\t\t\tpath = AIProxyReplicate;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2CD9648C2C1B98F7006DAD57 /* Preview Content */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CD9648D2C1B98F7006DAD57 /* Preview Assets.xcassets */,\n\t\t\t);\n\t\t\tpath = \"Preview Content\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t2CD964822C1B98F5006DAD57 /* AIProxyReplicate */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 2CD964912C1B98F7006DAD57 /* Build configuration list for PBXNativeTarget \"AIProxyReplicate\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t2CD9647F2C1B98F5006DAD57 /* Sources */,\n\t\t\t\t2CD964802C1B98F5006DAD57 /* Frameworks */,\n\t\t\t\t2CD964812C1B98F5006DAD57 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = AIProxyReplicate;\n\t\t\tpackageProductDependencies = (\n\t\t\t\t2C205C522C7F62330030E7AC /* AIProxy */,\n\t\t\t);\n\t\t\tproductName = AIProxyReplicate;\n\t\t\tproductReference = 2CD964832C1B98F5006DAD57 /* AIProxyReplicate.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t2CD9647B2C1B98F5006DAD57 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = 1;\n\t\t\t\tLastSwiftUpdateCheck = 1540;\n\t\t\t\tLastUpgradeCheck = 1540;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t2CD964822C1B98F5006DAD57 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 15.4;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 2CD9647E2C1B98F5006DAD57 /* Build configuration list for PBXProject \"AIProxyReplicate\" */;\n\t\t\tcompatibilityVersion = \"Xcode 14.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 2CD9647A2C1B98F5006DAD57;\n\t\t\tpackageReferences = (\n\t\t\t\t2C205C512C7F62330030E7AC /* XCRemoteSwiftPackageReference \"AIProxySwift\" */,\n\t\t\t);\n\t\t\tproductRefGroup = 2CD964842C1B98F5006DAD57 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t2CD964822C1B98F5006DAD57 /* AIProxyReplicate */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t2CD964812C1B98F5006DAD57 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2CD9648E2C1B98F7006DAD57 /* Preview Assets.xcassets in Resources */,\n\t\t\t\t2CD9648B2C1B98F7006DAD57 /* Assets.xcassets in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t2CD9647F2C1B98F5006DAD57 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2CD964892C1B98F5006DAD57 /* ContentView.swift in Sources */,\n\t\t\t\t2CD9649C2C1B995F006DAD57 /* ImageGenView.swift in Sources */,\n\t\t\t\t2CD964E02C1BDC53006DAD57 /* AppConstants.swift in Sources */,\n\t\t\t\t2CD964872C1B98F5006DAD57 /* AIProxyReplicateApp.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t2CD9648F2C1B98F7006DAD57 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.5;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"DEBUG $(inherited)\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2CD964902C1B98F7006DAD57 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.5;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t2CD964922C1B98F7006DAD57 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"AIProxyReplicate/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 553LMX46SJ;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.toddham.AIProxySampleApp;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2CD964932C1B98F7006DAD57 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"AIProxyReplicate/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 553LMX46SJ;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.toddham.AIProxySampleApp;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t2CD9647E2C1B98F5006DAD57 /* Build configuration list for PBXProject \"AIProxyReplicate\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2CD9648F2C1B98F7006DAD57 /* Debug */,\n\t\t\t\t2CD964902C1B98F7006DAD57 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t2CD964912C1B98F7006DAD57 /* Build configuration list for PBXNativeTarget \"AIProxyReplicate\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2CD964922C1B98F7006DAD57 /* Debug */,\n\t\t\t\t2CD964932C1B98F7006DAD57 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCRemoteSwiftPackageReference section */\n\t\t2C205C512C7F62330030E7AC /* XCRemoteSwiftPackageReference \"AIProxySwift\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/lzell/AIProxySwift\";\n\t\t\trequirement = {\n\t\t\t\tbranch = main;\n\t\t\t\tkind = branch;\n\t\t\t};\n\t\t};\n/* End XCRemoteSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */\n\t\t2C205C522C7F62330030E7AC /* AIProxy */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 2C205C512C7F62330030E7AC /* XCRemoteSwiftPackageReference \"AIProxySwift\" */;\n\t\t\tproductName = AIProxy;\n\t\t};\n/* End XCSwiftPackageProductDependency section */\n\t};\n\trootObject = 2CD9647B2C1B98F5006DAD57 /* Project object */;\n}\n"
  },
  {
    "path": "AIProxyStabilityAI/AIProxyStabilityAI/AIProxyStabilityAIApp.swift",
    "content": "//\n//  AIProxyStabilityAIApp.swift\n//  AIProxyStabilityAI\n//\n//  Created by Todd Hamilton on 8/13/24.\n//\n\nimport SwiftUI\n\n@main\nstruct AIProxyStabilityAIApp: App {\n    var body: some Scene {\n        WindowGroup {\n            ContentView()\n        }\n    }\n}\n"
  },
  {
    "path": "AIProxyStabilityAI/AIProxyStabilityAI/AppConstants.swift",
    "content": "//\n//  AppConstants.swift\n//  AIProxyStabilityAI\n//\n//  Created by Todd Hamilton on 8/13/24.\n//\n\nimport AIProxy\n\n#error(\n    \"\"\"\n    Uncomment one of the methods below. To build and run on device you must follow the AIProxy integration guide.\n    Please see https://www.aiproxy.pro/docs/integration-guide.html\")\n    \"\"\"\n)\n\n/* Uncomment for BYOK use cases */\nlet stabilityService = AIProxy.stabilityAIDirectService(\n    unprotectedAPIKey: \"your-stability-key\"\n)\n\n/* Uncomment for all other production use cases */\n//let stabilityService = AIProxy.stabilityAIService(\n//    partialKey: \"partial-key-from-your-developer-dashboard\",\n//    serviceURL: \"service-url-from-your-developer-dashboard\"\n//)\n"
  },
  {
    "path": "AIProxyStabilityAI/AIProxyStabilityAI/Assets.xcassets/AccentColor.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyStabilityAI/AIProxyStabilityAI/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyStabilityAI/AIProxyStabilityAI/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyStabilityAI/AIProxyStabilityAI/Assets.xcassets/stability.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"stability.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyStabilityAI/AIProxyStabilityAI/ContentView.swift",
    "content": "//\n//  ContentView.swift\n//  AIProxyStabilityAI\n//\n//  Created by Todd Hamilton on 8/13/24.\n//\n\nimport SwiftUI\n\nstruct ContentView: View {\n    var body: some View {\n        NavigationStack{\n            \n            VStack(spacing:48){\n                VStack{\n                    Image(\"stability\")\n                        .resizable()\n                        .scaledToFit()\n                        .frame(width: /*@START_MENU_TOKEN@*/100/*@END_MENU_TOKEN@*/)\n                        .cornerRadius(14)\n                        .foregroundColor(.primary)\n                    Text(\"Stability.ai\")\n                        .bold()\n                        .font(.largeTitle)\n                    Text(\"AIProxy Sample\")\n                        .font(.subheadline)\n                        .foregroundColor(.secondary)\n                }\n                .frame(maxWidth:.infinity,alignment:.center)\n                \n                VStack{\n                    NavigationLink(\"Generate Image Example\",destination: ImageGenView())\n                        .bold()\n                        .controlSize(.large)\n                        .tint(.indigo)\n                        .buttonStyle(.bordered)\n                }\n            }\n        }\n    }\n}\n\n#Preview {\n    ContentView()\n}\n"
  },
  {
    "path": "AIProxyStabilityAI/AIProxyStabilityAI/ImageGenView.swift",
    "content": "//\n//  ImageGenView.swift\n//  AIProxyStabilityAI\n//\n//  Created by Todd Hamilton on 8/13/24.\n//\n\nimport SwiftUI\nimport AIProxy\n\nstruct ImageGenView: View {\n    \n    @State private var prompt = \"\"\n    @State private var image: UIImage? = nil\n    @State private var isLoading = false\n    \n    func generate() async throws {\n        isLoading = true  // Start loading\n        defer { isLoading = false }\n        do {\n            let body = StabilityAIUltraRequestBody(prompt: prompt)\n            \n            // This demo is of text-to-image, which only requires a prompt\n            // To use image-to-image the following parameters are required:\n            // prompt - text to generate the image from\n            // image - the image to use as the starting point for the generation\n            // strength - controls how much influence the image parameter has on the output image\n            // mode - must be set to image-to-image\n            // Learn more: https://platform.stability.ai/docs/api-reference#tag/Generate\n            \n            let response = try await stabilityService.ultraRequest(body: body)\n            image = UIImage(data: response.imageData)\n        }  catch AIProxyError.unsuccessfulRequest(let statusCode, let responseBody) {\n            print(\"Received non-200 status code: \\(statusCode) with response body: \\(responseBody)\")\n        } catch {\n            print(error.localizedDescription)\n        }\n    }\n    \n    var body: some View {\n        VStack{\n                \n            VStack{\n                if (image != nil) {\n                    Image(uiImage: image!)\n                        .resizable()\n                        .aspectRatio(contentMode: .fit)\n                        .frame(maxHeight: UIScreen.main.bounds.width)\n                } else{\n                    ContentUnavailableView(\n                        \"Generate an image\",\n                        systemImage: \"photo.fill\",\n                        description: Text(\"Write a prompt below\")\n                    )\n                }\n            }\n            .frame(maxHeight: .infinity)\n            \n            Spacer()\n            \n            VStack(spacing:12){\n                TextField(\"Type a prompt\", text:$prompt)\n                    .submitLabel(.go)\n                    .padding(12)\n                    .background(Color(.systemBackground))\n                    .cornerRadius(8)\n                    .shadow(color:.primary, radius: 1)\n                    .onSubmit {\n                        Task{ try await generate() }\n                    }\n                Button{\n                    Task{ try await generate() }\n                }label:{\n                    if isLoading {\n                        ProgressView()\n                            .controlSize(.regular)\n                            .frame(maxWidth:.infinity)\n                    } else {\n                        Text(\"Generate Image\")\n                            .bold()\n                            .frame(maxWidth:.infinity)\n                    }\n                }\n                .controlSize(.large)\n                .buttonStyle(.borderedProminent)\n                .disabled(isLoading ? true : false)\n            }\n        }\n        .padding()\n        .navigationTitle(\"Generate Image\")\n        .navigationBarTitleDisplayMode(.inline)\n    }\n}\n\n#Preview {\n    ImageGenView()\n}\n"
  },
  {
    "path": "AIProxyStabilityAI/AIProxyStabilityAI/Preview Content/Preview Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyStabilityAI/AIProxyStabilityAI.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 56;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t2C1C112D2C6BE4A9000B80E0 /* AIProxyStabilityAIApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C1C112C2C6BE4A9000B80E0 /* AIProxyStabilityAIApp.swift */; };\n\t\t2C1C112F2C6BE4A9000B80E0 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C1C112E2C6BE4A9000B80E0 /* ContentView.swift */; };\n\t\t2C1C11312C6BE4AA000B80E0 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2C1C11302C6BE4AA000B80E0 /* Assets.xcassets */; };\n\t\t2C1C11342C6BE4AA000B80E0 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2C1C11332C6BE4AA000B80E0 /* Preview Assets.xcassets */; };\n\t\t2C1C113C2C6BE4D1000B80E0 /* AIProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 2C1C113B2C6BE4D1000B80E0 /* AIProxy */; };\n\t\t2C1C113E2C6BE4FA000B80E0 /* AppConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C1C113D2C6BE4FA000B80E0 /* AppConstants.swift */; };\n\t\t2C1C11402C6BE57A000B80E0 /* ImageGenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C1C113F2C6BE57A000B80E0 /* ImageGenView.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t2C1C11292C6BE4A9000B80E0 /* AIProxyStabilityAI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AIProxyStabilityAI.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t2C1C112C2C6BE4A9000B80E0 /* AIProxyStabilityAIApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AIProxyStabilityAIApp.swift; sourceTree = \"<group>\"; };\n\t\t2C1C112E2C6BE4A9000B80E0 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = \"<group>\"; };\n\t\t2C1C11302C6BE4AA000B80E0 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t2C1C11332C6BE4AA000B80E0 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = \"Preview Assets.xcassets\"; sourceTree = \"<group>\"; };\n\t\t2C1C113D2C6BE4FA000B80E0 /* AppConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConstants.swift; sourceTree = \"<group>\"; };\n\t\t2C1C113F2C6BE57A000B80E0 /* ImageGenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageGenView.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t2C1C11262C6BE4A9000B80E0 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2C1C113C2C6BE4D1000B80E0 /* AIProxy in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t2C1C11202C6BE4A9000B80E0 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2C1C112B2C6BE4A9000B80E0 /* AIProxyStabilityAI */,\n\t\t\t\t2C1C112A2C6BE4A9000B80E0 /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2C1C112A2C6BE4A9000B80E0 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2C1C11292C6BE4A9000B80E0 /* AIProxyStabilityAI.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2C1C112B2C6BE4A9000B80E0 /* AIProxyStabilityAI */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2C1C112C2C6BE4A9000B80E0 /* AIProxyStabilityAIApp.swift */,\n\t\t\t\t2C1C112E2C6BE4A9000B80E0 /* ContentView.swift */,\n\t\t\t\t2C1C113F2C6BE57A000B80E0 /* ImageGenView.swift */,\n\t\t\t\t2C1C113D2C6BE4FA000B80E0 /* AppConstants.swift */,\n\t\t\t\t2C1C11302C6BE4AA000B80E0 /* Assets.xcassets */,\n\t\t\t\t2C1C11322C6BE4AA000B80E0 /* Preview Content */,\n\t\t\t);\n\t\t\tpath = AIProxyStabilityAI;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2C1C11322C6BE4AA000B80E0 /* Preview Content */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2C1C11332C6BE4AA000B80E0 /* Preview Assets.xcassets */,\n\t\t\t);\n\t\t\tpath = \"Preview Content\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t2C1C11282C6BE4A9000B80E0 /* AIProxyStabilityAI */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 2C1C11372C6BE4AA000B80E0 /* Build configuration list for PBXNativeTarget \"AIProxyStabilityAI\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t2C1C11252C6BE4A9000B80E0 /* Sources */,\n\t\t\t\t2C1C11262C6BE4A9000B80E0 /* Frameworks */,\n\t\t\t\t2C1C11272C6BE4A9000B80E0 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = AIProxyStabilityAI;\n\t\t\tpackageProductDependencies = (\n\t\t\t\t2C1C113B2C6BE4D1000B80E0 /* AIProxy */,\n\t\t\t);\n\t\t\tproductName = AIProxyStabilityAI;\n\t\t\tproductReference = 2C1C11292C6BE4A9000B80E0 /* AIProxyStabilityAI.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t2C1C11212C6BE4A9000B80E0 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = 1;\n\t\t\t\tLastSwiftUpdateCheck = 1540;\n\t\t\t\tLastUpgradeCheck = 1540;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t2C1C11282C6BE4A9000B80E0 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 15.4;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 2C1C11242C6BE4A9000B80E0 /* Build configuration list for PBXProject \"AIProxyStabilityAI\" */;\n\t\t\tcompatibilityVersion = \"Xcode 14.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 2C1C11202C6BE4A9000B80E0;\n\t\t\tpackageReferences = (\n\t\t\t\t2C1C113A2C6BE4D1000B80E0 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */,\n\t\t\t);\n\t\t\tproductRefGroup = 2C1C112A2C6BE4A9000B80E0 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t2C1C11282C6BE4A9000B80E0 /* AIProxyStabilityAI */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t2C1C11272C6BE4A9000B80E0 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2C1C11342C6BE4AA000B80E0 /* Preview Assets.xcassets in Resources */,\n\t\t\t\t2C1C11312C6BE4AA000B80E0 /* Assets.xcassets in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t2C1C11252C6BE4A9000B80E0 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2C1C112F2C6BE4A9000B80E0 /* ContentView.swift in Sources */,\n\t\t\t\t2C1C11402C6BE57A000B80E0 /* ImageGenView.swift in Sources */,\n\t\t\t\t2C1C113E2C6BE4FA000B80E0 /* AppConstants.swift in Sources */,\n\t\t\t\t2C1C112D2C6BE4A9000B80E0 /* AIProxyStabilityAIApp.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t2C1C11352C6BE4AA000B80E0 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.5;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"DEBUG $(inherited)\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2C1C11362C6BE4AA000B80E0 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.5;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t2C1C11382C6BE4AA000B80E0 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"AIProxyStabilityAI/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 553LMX46SJ;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.toddham.AIProxySampleApp;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2C1C11392C6BE4AA000B80E0 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"AIProxyStabilityAI/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 553LMX46SJ;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.toddham.AIProxySampleApp;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t2C1C11242C6BE4A9000B80E0 /* Build configuration list for PBXProject \"AIProxyStabilityAI\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2C1C11352C6BE4AA000B80E0 /* Debug */,\n\t\t\t\t2C1C11362C6BE4AA000B80E0 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t2C1C11372C6BE4AA000B80E0 /* Build configuration list for PBXNativeTarget \"AIProxyStabilityAI\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2C1C11382C6BE4AA000B80E0 /* Debug */,\n\t\t\t\t2C1C11392C6BE4AA000B80E0 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCRemoteSwiftPackageReference section */\n\t\t2C1C113A2C6BE4D1000B80E0 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/lzell/AIProxySwift\";\n\t\t\trequirement = {\n\t\t\t\tbranch = main;\n\t\t\t\tkind = branch;\n\t\t\t};\n\t\t};\n/* End XCRemoteSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */\n\t\t2C1C113B2C6BE4D1000B80E0 /* AIProxy */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 2C1C113A2C6BE4D1000B80E0 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */;\n\t\t\tproductName = AIProxy;\n\t\t};\n/* End XCSwiftPackageProductDependency section */\n\t};\n\trootObject = 2C1C11212C6BE4A9000B80E0 /* Project object */;\n}\n"
  },
  {
    "path": "AIProxyTogetherAI/AIProxyTogetherAI/AIProxyTogetherAIApp.swift",
    "content": "//\n//  AIProxyTogetherAIApp.swift\n//  AIProxyTogetherAI\n//\n//  Created by Todd Hamilton on 8/18/24.\n//\n\nimport SwiftUI\n\n@main\nstruct AIProxyTogetherAIApp: App {\n    var body: some Scene {\n        WindowGroup {\n            ContentView()\n        }\n    }\n}\n"
  },
  {
    "path": "AIProxyTogetherAI/AIProxyTogetherAI/AppConstants.swift",
    "content": "//\n//  AppConstants.swift\n//  AIProxyTogetherAI\n//\n//  Created by Todd Hamilton on 8/18/24.\n//\n\nimport AIProxy\n\n#error(\n    \"\"\"\n    Uncomment one of the methods below. To build and run on device you must follow the AIProxy integration guide.\n    Please see https://www.aiproxy.pro/docs/integration-guide.html\")\n    \"\"\"\n)\n\n/* Uncomment for BYOK use cases */\nlet togetherAIService = AIProxy.togetherAIDirectService(\n    unprotectedAPIKey: \"your-togetherAI-key\"\n)\n\n/* Uncomment for all other production use cases */\n//let togetherAIService = AIProxy.togetherAIService(\n//    partialKey: \"partial-key-from-your-developer-dashboard\",\n//    serviceURL: \"service-url-from-your-developer-dashboard\"\n//)\n"
  },
  {
    "path": "AIProxyTogetherAI/AIProxyTogetherAI/Assets.xcassets/AccentColor.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyTogetherAI/AIProxyTogetherAI/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyTogetherAI/AIProxyTogetherAI/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyTogetherAI/AIProxyTogetherAI/Assets.xcassets/togetherai.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"togetherai.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyTogetherAI/AIProxyTogetherAI/ChatView.swift",
    "content": "//\n//  ChatView.swift\n//  AIProxyTogetherAI\n//\n//  Created by Todd Hamilton on 8/18/24.\n//\n\nimport SwiftUI\nimport AIProxy\n\nstruct ChatView: View {\n    \n    @State private var prompt = \"\"\n    @State private var result = \"\"\n    @State private var isLoading = false\n    @State private var showingAlert = false\n    \n    func generate() async throws {\n        isLoading = true\n        defer { isLoading = false }\n        do {\n            let requestBody = TogetherAIChatCompletionRequestBody(\n                messages: [TogetherAIMessage(content: prompt, role: .user)],\n                model: \"meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo\"\n            )\n            let response = try await togetherAIService.chatCompletionRequest(body: requestBody)\n            print(response.choices.first?.message.content ?? \"\")\n            result = response.choices.first?.message.content ?? \"\"\n            showingAlert = true\n        }  catch AIProxyError.unsuccessfulRequest(let statusCode, let responseBody) {\n            print(\"Received non-200 status code: \\(statusCode) with response body: \\(responseBody)\")\n        } catch {\n            print(\"Could not create TogetherAI chat completion: \\(error.localizedDescription)\")\n        }\n    }\n    \n    var body: some View {\n        VStack {\n            VStack{\n                ContentUnavailableView(\n                    \"Generate Text\",\n                    systemImage: \"doc.plaintext.fill\",\n                    description: Text(\"Write a prompt below\")\n                )\n            }\n            .alert(isPresented: $showingAlert) {\n                Alert(\n                    title: Text(\"Result\"),\n                    message: Text(result),\n                    dismissButton: .default(Text(\"Close\"))\n                )\n            }\n\n            Spacer()\n            \n            VStack(spacing:12){\n                TextField(\"Type a prompt\", text:$prompt)\n                    .submitLabel(.go)\n                    .padding(12)\n                    .background(.white)\n                    .cornerRadius(8)\n                    .shadow(radius: 1)\n                    .onSubmit {\n                        Task{ try await generate() }\n                    }\n                Button{\n                    Task{ try await generate() }\n                }label:{\n                    if isLoading {\n                        ProgressView()\n                            .controlSize(.regular)\n                            .frame(maxWidth:.infinity)\n                    } else {\n                        Text(\"Generate Text\")\n                            .bold()\n                            .frame(maxWidth:.infinity)\n                    }\n                }\n                .controlSize(.large)\n                .buttonStyle(.borderedProminent)\n                .disabled(isLoading ? true : false)\n            }\n        }\n        .padding()\n        .navigationTitle(\"Chat Example\")\n        .navigationBarTitleDisplayMode(.inline)\n    }\n}\n\n#Preview {\n    ChatView()\n}\n"
  },
  {
    "path": "AIProxyTogetherAI/AIProxyTogetherAI/ContentView.swift",
    "content": "//\n//  ContentView.swift\n//  AIProxyTogetherAI\n//\n//  Created by Todd Hamilton on 8/18/24.\n//\n\nimport SwiftUI\n\nstruct ContentView: View {\n    var body: some View {\n        NavigationStack{\n            \n            VStack(spacing:48){\n                VStack{\n                    Image(\"togetherai\")\n                        .resizable()\n                        .scaledToFit()\n                        .frame(width: /*@START_MENU_TOKEN@*/100/*@END_MENU_TOKEN@*/)\n                        .cornerRadius(14)\n                        .foregroundColor(.primary)\n                    Text(\"Together AI\")\n                        .bold()\n                        .font(.largeTitle)\n                    Text(\"AIProxy Sample\")\n                        .font(.subheadline)\n                        .foregroundColor(.secondary)\n                }\n                .frame(maxWidth:.infinity,alignment:.center)\n                \n                VStack{\n                    NavigationLink(\"Chat Example\",destination: ChatView())\n                        .bold()\n                        .controlSize(.large)\n                        .tint(.blue)\n                        .buttonStyle(.bordered)\n                    NavigationLink(\"Streaming Chat Example\",destination: StreamingChatView())\n                        .bold()\n                        .controlSize(.large)\n                        .tint(.blue)\n                        .buttonStyle(.bordered)\n                    NavigationLink(\"JSON Response\",destination: JSONResponseView())\n                        .bold()\n                        .controlSize(.large)\n                        .tint(.blue)\n                        .buttonStyle(.bordered)\n                    \n                }\n            }\n        }\n    }\n}\n\n#Preview {\n    ContentView()\n}\n"
  },
  {
    "path": "AIProxyTogetherAI/AIProxyTogetherAI/JSONResponseView.swift",
    "content": "//\n//  JSONResponseView.swift\n//  AIProxyTogetherAI\n//\n//  Created by Todd Hamilton on 8/18/24.\n//\n\nimport SwiftUI\nimport AIProxy\n\nstruct JSONResponseView: View {\n    @State private var prompt = \"\"\n    @State private var result = \"\"\n    @State private var isLoading = false\n    @State private var showingAlert = false\n    \n    func generate() async throws {\n        isLoading = true\n        defer { isLoading = false }\n        do {\n            let schema: [String: AIProxyJSONValue] = [\n                \"type\": \"object\",\n                \"properties\": [\n                    \"people\": [\n                        \"type\": \"array\",\n                        \"items\": [\n                            \"type\": \"object\",\n                            \"properties\": [\n                                \"name\": [\n                                    \"type\": \"string\",\n                                    \"description\": \"The name of the person\"\n                                ],\n                                \"address\": [\n                                    \"type\": \"string\",\n                                    \"description\": \"The address of the person\"\n                                ]\n                            ],\n                            \"required\": [\"name\", \"address\"]\n                        ]\n                    ]\n                ]\n            ]\n            let requestBody = TogetherAIChatCompletionRequestBody(\n                messages: [\n                    TogetherAIMessage(\n                        content: \"You are a helpful assistant that answers in JSON\",\n                        role: .system\n                    ),\n                    TogetherAIMessage(\n                        content: prompt,\n                        role: .user\n                    )\n                ],\n                model: \"meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo\",\n                responseFormat: .json(schema: schema)\n            )\n            let response = try await togetherAIService.chatCompletionRequest(body: requestBody)\n            print(response.choices.first?.message.content ?? \"\")\n            result = response.choices.first?.message.content ?? \"\"\n            showingAlert = true\n        }  catch AIProxyError.unsuccessfulRequest(let statusCode, let responseBody) {\n            print(\"Received non-200 status code: \\(statusCode) with response body: \\(responseBody)\")\n        } catch {\n            print(\"Could not create TogetherAI JSON chat completion: \\(error.localizedDescription)\")\n        }\n    }\n    \n    var body: some View {\n        VStack {\n            VStack{\n                ContentUnavailableView(\n                    \"Generate JSON\",\n                    systemImage: \"doc.plaintext.fill\",\n                    description: Text(\"Write a prompt below\")\n                )\n            }\n            .alert(isPresented: $showingAlert) {\n                Alert(\n                    title: Text(\"Result\"),\n                    message: Text(result),\n                    dismissButton: .default(Text(\"Close\"))\n                )\n            }\n\n            Spacer()\n            \n            VStack(spacing:12){\n                TextField(\"Type a prompt\", text:$prompt)\n                    .submitLabel(.go)\n                    .padding(12)\n                    .background(.white)\n                    .cornerRadius(8)\n                    .shadow(radius: 1)\n                    .onSubmit {\n                        Task{ try await generate() }\n                    }\n                Button{\n                    Task{ try await generate() }\n                }label:{\n                    if isLoading {\n                        ProgressView()\n                            .controlSize(.regular)\n                            .frame(maxWidth:.infinity)\n                    } else {\n                        Text(\"Generate JSON\")\n                            .bold()\n                            .frame(maxWidth:.infinity)\n                    }\n                }\n                .controlSize(.large)\n                .buttonStyle(.borderedProminent)\n                .disabled(isLoading ? true : false)\n            }\n        }\n        .padding()\n        .navigationTitle(\"JSON Example\")\n        .navigationBarTitleDisplayMode(.inline)\n    }\n}\n\n#Preview {\n    JSONResponseView()\n}\n"
  },
  {
    "path": "AIProxyTogetherAI/AIProxyTogetherAI/Preview Content/Preview Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "AIProxyTogetherAI/AIProxyTogetherAI/StreamingChatView.swift",
    "content": "//\n//  StreamingChatView.swift\n//  AIProxyTogetherAI\n//\n//  Created by Todd Hamilton on 8/18/24.\n//\n\nimport SwiftUI\nimport AIProxy\n\nstruct StreamingChatView: View {\n    @State private var prompt = \"\"\n    @State private var result = \"\"\n    @State private var isLoading = false\n    @State private var showingAlert = false\n    \n    func generate() async throws {\n        isLoading = true\n        defer { isLoading = false }\n        do {\n            let requestBody = TogetherAIChatCompletionRequestBody(\n                messages: [TogetherAIMessage(content: prompt, role: .user)],\n                model: \"meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo\"\n            )\n            let stream = try await togetherAIService.streamingChatCompletionRequest(body: requestBody)\n            for try await chunk in stream {\n                print(chunk.choices.first?.delta.content ?? \"\")\n            }\n        }  catch AIProxyError.unsuccessfulRequest(let statusCode, let responseBody) {\n            print(\"Received non-200 status code: \\(statusCode) with response body: \\(responseBody)\")\n        } catch {\n            print(\"Could not create TogetherAI streaming chat completion: \\(error.localizedDescription)\")\n        }\n    }\n    \n    var body: some View {\n        VStack {\n            VStack{\n                ContentUnavailableView(\n                    \"Generate Text\",\n                    systemImage: \"doc.plaintext.fill\",\n                    description: Text(\"Write a prompt below\")\n                )\n            }\n            .alert(isPresented: $showingAlert) {\n                Alert(\n                    title: Text(\"Result\"),\n                    message: Text(\"View streaming response in the Xcode console.\"),\n                    dismissButton: .default(Text(\"Close\"))\n                )\n            }\n\n            Spacer()\n            \n            VStack(spacing:12){\n                TextField(\"Type a prompt\", text:$prompt)\n                    .submitLabel(.go)\n                    .padding(12)\n                    .background(.white)\n                    .cornerRadius(8)\n                    .shadow(radius: 1)\n                    .onSubmit {\n                        Task{ try await generate() }\n                    }\n                Button{\n                    showingAlert = true\n                    Task{ try await generate() }\n                }label:{\n                    if isLoading {\n                        ProgressView()\n                            .controlSize(.regular)\n                            .frame(maxWidth:.infinity)\n                    } else {\n                        Text(\"Generate Text\")\n                            .bold()\n                            .frame(maxWidth:.infinity)\n                    }\n                }\n                .controlSize(.large)\n                .buttonStyle(.borderedProminent)\n                .disabled(isLoading ? true : false)\n            }\n        }\n        .padding()\n        .navigationTitle(\"Streaming Chat Example\")\n        .navigationBarTitleDisplayMode(.inline)\n    }\n}\n\n#Preview {\n    StreamingChatView()\n}\n"
  },
  {
    "path": "AIProxyTogetherAI/AIProxyTogetherAI.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 56;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t2CCA22CA2C72D78A0054393E /* AIProxyTogetherAIApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCA22C92C72D78A0054393E /* AIProxyTogetherAIApp.swift */; };\n\t\t2CCA22CC2C72D78A0054393E /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCA22CB2C72D78A0054393E /* ContentView.swift */; };\n\t\t2CCA22CE2C72D78B0054393E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2CCA22CD2C72D78B0054393E /* Assets.xcassets */; };\n\t\t2CCA22D12C72D78B0054393E /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2CCA22D02C72D78B0054393E /* Preview Assets.xcassets */; };\n\t\t2CCA22D92C72D7930054393E /* AIProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 2CCA22D82C72D7930054393E /* AIProxy */; };\n\t\t2CCA22DB2C72D7AD0054393E /* AppConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCA22DA2C72D7AD0054393E /* AppConstants.swift */; };\n\t\t2CCA22DD2C72DA570054393E /* ChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCA22DC2C72DA570054393E /* ChatView.swift */; };\n\t\t2CCA22DF2C72DBB00054393E /* StreamingChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCA22DE2C72DBB00054393E /* StreamingChatView.swift */; };\n\t\t2CCA22E12C72DDDE0054393E /* JSONResponseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCA22E02C72DDDE0054393E /* JSONResponseView.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t2CCA22C62C72D78A0054393E /* AIProxyTogetherAI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AIProxyTogetherAI.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t2CCA22C92C72D78A0054393E /* AIProxyTogetherAIApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AIProxyTogetherAIApp.swift; sourceTree = \"<group>\"; };\n\t\t2CCA22CB2C72D78A0054393E /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = \"<group>\"; };\n\t\t2CCA22CD2C72D78B0054393E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t2CCA22D02C72D78B0054393E /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = \"Preview Assets.xcassets\"; sourceTree = \"<group>\"; };\n\t\t2CCA22DA2C72D7AD0054393E /* AppConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConstants.swift; sourceTree = \"<group>\"; };\n\t\t2CCA22DC2C72DA570054393E /* ChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatView.swift; sourceTree = \"<group>\"; };\n\t\t2CCA22DE2C72DBB00054393E /* StreamingChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StreamingChatView.swift; sourceTree = \"<group>\"; };\n\t\t2CCA22E02C72DDDE0054393E /* JSONResponseView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONResponseView.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t2CCA22C32C72D78A0054393E /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2CCA22D92C72D7930054393E /* AIProxy in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t2CCA22BD2C72D78A0054393E = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CCA22C82C72D78A0054393E /* AIProxyTogetherAI */,\n\t\t\t\t2CCA22C72C72D78A0054393E /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2CCA22C72C72D78A0054393E /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CCA22C62C72D78A0054393E /* AIProxyTogetherAI.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2CCA22C82C72D78A0054393E /* AIProxyTogetherAI */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CCA22C92C72D78A0054393E /* AIProxyTogetherAIApp.swift */,\n\t\t\t\t2CCA22CB2C72D78A0054393E /* ContentView.swift */,\n\t\t\t\t2CCA22DC2C72DA570054393E /* ChatView.swift */,\n\t\t\t\t2CCA22DE2C72DBB00054393E /* StreamingChatView.swift */,\n\t\t\t\t2CCA22E02C72DDDE0054393E /* JSONResponseView.swift */,\n\t\t\t\t2CCA22DA2C72D7AD0054393E /* AppConstants.swift */,\n\t\t\t\t2CCA22CD2C72D78B0054393E /* Assets.xcassets */,\n\t\t\t\t2CCA22CF2C72D78B0054393E /* Preview Content */,\n\t\t\t);\n\t\t\tpath = AIProxyTogetherAI;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2CCA22CF2C72D78B0054393E /* Preview Content */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CCA22D02C72D78B0054393E /* Preview Assets.xcassets */,\n\t\t\t);\n\t\t\tpath = \"Preview Content\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t2CCA22C52C72D78A0054393E /* AIProxyTogetherAI */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 2CCA22D42C72D78B0054393E /* Build configuration list for PBXNativeTarget \"AIProxyTogetherAI\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t2CCA22C22C72D78A0054393E /* Sources */,\n\t\t\t\t2CCA22C32C72D78A0054393E /* Frameworks */,\n\t\t\t\t2CCA22C42C72D78A0054393E /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = AIProxyTogetherAI;\n\t\t\tpackageProductDependencies = (\n\t\t\t\t2CCA22D82C72D7930054393E /* AIProxy */,\n\t\t\t);\n\t\t\tproductName = AIProxyTogetherAI;\n\t\t\tproductReference = 2CCA22C62C72D78A0054393E /* AIProxyTogetherAI.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t2CCA22BE2C72D78A0054393E /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = 1;\n\t\t\t\tLastSwiftUpdateCheck = 1540;\n\t\t\t\tLastUpgradeCheck = 1540;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t2CCA22C52C72D78A0054393E = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 15.4;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 2CCA22C12C72D78A0054393E /* Build configuration list for PBXProject \"AIProxyTogetherAI\" */;\n\t\t\tcompatibilityVersion = \"Xcode 14.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 2CCA22BD2C72D78A0054393E;\n\t\t\tpackageReferences = (\n\t\t\t\t2CCA22D72C72D7930054393E /* XCRemoteSwiftPackageReference \"AIProxySwift\" */,\n\t\t\t);\n\t\t\tproductRefGroup = 2CCA22C72C72D78A0054393E /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t2CCA22C52C72D78A0054393E /* AIProxyTogetherAI */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t2CCA22C42C72D78A0054393E /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2CCA22D12C72D78B0054393E /* Preview Assets.xcassets in Resources */,\n\t\t\t\t2CCA22CE2C72D78B0054393E /* Assets.xcassets in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t2CCA22C22C72D78A0054393E /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2CCA22DD2C72DA570054393E /* ChatView.swift in Sources */,\n\t\t\t\t2CCA22E12C72DDDE0054393E /* JSONResponseView.swift in Sources */,\n\t\t\t\t2CCA22CC2C72D78A0054393E /* ContentView.swift in Sources */,\n\t\t\t\t2CCA22DB2C72D7AD0054393E /* AppConstants.swift in Sources */,\n\t\t\t\t2CCA22DF2C72DBB00054393E /* StreamingChatView.swift in Sources */,\n\t\t\t\t2CCA22CA2C72D78A0054393E /* AIProxyTogetherAIApp.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t2CCA22D22C72D78B0054393E /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.5;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"DEBUG $(inherited)\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2CCA22D32C72D78B0054393E /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.5;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t2CCA22D52C72D78B0054393E /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"AIProxyTogetherAI/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 553LMX46SJ;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.toddham.AIProxyTogetherAI;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2CCA22D62C72D78B0054393E /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"AIProxyTogetherAI/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 553LMX46SJ;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.toddham.AIProxyTogetherAI;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t2CCA22C12C72D78A0054393E /* Build configuration list for PBXProject \"AIProxyTogetherAI\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2CCA22D22C72D78B0054393E /* Debug */,\n\t\t\t\t2CCA22D32C72D78B0054393E /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t2CCA22D42C72D78B0054393E /* Build configuration list for PBXNativeTarget \"AIProxyTogetherAI\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2CCA22D52C72D78B0054393E /* Debug */,\n\t\t\t\t2CCA22D62C72D78B0054393E /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCRemoteSwiftPackageReference section */\n\t\t2CCA22D72C72D7930054393E /* XCRemoteSwiftPackageReference \"AIProxySwift\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/lzell/AIProxySwift\";\n\t\t\trequirement = {\n\t\t\t\tbranch = main;\n\t\t\t\tkind = branch;\n\t\t\t};\n\t\t};\n/* End XCRemoteSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */\n\t\t2CCA22D82C72D7930054393E /* AIProxy */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 2CCA22D72C72D7930054393E /* XCRemoteSwiftPackageReference \"AIProxySwift\" */;\n\t\t\tproductName = AIProxy;\n\t\t};\n/* End XCSwiftPackageProductDependency section */\n\t};\n\trootObject = 2CCA22BE2C72D78A0054393E /* Project object */;\n}\n"
  },
  {
    "path": "Demos/AIColorPalette/AIColorPalette/AIColorPaletteApp.swift",
    "content": "//\n//  AIColorPaletteApp.swift\n//  AIColorPalette\n//\n//  Created by Todd Hamilton on 6/20/24.\n//\n\nimport SwiftUI\n\n@main\nstruct AIColorPaletteApp: App {\n    var body: some Scene {\n        WindowGroup {\n            ContentView()\n        }\n    }\n}\n"
  },
  {
    "path": "Demos/AIColorPalette/AIColorPalette/AIProxyIntegration.swift",
    "content": "//\n//  AIProxyIntegration.swift\n//  AIColorPalette\n//\n//  Created by Todd Hamilton on 6/20/24.\n//\n\nimport AIProxy // The AIProxy SPM package is found at https://github.com/lzell/AIProxySwift\nimport Foundation\nimport UIKit\n\n#error(\n    \"\"\"\n    Uncomment one of the methods below. To build and run on device you must follow the AIProxy integration guide.\n    Please see https://www.aiproxy.pro/docs/integration-guide.html\")\n    \"\"\"\n)\n\n/* Uncomment for BYOK use cases */\nlet openAIService = AIProxy.openAIDirectService(\n    unprotectedAPIKey: \"your-openai-key\"\n)\n\n/* Uncomment for all other production use cases */\n//let openAIService = AIProxy.openAIService(\n//    partialKey: \"partial-key-from-your-developer-dashboard\",\n//    serviceURL: \"service-url-from-your-developer-dashboard\"\n//)\n\nstruct AIProxyIntegration {\n\n    static func getColorPalette(forImage image: UIImage) async -> String? {\n        let message = \"generate a color palette based on the provided image, return 4 colors in valid JSON, nothing else. Here's an example of the JSON format: 'colors': [{red: 0.85, green: 0.85, blue: 0.85}, {red: 0.85, green: 0.85, blue: 0.85}, {red: 0.85, green: 0.85, blue: 0.85}, {red: 0.85, green: 0.85, blue: 0.85}, {red: 0.85, green: 0.85, blue: 0.85}].\"\n\n        let localURL = createOpenAILocalURL(forImage: image)!\n        do {\n            let response = try await openAIService.chatCompletionRequest(body: .init(\n                model: \"gpt-4o\",\n                messages: [\n                    .system(\n                        content: .text(message)\n                    ),\n                    .user(\n                        content: .parts(\n                            [\n                                .imageURL(localURL, detail: .auto)\n                            ]\n                        )\n                    )\n                ],\n                responseFormat: .jsonObject\n            ))\n            return response.choices.first?.message.content\n        }  catch AIProxyError.unsuccessfulRequest(let statusCode, let responseBody) {\n            print(\"Received non-200 status code: \\(statusCode) with response body: \\(responseBody)\")\n        } catch {\n            print(error.localizedDescription)\n        }\n        return nil\n    }\n\n    private init() {\n        fatalError(\"This type is not intended to be instantiated\")\n    }\n}\n\nfunc createOpenAILocalURL(forImage image: UIImage) -> URL? {\n    // Attempt to get JPEG data from the UIImage\n    guard let jpegData = image.jpegData(compressionQuality: 0.4) else {\n        return nil\n    }\n\n    // Encode the JPEG data to a base64 string\n    let base64String = jpegData.base64EncodedString()\n\n    // Create the data URL string\n    let urlString = \"data:image/jpeg;base64,\\(base64String)\"\n\n    // Return the URL constructed from the data URL string\n    return URL(string: urlString)\n}\n"
  },
  {
    "path": "Demos/AIColorPalette/AIColorPalette/Assets.xcassets/AccentColor.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/AIColorPalette/AIColorPalette/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/AIColorPalette/AIColorPalette/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/AIColorPalette/AIColorPalette/Assets.xcassets/palm.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"palm.jpg\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/AIColorPalette/AIColorPalette/ColorData.swift",
    "content": "//\n//  ColorData.swift\n//  AIColorPalette\n//\n//  Created by Todd Hamilton on 6/21/24.\n//\n\nimport SwiftUI\n\n// Define the structure for the JSON data\nstruct ColorData: Codable {\n    let red: Double\n    let green: Double\n    let blue: Double\n\n    enum CodingKeys: String, CodingKey {\n        case red\n        case green\n        case blue\n    }\n}\n\nstruct Colors: Codable {\n    let colors: [ColorData]\n}\n"
  },
  {
    "path": "Demos/AIColorPalette/AIColorPalette/ColorDetailView.swift",
    "content": "//\n//  ColorDetailView.swift\n//  AIColorPalette\n//\n//  Created by Todd Hamilton on 6/22/24.\n//\n\nimport SwiftUI\n\nstruct ColorDetailView: View {\n\n    @Binding var currentColor:ColorData\n    @State var copiedToClipboard:Bool = false\n    @State private var hexValue:String = \"\"\n    @State private var rgbValue:String = \"\"\n\n    var body: some View {\n        VStack(spacing:16){\n            ZStack{\n                Circle()\n                    .fill(.white)\n                    .frame(width:68)\n                    .shadow(radius: 2, x: 0, y: 2)\n                Circle()\n                    .fill(Color(red:currentColor.red, green: currentColor.green, blue: currentColor.blue))\n                    .frame(width:60)\n            }\n            .padding(.vertical, 16)\n\n            HStack{\n                Text(hexValue)\n                    .fontWeight(.medium)\n                Spacer()\n                Button{\n                    copyToClipboard(copyItem: hexValue)\n                }label:{\n                    Image(systemName: \"square.on.square\")\n                }\n                .buttonStyle(.bordered)\n                .tint(Color(red:currentColor.red, green: currentColor.green, blue: currentColor.blue))\n                .sensoryFeedback(.success, trigger: copiedToClipboard)\n            }\n            Divider()\n            HStack{\n                Text(rgbValue)\n                    .fontWeight(.medium)\n                Spacer()\n                Button{\n                    copyToClipboard(copyItem: rgbValue)\n                }label:{\n                    Image(systemName: \"square.on.square\")\n                }\n                .buttonStyle(.bordered)\n                .tint(Color(red:currentColor.red, green: currentColor.green, blue: currentColor.blue))\n                .sensoryFeedback(.success, trigger: copiedToClipboard)\n            }\n            Spacer()\n\n        }\n        .padding()\n        .overlay(\n            ZStack{\n                if copiedToClipboard {\n                    Text(\"Copied to clipboard\")\n                        .fontWeight(.medium)\n                        .foregroundColor(.white)\n                        .padding()\n                        .background(Color.black.opacity(0.75).cornerRadius(20))\n                        .padding(.bottom)\n                        .shadow(radius: 5)\n                        .transition(.move(edge: .bottom))\n                        .frame(maxHeight:.infinity, alignment:.bottom)\n                }\n            }\n        )\n        .onAppear{\n            hexValue = rgbToHex(red: currentColor.red, green: currentColor.green, blue: currentColor.blue)\n            rgbValue = \"rgb(\\(String(format: \"%.2f\", currentColor.red)), \\(String(format: \"%.2f\", currentColor.green)), \\(String(format: \"%.2f\", currentColor.blue)))\"\n        }\n    }\n\n\n    func rgbToHex(red: CGFloat, green: CGFloat, blue: CGFloat) -> String {\n        let r = Int(red * 255.0)\n        let g = Int(green * 255.0)\n        let b = Int(blue * 255.0)\n        return String(format: \"#%02X%02X%02X\", r, g, b)\n    }\n\n    func copyToClipboard(copyItem: String) {\n        UIPasteboard.general.string = copyItem\n        withAnimation(.snappy){\n            copiedToClipboard = true\n        }\n        DispatchQueue.main.asyncAfter(deadline: .now() + 2){\n            withAnimation(.snappy){\n                copiedToClipboard = false\n            }\n        }\n    }\n\n}\n\n#Preview {\n    ZStack{\n        Image(\"palm\")\n            .resizable()\n            .scaledToFill()\n            .ignoresSafeArea()\n            .frame(width:UIScreen.main.bounds.width)\n        ColorDetailView(currentColor: .constant(ColorData(red: 0.5, green:0.2, blue:0.3)))\n            .background(.thickMaterial)\n    }\n}\n"
  },
  {
    "path": "Demos/AIColorPalette/AIColorPalette/ContentView.swift",
    "content": "//\n//  ContentView.swift\n//  AIColorPalette\n//\n//  Created by Todd Hamilton on 6/20/24.\n//\n\nimport SwiftUI\nimport PhotosUI\n\nstruct ContentView: View {\n\n    @State private var presentSheet = false\n    @State private var sheetColor:ColorData = ColorData(red: 1.0, green:1.0, blue:1.0)\n    @State private var copiedToClipboard = false\n\n    @State var counter: Int = 0\n    @State var origin: CGPoint = .zero\n\n    @State private var sampleImage: UIImage? = UIImage(named: \"palm\")\n    @State private var photosPickerItem: PhotosPickerItem?\n    @State private var loading = false\n    @State private var loadingIndicator = false\n    @State private var sampleColors:Colors = Colors(\n        colors:\n            [\n                ColorData(red: 0.28, green: 0.28, blue: 0.20),\n                ColorData(red: 0.72, green: 0.75, blue: 0.73),\n                ColorData(red: 0.08, green: 0.54, blue: 0.63),\n                ColorData(red: 0.59, green: 0.49, blue: 0.35)\n            ]\n    )\n\n    var body: some View {\n\n        ZStack{\n            MeshGradient(\n                width: 2,\n                height: 2,\n                points: [\n                    [0, 0], [1, 0],\n                    [0, 1], [1, 1],\n                ], colors: createMeshColors())\n            .ignoresSafeArea()\n\n            VStack(spacing:48){\n\n                // Sample image\n                Image(uiImage: sampleImage!)\n                    .resizable()\n                    .scaledToFill()\n                    .modifier(RippleEffect(at: origin, trigger: counter))\n                    .frame(maxWidth:320, maxHeight:360)\n                    .cornerRadius(24)\n                    .clipped()\n                    .shadow(radius: 10)\n                    .overlay(\n                        ZStack{\n                            Color\n                                .black\n                                .opacity(0.75)\n                            Text(\"Generating palette...\")\n                                .bold()\n                                .foregroundStyle(.white)\n                        }\n                            .cornerRadius(24)\n                            .clipped()\n                            .opacity(loadingIndicator ? 1 : 0)\n                    )\n\n                VStack(spacing: 48){\n                    ZStack{\n                        // Color swatches\n                        HStack(spacing:loading ? -60 : 20){\n                            ForEach(Array(sampleColors.colors.enumerated()), id: \\.offset) { index, color in\n                                Circle()\n                                    .stroke(.white, lineWidth: 8)\n                                    .fill(Color(red: color.red,green: color.green,blue: color.blue))\n                                    .frame(width:60)\n                                    .onTapGesture {\n                                        sheetColor = color\n                                        presentSheet.toggle()\n                                    }\n                            }\n                        }\n\n                        if loadingIndicator{\n                            Circle()\n                                .fill(.white)\n                                .stroke(.white, lineWidth:8)\n                                .frame(width:60)\n                                .overlay(\n                                    ProgressView()\n                                        .tint(.black)\n                                )\n                        }\n                    }\n\n                    PhotosPicker(selection: $photosPickerItem, matching: .images){\n                        Text(\"Choose Photo\")\n                            .bold()\n                    }\n                    .buttonStyle(.borderedProminent)\n                    .tint(.black)\n                    .controlSize(.extraLarge)\n                }\n\n            }\n\n        }\n        .sheet(isPresented: $presentSheet) {\n            ColorDetailView(currentColor: $sheetColor)\n                .presentationDetents([.medium])\n                .presentationBackground(.thickMaterial)\n\n        }\n        .onChange(of: photosPickerItem){ _, _ in\n            Task{\n                loading = true\n                loadingIndicator = true\n                if let photosPickerItem,\n                   let data = try? await photosPickerItem.loadTransferable(type: Data.self){\n                    if let image = UIImage(data: data){\n                        withAnimation(){\n                            sampleImage = image\n                        }\n                        try await generateColorPalette(image: sampleImage!)\n                    }\n                }\n                withAnimation(){\n                    loading = false\n                }\n                withAnimation(.bouncy){\n                    loadingIndicator = false\n                }\n                counter += 1\n            }\n        }\n\n    }\n\n    func createMeshColors() -> [Color] {\n        var meshColors: [Color] = []\n        for color in sampleColors.colors {\n            meshColors.append(Color(red: color.red, green: color.green, blue: color.blue))\n        }\n        return meshColors\n    }\n\n    func generateColorPalette(image: UIImage) async throws  {\n        let jsonString = await AIProxyIntegration.getColorPalette(forImage: image)\n        let jsonData = jsonString!.data(using: .utf8)!\n\n        do {\n            sampleColors = try JSONDecoder().decode(Colors.self, from: jsonData)\n        } catch {\n            fatalError(\"Failed to decode JSON: \\(error)\")\n        }\n    }\n}\n\n#Preview {\n    ContentView()\n}\n"
  },
  {
    "path": "Demos/AIColorPalette/AIColorPalette/Preview Content/Preview Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/AIColorPalette/AIColorPalette/Ripple.metal",
    "content": "//\n//  Ripple.metal\n//  AIColorPalette\n//\n//  Created by Todd Hamilton on 6/21/24.\n//\n\n// Insert #include <metal_stdlib>\n#include <SwiftUI/SwiftUI.h>\nusing namespace metal;\n\n[[ stitchable ]]\nhalf4 Ripple(\n    float2 position,\n    SwiftUI::Layer layer,\n    float2 origin,\n    float time,\n    float amplitude,\n    float frequency,\n    float decay,\n    float speed\n) {\n    // The distance of the current pixel position from `origin`.\n    float distance = length(position - origin);\n    // The amount of time it takes for the ripple to arrive at the current pixel position.\n    float delay = distance / speed;\n\n    // Adjust for delay, clamp to 0.\n    time -= delay;\n    time = max(0.0, time);\n\n    // The ripple is a sine wave that Metal scales by an exponential decay\n    // function.\n    float rippleAmount = amplitude * sin(frequency * time) * exp(-decay * time);\n\n    // A vector of length `amplitude` that points away from position.\n    float2 n = normalize(position - origin);\n\n    // Scale `n` by the ripple amount at the current pixel position and add it\n    // to the current pixel position.\n    //\n    // This new position moves toward or away from `origin` based on the\n    // sign and magnitude of `rippleAmount`.\n    float2 newPosition = position + rippleAmount * n;\n\n    // Sample the layer at the new position.\n    half4 color = layer.sample(newPosition);\n\n    // Lighten or darken the color based on the ripple amount and its alpha\n    // component.\n    color.rgb += 0.3 * (rippleAmount / amplitude) * color.a;\n\n    return color;\n}\n\n\n"
  },
  {
    "path": "Demos/AIColorPalette/AIColorPalette/Ripple.swift",
    "content": "//\n//  Ripple.swift\n//  AIColorPalette\n//\n//  Created by Todd Hamilton on 6/21/24.\n//\n\nimport SwiftUI\n\nstruct PushEffect<T: Equatable>: ViewModifier {\n    var trigger: T\n\n    func body(content: Content) -> some View {\n        content.keyframeAnimator(\n            initialValue: 1.0,\n            trigger: trigger\n        ) { view, value in\n            view.visualEffect { view, _ in\n                view.scaleEffect(value)\n            }\n        } keyframes: { _ in\n            SpringKeyframe(0.95, duration: 0.2, spring: .snappy)\n            SpringKeyframe(1.0, duration: 0.2, spring: .bouncy)\n        }\n    }\n}\n\n/// A modifer that performs a ripple effect to its content whenever its\n/// trigger value changes.\nstruct RippleEffect<T: Equatable>: ViewModifier {\n    var origin: CGPoint\n\n    var trigger: T\n\n    init(at origin: CGPoint, trigger: T) {\n        self.origin = origin\n        self.trigger = trigger\n    }\n\n    func body(content: Content) -> some View {\n        let origin = origin\n        let duration = duration\n\n        content.keyframeAnimator(\n            initialValue: 0,\n            trigger: trigger\n        ) { view, elapsedTime in\n            view.modifier(RippleModifier(\n                origin: origin,\n                elapsedTime: elapsedTime,\n                duration: duration\n            ))\n        } keyframes: { _ in\n            MoveKeyframe(0)\n            LinearKeyframe(duration, duration: duration)\n        }\n    }\n\n    var duration: TimeInterval { 3 }\n}\n\n/// A modifier that applies a ripple effect to its content.\nstruct RippleModifier: ViewModifier {\n    var origin: CGPoint\n\n    var elapsedTime: TimeInterval\n\n    var duration: TimeInterval\n\n    var amplitude: Double = 12\n    var frequency: Double = 15\n    var decay: Double = 8\n    var speed: Double = 1200\n\n    func body(content: Content) -> some View {\n        let shader = ShaderLibrary.Ripple(\n            .float2(origin),\n            .float(elapsedTime),\n\n            // Parameters\n            .float(amplitude),\n            .float(frequency),\n            .float(decay),\n            .float(speed)\n        )\n\n        let maxSampleOffset = maxSampleOffset\n        let elapsedTime = elapsedTime\n        let duration = duration\n\n        content.visualEffect { view, _ in\n            view.layerEffect(\n                shader,\n                maxSampleOffset: maxSampleOffset,\n                isEnabled: 0 < elapsedTime && elapsedTime < duration\n            )\n        }\n    }\n\n    var maxSampleOffset: CGSize {\n        CGSize(width: amplitude, height: amplitude)\n    }\n}\n\nextension View {\n    func onPressingChanged(_ action: @escaping (CGPoint?) -> Void) -> some View {\n        modifier(SpatialPressingGestureModifier(action: action))\n    }\n}\n\nstruct SpatialPressingGestureModifier: ViewModifier {\n    var onPressingChanged: (CGPoint?) -> Void\n\n    @State var currentLocation: CGPoint?\n\n    init(action: @escaping (CGPoint?) -> Void) {\n        self.onPressingChanged = action\n    }\n\n    func body(content: Content) -> some View {\n        let gesture = SpatialPressingGesture(location: $currentLocation)\n\n        content\n            .gesture(gesture)\n            .onChange(of: currentLocation, initial: false) { _, location in\n                onPressingChanged(location)\n            }\n    }\n}\n\nstruct SpatialPressingGesture: UIGestureRecognizerRepresentable {\n    final class Coordinator: NSObject, UIGestureRecognizerDelegate {\n        @objc\n        func gestureRecognizer(\n            _ gestureRecognizer: UIGestureRecognizer,\n            shouldRecognizeSimultaneouslyWith other: UIGestureRecognizer\n        ) -> Bool {\n            true\n        }\n    }\n\n    @Binding var location: CGPoint?\n\n    func makeCoordinator(converter: CoordinateSpaceConverter) -> Coordinator {\n        Coordinator()\n    }\n\n    func makeUIGestureRecognizer(context: Context) -> UILongPressGestureRecognizer {\n        let recognizer = UILongPressGestureRecognizer()\n        recognizer.minimumPressDuration = 0\n        recognizer.delegate = context.coordinator\n\n        return recognizer\n    }\n\n    func handleUIGestureRecognizerAction(\n        _ recognizer: UIGestureRecognizerType, context: Context) {\n            switch recognizer.state {\n                case .began:\n                    location = context.converter.localLocation\n                case .ended, .cancelled, .failed:\n                    location = nil\n                default:\n                    break\n            }\n        }\n    }\n"
  },
  {
    "path": "Demos/AIColorPalette/AIColorPalette.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 56;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t0D24C88C2C29DA4B009E0102 /* AIProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 0D24C88B2C29DA4B009E0102 /* AIProxy */; };\n\t\t2C22A6612C25D9EA00C9B21C /* ColorData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C22A6602C25D9EA00C9B21C /* ColorData.swift */; };\n\t\t2C754B602C267044008A4329 /* Ripple.metal in Sources */ = {isa = PBXBuildFile; fileRef = 2C754B5F2C267044008A4329 /* Ripple.metal */; };\n\t\t2C754B622C2674EF008A4329 /* Ripple.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C754B612C2674EA008A4329 /* Ripple.swift */; };\n\t\t2C754B642C27831B008A4329 /* ColorDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C754B632C27831B008A4329 /* ColorDetailView.swift */; };\n\t\t2CE5D2E62C247CA500E53983 /* AIColorPaletteApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE5D2E52C247CA500E53983 /* AIColorPaletteApp.swift */; };\n\t\t2CE5D2E82C247CA500E53983 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE5D2E72C247CA500E53983 /* ContentView.swift */; };\n\t\t2CE5D2EA2C247CA600E53983 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2CE5D2E92C247CA600E53983 /* Assets.xcassets */; };\n\t\t2CE5D2ED2C247CA600E53983 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2CE5D2EC2C247CA600E53983 /* Preview Assets.xcassets */; };\n\t\t2CF0AB4E2C5C133B00BFA8BC /* AIProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 2CF0AB4D2C5C133B00BFA8BC /* AIProxy */; };\n\t\t2CFD48A92C24BC480065C162 /* AIProxyIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CFD48A82C24BC480065C162 /* AIProxyIntegration.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t2C22A6602C25D9EA00C9B21C /* ColorData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorData.swift; sourceTree = \"<group>\"; };\n\t\t2C754B5F2C267044008A4329 /* Ripple.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = Ripple.metal; sourceTree = \"<group>\"; };\n\t\t2C754B612C2674EA008A4329 /* Ripple.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ripple.swift; sourceTree = \"<group>\"; };\n\t\t2C754B632C27831B008A4329 /* ColorDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorDetailView.swift; sourceTree = \"<group>\"; };\n\t\t2CE5D2E22C247CA500E53983 /* AIColorPalette.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AIColorPalette.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t2CE5D2E52C247CA500E53983 /* AIColorPaletteApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AIColorPaletteApp.swift; sourceTree = \"<group>\"; };\n\t\t2CE5D2E72C247CA500E53983 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = \"<group>\"; };\n\t\t2CE5D2E92C247CA600E53983 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t2CE5D2EC2C247CA600E53983 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = \"Preview Assets.xcassets\"; sourceTree = \"<group>\"; };\n\t\t2CFD48A82C24BC480065C162 /* AIProxyIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AIProxyIntegration.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t2CE5D2DF2C247CA500E53983 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t0D24C88C2C29DA4B009E0102 /* AIProxy in Frameworks */,\n\t\t\t\t2CF0AB4E2C5C133B00BFA8BC /* AIProxy in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t2CE5D2D92C247CA500E53983 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CE5D2E42C247CA500E53983 /* AIColorPalette */,\n\t\t\t\t2CE5D2E32C247CA500E53983 /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2CE5D2E32C247CA500E53983 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CE5D2E22C247CA500E53983 /* AIColorPalette.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2CE5D2E42C247CA500E53983 /* AIColorPalette */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CE5D2E52C247CA500E53983 /* AIColorPaletteApp.swift */,\n\t\t\t\t2CFD48A82C24BC480065C162 /* AIProxyIntegration.swift */,\n\t\t\t\t2C22A6602C25D9EA00C9B21C /* ColorData.swift */,\n\t\t\t\t2C754B632C27831B008A4329 /* ColorDetailView.swift */,\n\t\t\t\t2CE5D2E72C247CA500E53983 /* ContentView.swift */,\n\t\t\t\t2C754B612C2674EA008A4329 /* Ripple.swift */,\n\t\t\t\t2C754B5F2C267044008A4329 /* Ripple.metal */,\n\t\t\t\t2CE5D2E92C247CA600E53983 /* Assets.xcassets */,\n\t\t\t\t2CE5D2EB2C247CA600E53983 /* Preview Content */,\n\t\t\t);\n\t\t\tpath = AIColorPalette;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2CE5D2EB2C247CA600E53983 /* Preview Content */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CE5D2EC2C247CA600E53983 /* Preview Assets.xcassets */,\n\t\t\t);\n\t\t\tpath = \"Preview Content\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t2CE5D2E12C247CA500E53983 /* AIColorPalette */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 2CE5D2F02C247CA600E53983 /* Build configuration list for PBXNativeTarget \"AIColorPalette\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t2CE5D2DE2C247CA500E53983 /* Sources */,\n\t\t\t\t2CE5D2DF2C247CA500E53983 /* Frameworks */,\n\t\t\t\t2CE5D2E02C247CA500E53983 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = AIColorPalette;\n\t\t\tpackageProductDependencies = (\n\t\t\t\t0D24C88B2C29DA4B009E0102 /* AIProxy */,\n\t\t\t\t2CF0AB4D2C5C133B00BFA8BC /* AIProxy */,\n\t\t\t);\n\t\t\tproductName = AIColorPalette;\n\t\t\tproductReference = 2CE5D2E22C247CA500E53983 /* AIColorPalette.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t2CE5D2DA2C247CA500E53983 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = 1;\n\t\t\t\tLastSwiftUpdateCheck = 1540;\n\t\t\t\tLastUpgradeCheck = 1540;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t2CE5D2E12C247CA500E53983 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 15.4;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 2CE5D2DD2C247CA500E53983 /* Build configuration list for PBXProject \"AIColorPalette\" */;\n\t\t\tcompatibilityVersion = \"Xcode 14.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 2CE5D2D92C247CA500E53983;\n\t\t\tpackageReferences = (\n\t\t\t\t2CF0AB4C2C5C133B00BFA8BC /* XCRemoteSwiftPackageReference \"AIProxySwift\" */,\n\t\t\t);\n\t\t\tproductRefGroup = 2CE5D2E32C247CA500E53983 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t2CE5D2E12C247CA500E53983 /* AIColorPalette */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t2CE5D2E02C247CA500E53983 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2CE5D2ED2C247CA600E53983 /* Preview Assets.xcassets in Resources */,\n\t\t\t\t2CE5D2EA2C247CA600E53983 /* Assets.xcassets in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t2CE5D2DE2C247CA500E53983 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2CE5D2E82C247CA500E53983 /* ContentView.swift in Sources */,\n\t\t\t\t2C754B622C2674EF008A4329 /* Ripple.swift in Sources */,\n\t\t\t\t2C22A6612C25D9EA00C9B21C /* ColorData.swift in Sources */,\n\t\t\t\t2CE5D2E62C247CA500E53983 /* AIColorPaletteApp.swift in Sources */,\n\t\t\t\t2C754B642C27831B008A4329 /* ColorDetailView.swift in Sources */,\n\t\t\t\t2C754B602C267044008A4329 /* Ripple.metal in Sources */,\n\t\t\t\t2CFD48A92C24BC480065C162 /* AIProxyIntegration.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t2CE5D2EE2C247CA600E53983 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.5;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"DEBUG $(inherited)\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2CE5D2EF2C247CA600E53983 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.5;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t2CE5D2F12C247CA600E53983 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"AIColorPalette/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 9557YJ9D37;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_NSCameraUsageDescription = \"Needed to capture images and generate color palettes.\";\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 18.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.toddham.AIColorPalette;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2CE5D2F22C247CA600E53983 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"AIColorPalette/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 9557YJ9D37;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_NSCameraUsageDescription = \"Needed to capture images and generate color palettes.\";\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 18.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.toddham.AIColorPalette;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t2CE5D2DD2C247CA500E53983 /* Build configuration list for PBXProject \"AIColorPalette\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2CE5D2EE2C247CA600E53983 /* Debug */,\n\t\t\t\t2CE5D2EF2C247CA600E53983 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t2CE5D2F02C247CA600E53983 /* Build configuration list for PBXNativeTarget \"AIColorPalette\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2CE5D2F12C247CA600E53983 /* Debug */,\n\t\t\t\t2CE5D2F22C247CA600E53983 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCRemoteSwiftPackageReference section */\n\t\t2CF0AB4C2C5C133B00BFA8BC /* XCRemoteSwiftPackageReference \"AIProxySwift\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/lzell/AIProxySwift\";\n\t\t\trequirement = {\n\t\t\t\tbranch = main;\n\t\t\t\tkind = branch;\n\t\t\t};\n\t\t};\n/* End XCRemoteSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */\n\t\t0D24C88B2C29DA4B009E0102 /* AIProxy */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tproductName = AIProxy;\n\t\t};\n\t\t2CF0AB4D2C5C133B00BFA8BC /* AIProxy */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 2CF0AB4C2C5C133B00BFA8BC /* XCRemoteSwiftPackageReference \"AIProxySwift\" */;\n\t\t\tproductName = AIProxy;\n\t\t};\n/* End XCSwiftPackageProductDependency section */\n\t};\n\trootObject = 2CE5D2DA2C247CA500E53983 /* Project object */;\n}\n"
  },
  {
    "path": "Demos/AIColorPalette/README.md",
    "content": "## Example projects\n\n### AIColorPalette\n\n#### About\n\nAIColorPalette generates a color palette from a photo in your camera roll. This project uses [AIProxy](https://www.aiproxy.pro) to secure your OpenAI key.\n\n#### Features demonstrated\n\n- Shows off new iOS 18 SwiftUI effects\n- Calls the OpenAI chat completion endpoint\n- Submits a photo as the chat completion request body\n- Compels OpenAI to return valid JSON in the chat completion response\n\n#### Minimum requirements\n\nThe minimum deployment target for this sample app is 18.0, as it uses beta UI effects.\n\nYou'll need:\n\n- macOS Sonoma 14.5 or higher\n- Xcode Beta 16.0 or higher\n\n#### How to run with your own AIProxy settings\n\n- Set the `AIPROXY_DEVICE_CHECK_BYPASS` environment variable in your Xcode build settings.\n  Refer to the [README](https://github.com/lzell/AIProxySwift?tab=readme-ov-file#adding-this-package-as-a-dependency-to-your-xcode-project)\n  for instructions on adding an env variable to your Xcode project.\n\n- Replace the `partialKey` placeholder value in `AIColorPalette/AIProxyIntegration.swift` with the\n  value provided to you in the AIProxy dashboard when you submit your OpenAI key\n"
  },
  {
    "path": "Demos/Chat/Chat/AppConstants.swift",
    "content": "//\n//  AppConstants.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport AIProxy\n\nenum AppConstants {\n    #error(\n        \"\"\"\n        Uncomment one of the methods below. To build and run on device you must follow the AIProxy integration guide.\n        Please see https://www.aiproxy.pro/docs/integration-guide.html\")\n        \"\"\"\n    )\n    \n    /* Uncomment for BYOK use cases */\n    static let openAIService = AIProxy.openAIDirectService(\n        unprotectedAPIKey: \"your-openai-key\"\n    )\n\n    /* Uncomment for all other production use cases */\n//    static let openAIService = AIProxy.openAIService(\n//        partialKey: \"partial-key-from-your-developer-dashboard\",\n//        serviceURL: \"service-url-from-your-developer-dashboard\"\n//    )\n}\n"
  },
  {
    "path": "Demos/Chat/Chat/AppLogger.swift",
    "content": "//\n//  AppLogger.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport OSLog\n\n/// Log levels available:\n///\n///     AppLogger.debug\n///     AppLogger.info\n///     AppLogger.warning\n///     AppLogger.error\n///     AppLogger.critical\n///\n/// Flip on metadata logging in Xcode's console to show which source line the log occurred from.\n///\n/// See my reddit post for a video instructions:\n/// https://www.reddit.com/r/SwiftUI/comments/15lsdtk/how_to_use_the_oslog_logger/\nlet AppLogger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"UnknownApp\",\n                       category: \"AIProxyBootstrapChat\")\n"
  },
  {
    "path": "Demos/Chat/Chat/Assets.xcassets/AccentColor.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/Chat/Chat/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"chat.png\",\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/Chat/Chat/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/Chat/Chat/ChatApp.swift",
    "content": "//\n//  ChatApp.swift\n//  Chat\n//\n//  Created by Lou Zell\n//\n\nimport SwiftUI\n\n@main\n@MainActor\nstruct ChatApp: App {\n\n    @State private var chatManager = ChatManager()\n\n    var body: some Scene {\n        WindowGroup {\n            ChatView(chatManager: chatManager)\n        }\n    }\n}\n"
  },
  {
    "path": "Demos/Chat/Chat/ChatBubble.swift",
    "content": "//\n//  ChatBubbleView.swift\n//  AIProxyBootstrap\n//\n//  Created by Todd Hamilton\n//\n\nimport SwiftUI\n\n/// A view to contain a single message from either the user or OpenAI.\nstruct ChatBubble: View {\n\n    /// The message to display\n    let message: ChatMessage\n\n    /// Whether to animate in the chat bubble\n    let animateIn: Bool\n\n    /// State used to animate in the chat bubble if `animateIn` is true\n    @State private var animationTrigger = false\n\n    var body: some View {\n        HStack(alignment: .top, spacing: 12) {\n            chatIcon\n            VStack(alignment: .leading) {\n                chatName\n                chatBody\n            }\n        }\n        .opacity(bubbleOpacity)\n        .animation(.easeIn(duration: 0.75), value: animationTrigger)\n        .onAppear {\n            adjustAnimationTriggerIfNecessary()\n        }\n    }\n\n    private var bubbleOpacity: Double {\n        guard animateIn else {\n            return 1\n        }\n        return animationTrigger ? 1 : 0\n    }\n\n    private func adjustAnimationTriggerIfNecessary() {\n        guard animateIn else {\n            return\n        }\n        animationTrigger = true\n    }\n\n    private var chatIcon: some View {\n        Image(systemName: message.isUser ? \"person.circle.fill\" : \"command.circle.fill\")\n            .font(.title2)\n            .frame(width:24, height:24)\n            .foregroundColor(message.isUser ? .primary : .teal)\n    }\n\n    private var chatName: some View {\n        Text(message.isUser ? \"You\" : \"ChatGPT\")\n            .fontWeight(.bold)\n            .frame(maxWidth: .infinity, maxHeight:24, alignment: .leading)\n    }\n\n    @ViewBuilder\n    private var chatBody: some View {\n        if message.isUser {\n            Text(LocalizedStringKey(message.text))\n                .fixedSize(horizontal: false, vertical: true)\n                .foregroundColor(.primary)\n        } else {\n            if message.isWaitingForFirstText {\n                ProgressView()\n            } else {\n                Text(LocalizedStringKey(message.text))\n                    .fixedSize(horizontal: false, vertical: true)\n                    .foregroundColor(.primary)\n            }\n        }\n    }\n}\n\n#Preview {\n    ChatBubble(message: ChatMessage(text: \"hello\", isUser: false), animateIn: false)\n        .frame(maxWidth:.infinity)\n        .padding()\n}\n"
  },
  {
    "path": "Demos/Chat/Chat/ChatDataLoader.swift",
    "content": "//\n//  ChatDataLoader.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport AIProxy\n\nenum ChatDataLoaderError: Error {\n    case busy\n}\n\n/// Asynchronously sends prompts to OpenAI and streams back the response\nfinal actor ChatDataLoader {\n    private var streamingResponseAccumulator: String?\n\n    /// All chat messages, including user queries and openai responses.\n    /// The full history of the chat is sent with each request to openai to provide an ongoing conversation with memory.\n    private var messages = [OpenAIChatCompletionMessage]()\n\n    /// Add a user message to the conversation and stream back the openai response\n    func addToConversation(_ prompt: String) async throws -> AsyncThrowingStream<String, Error> {\n        guard streamingResponseAccumulator == nil else {\n            throw ChatDataLoaderError.busy\n        }\n        self.streamingResponseAccumulator = \"\"\n        \n        self.messages.append((.user(content: .text(prompt))))\n        let requestBody = OpenAIChatCompletionRequestBody(\n            model: \"gpt-4o-mini\",\n            messages: [.user(content: .text(prompt))]\n        )\n        let stream = try await AppConstants.openAIService.streamingChatCompletionRequest(body: requestBody)\n\n        return AsyncThrowingStream { continuation in\n            let task = Task {\n                for try await result in stream {\n                    guard let choice = result.choices.first,\n                          let content = choice.delta.content else\n                    {\n                        self.addAccumulatedResponseToMessageHistory()\n                        continuation.finish()\n                        return\n                    }\n\n                    self.addToResponseAccumulator(text: content)\n                    continuation.yield(content)\n                }\n            }\n\n            continuation.onTermination = { @Sendable termination in\n                task.cancel()\n                if case .cancelled = termination {\n                    Task {\n                        await self.addAccumulatedResponseToMessageHistory()\n                    }\n                }\n            }\n        }\n    }\n\n\n    private func addAccumulatedResponseToMessageHistory() {\n        if let accumulator = self.streamingResponseAccumulator {\n            self.messages.append(.assistant(content: .text(accumulator)))\n            self.streamingResponseAccumulator = nil\n        }\n    }\n\n    private func addToResponseAccumulator(text: String) {\n        if let accumulator = self.streamingResponseAccumulator {\n            self.streamingResponseAccumulator = accumulator + text\n        } else {\n            self.streamingResponseAccumulator = text\n        }\n    }\n}\n"
  },
  {
    "path": "Demos/Chat/Chat/ChatInputView.swift",
    "content": "//\n//  ChatInputView.swift\n//  AIProxyBootstrap\n//\n//  Created by Todd Hamilton\n//\n\nimport SwiftUI\n\n/// A view for the user to enter chat messages\nstruct ChatInputView: View {\n\n    private enum FocusedField {\n        case newMessageText\n    }\n\n    /// Is a streaming chat response in progress\n    let isStreamingResponse: Bool\n\n    /// Callback invoked when the user taps the submit button or presses return\n    var didSubmit: (String) -> Void\n\n    /// Callback invoked when the user taps on the stop button\n    var didTapStop: () -> Void\n\n    /// State to collect new text messages\n    @State private var newMessageText: String = \"\"\n    @FocusState private var focusedField: FocusedField?\n\n    var body: some View {\n        HStack(spacing:0){\n            chatInputTextField\n            actionButton\n        }\n        .padding(8)\n    }\n\n    private var chatInputTextField: some View {\n        TextField(\"Type a message\", text: $newMessageText, axis: .vertical)\n            .focused($focusedField, equals: .newMessageText)\n            .lineLimit(5)\n            .padding(.horizontal, 16)\n            .padding(.vertical, 10)\n            .background(\n                RoundedRectangle(cornerRadius:30)\n                    .fill(Color(.tertiarySystemGroupedBackground))\n                    .stroke(.separator)\n            )\n            .onAppear {\n                focusedField = .newMessageText\n            }\n            .onSubmit {\n                didSubmit(newMessageText)\n                newMessageText = \"\"\n            }\n    }\n\n    private var actionButton: some View {\n        Button {\n            if isStreamingResponse {\n                didTapStop()\n            } else {\n                didSubmit(newMessageText)\n                newMessageText = \"\"\n            }\n        } label:{\n            Image(systemName: isStreamingResponse ? \"stop.circle.fill\" : \"arrow.up.circle.fill\")\n                .font(.title)\n                .foregroundColor((isStreamingResponse || !newMessageText.isEmpty) ? .primary : .secondary)\n                .frame(width:40, height:40)\n        }\n        .contentTransition(.symbolEffect(.replace))\n        .padding(.horizontal, 8)\n    }\n}\n\n#Preview {\n    ChatInputView(isStreamingResponse: false, didSubmit: { _ in }, didTapStop: { })\n}\n"
  },
  {
    "path": "Demos/Chat/Chat/ChatManager.swift",
    "content": "//\n//  ChatManager.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport SwiftUI\n\n@MainActor\n@Observable\nfinal class ChatManager {\n\n    /// Messages sent from the user or received from OpenAI\n    var messages = [ChatMessage]()\n\n    /// Returns true if OpenAI is still streaming a response back to us\n    var isProcessing: Bool {\n        return self.streamTask != nil\n    }\n\n    /// Task that encapsulates OpenAI's streaming response.\n    /// Cancel this to interrupt OpenAI's response.\n    private var streamTask: Task<Void, Never>? = nil\n    private let chatDataLoader = ChatDataLoader()\n\n    /// Send a new message to OpenAI and start streaming OpenAI's response\n    func send(message: ChatMessage) {\n        self.messages.append(message)\n        self.setupStreamingTask(withPrompt: message.text)\n    }\n\n    /// Stop the streaming response from OpenAI\n    func stop() {\n        self.streamTask?.cancel()\n        self.streamTask = nil\n    }\n\n    private func setupStreamingTask(withPrompt prompt: String) {\n        self.messages.append(ChatMessage(text: \"\", isUser: false, isWaitingForFirstText: true))\n        self.streamTask = Task { [weak self] in\n            guard let this = self else { return }\n            do {\n                let responseStream = try await this.chatDataLoader.addToConversation(prompt)\n                for try await responseText in responseStream {\n                    if var last = this.messages.popLast() {\n                        last.isWaitingForFirstText = false\n                        last.text += responseText\n                        this.messages.append(last)\n                    }\n                }\n                this.streamTask = nil\n            } catch {\n                AppLogger.error(\"Received an unexpected error from OpenAI streaming: \\(error)\")\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Demos/Chat/Chat/ChatMessage.swift",
    "content": "//\n//  ChatMessage.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\n\n/// Data model to represent a chat message\nstruct ChatMessage: Identifiable, Equatable {\n    /// Unique identifier\n    let id = UUID()\n\n    /// The body of the chat message\n    var text: String\n\n    /// True if the message originates from the user, false if it originates from OpenAI\n    let isUser: Bool\n\n    /// Indicates that we are waiting for the first bit of message content from OpenAI\n    var isWaitingForFirstText = false\n}\n"
  },
  {
    "path": "Demos/Chat/Chat/ChatView.swift",
    "content": "//\n//  ChatView.swift\n//  AIProxyBootstrap\n//\n//  Created by Todd Hamilton\n//\n\nimport SwiftUI\n\n@MainActor\nstruct ChatView: View {\n\n    private enum ScrollChange {\n        case userInteraction\n        case programmatic\n    }\n\n    /// The chat manager that controls communication with OpenAI\n    let chatManager: ChatManager\n\n    /// Should we auto-scroll the scrollview as message content arrives\n    @State private var isTrackingScrollView = false\n\n    /// As the scroll position changes, this state indicates whether the change originated from a user interation or programmatically\n    @State private var scrollChange: ScrollChange = .userInteraction\n\n    /// The user's scroll position of the content view (e.g. where in the chat message contents they are positioned)\n    @State private var scrollPosition: CGPoint = .zero {\n        didSet {\n            switch scrollChange {\n            case .userInteraction:\n                isTrackingScrollView = false\n            case .programmatic:\n                scrollChange = .userInteraction\n            }\n        }\n    }\n\n    /// The height of the scroll view (e.g. the frame's height)\n    @State private var scrollViewHeight: CGFloat = .infinity\n\n    /// The height of the contents contained within the scroll view\n    @State private var scrollViewContentHeight: CGFloat = .zero\n\n    @State private var scrollTrigger = false\n\n    var body: some View {\n        VStack {\n            autoScrollingChatView\n                .padding([.top, .leading, .trailing])\n\n            ZStack(alignment: .top) {\n\n                AutoScrollButton(isVisible: !isTrackingScrollView && scrollViewContentHeight > scrollViewHeight) {\n                    isTrackingScrollView = true\n                    scrollTrigger.toggle()\n                }\n                .offset(y: -50)\n\n                ChatInputView(isStreamingResponse: chatManager.isProcessing,\n                              didSubmit: { sendMessage($0) },\n                              didTapStop: { chatManager.stop() })\n            }\n        }\n    }\n\n    private var autoScrollingChatView: some View {\n        ScrollViewReader { scrollView in\n            ScrollView(.vertical) {\n                ChatMessagesView(chatMessages: chatManager.messages)\n                    .id(\"MessagesView\")\n                    .background(GeometryReader { geometry in\n                        Color.clear\n                            .preference(key: ScrollOffsetPreferenceKey.self,\n                                        value: geometry.frame(in: .named(\"chatScrollView\")).origin)\n                            .preference(key: ScrollHeightPreferenceKey.self,\n                                        value: geometry.size.height)\n                    })\n                    .onPreferenceChange(ScrollOffsetPreferenceKey.self) { value in\n                        scrollPosition = value\n                    }\n                    .onPreferenceChange(ScrollHeightPreferenceKey.self) { value in\n                        scrollViewContentHeight = value\n                    }\n            }\n            .coordinateSpace(name: \"chatScrollView\")\n            .background(\n                GeometryReader { outerScrollViewGeometry in\n                    Color.clear\n                        .preference(key: ScrollHeightPreferenceKey.self,\n                                    value: outerScrollViewGeometry.size.height)\n                }\n            )\n            .onPreferenceChange(ScrollHeightPreferenceKey.self) { value in\n                scrollViewHeight = value\n            }\n            .onChange(of: scrollTrigger) {\n                scrollChange = .programmatic\n                scrollView.scrollTo(\"MessagesView\", anchor: .bottom)\n            }\n            .onChange(of: chatManager.messages) { _, _ in\n                if isTrackingScrollView {\n                    scrollTrigger.toggle()\n                }\n            }\n        }\n    }\n\n    private func sendMessage(_ message: String) {\n        guard !message.isEmpty else { return }\n        chatManager.send(message: ChatMessage(text: message, isUser: true))\n    }\n}\n\nprivate struct ChatMessagesView: View {\n    /// Flags to prevent messages from animating in multiple times as dependencies that drive `body` change\n    @State private var shouldAnimateMessageIn = [UUID: Bool]()\n    let chatMessages: [ChatMessage]\n\n    var body: some View {\n        VStack(alignment: .leading) {\n            ChatBubble(message: ChatMessage(text: \"How can I help you?\", isUser: false), animateIn: true)\n                .listRowSeparator(.hidden)\n\n            ForEach(chatMessages) { message in\n                ChatBubble(message: message, animateIn: shouldAnimateMessageIn[message.id] ?? true)\n                    .listRowSeparator(.hidden)\n                    .transition(.opacity)\n                    .onAppear {\n                        shouldAnimateMessageIn[message.id] = false\n                    }\n            }\n        }\n    }\n}\n\n\n// Credit: https://saeedrz.medium.com/detect-scroll-position-in-swiftui-3d6e0d81fc6b\nprivate struct ScrollOffsetPreferenceKey: PreferenceKey {\n    static var defaultValue: CGPoint = .zero\n\n    static func reduce(value: inout CGPoint, nextValue: () -> CGPoint) {}\n}\n\nprivate struct ScrollHeightPreferenceKey: PreferenceKey {\n    static var defaultValue: CGFloat = .zero\n\n    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {}\n}\n\nprivate struct AutoScrollButton: View {\n    let isVisible: Bool\n    let action: () -> Void\n\n    var body: some View {\n        Button {\n            action()\n        } label: {\n            Image(systemName: \"arrowshape.down.fill\")\n                .font(.body)\n                .foregroundColor(.primary)\n                .padding(8)\n        }\n        .background(\n            Circle()\n                .fill(Color(.secondarySystemBackground))\n                .stroke(.primary.opacity(0.1), lineWidth:1)\n        ).shadow(color:.primary.opacity(0.14), radius: 3, x:0, y:2)\n        .opacity(isVisible ? 1 : 0)\n    }\n\n}\n\n#Preview {\n    ChatView(chatManager: ChatManager())\n}\n"
  },
  {
    "path": "Demos/Chat/Chat/Preview Content/Preview Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/Chat/Chat.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 56;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t0DDD23062B4DE02100B2AE5C /* ChatApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD23052B4DE02100B2AE5C /* ChatApp.swift */; };\n\t\t0DDD230A2B4DE02200B2AE5C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0DDD23092B4DE02200B2AE5C /* Assets.xcassets */; };\n\t\t0DDD230D2B4DE02200B2AE5C /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0DDD230C2B4DE02200B2AE5C /* Preview Assets.xcassets */; };\n\t\t0DDD23F42B4DE6DC00B2AE5C /* ChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD23F32B4DE6DC00B2AE5C /* ChatView.swift */; };\n\t\t0DDD23F62B4DE6FA00B2AE5C /* ChatBubble.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD23F52B4DE6FA00B2AE5C /* ChatBubble.swift */; };\n\t\t0DDD23FB2B4DE70A00B2AE5C /* ChatMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD23F72B4DE70A00B2AE5C /* ChatMessage.swift */; };\n\t\t0DDD23FC2B4DE70A00B2AE5C /* ChatManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD23F82B4DE70A00B2AE5C /* ChatManager.swift */; };\n\t\t0DDD23FD2B4DE70A00B2AE5C /* ChatInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD23F92B4DE70A00B2AE5C /* ChatInputView.swift */; };\n\t\t0DDD23FE2B4DE70A00B2AE5C /* ChatDataLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD23FA2B4DE70A00B2AE5C /* ChatDataLoader.swift */; };\n\t\t0DDD24002B4DE79300B2AE5C /* AppConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD23FF2B4DE79300B2AE5C /* AppConstants.swift */; };\n\t\t0DDD24022B4DE7AF00B2AE5C /* AppLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD24012B4DE7AF00B2AE5C /* AppLogger.swift */; };\n\t\t2CE7709B2C9B59C000EC6C74 /* AIProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 2CE7709A2C9B59C000EC6C74 /* AIProxy */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t0DDD23022B4DE02100B2AE5C /* Chat.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Chat.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t0DDD23052B4DE02100B2AE5C /* ChatApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatApp.swift; sourceTree = \"<group>\"; };\n\t\t0DDD23092B4DE02200B2AE5C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t0DDD230C2B4DE02200B2AE5C /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = \"Preview Assets.xcassets\"; sourceTree = \"<group>\"; };\n\t\t0DDD23F32B4DE6DC00B2AE5C /* ChatView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatView.swift; sourceTree = \"<group>\"; };\n\t\t0DDD23F52B4DE6FA00B2AE5C /* ChatBubble.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatBubble.swift; sourceTree = \"<group>\"; };\n\t\t0DDD23F72B4DE70A00B2AE5C /* ChatMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatMessage.swift; sourceTree = \"<group>\"; };\n\t\t0DDD23F82B4DE70A00B2AE5C /* ChatManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatManager.swift; sourceTree = \"<group>\"; };\n\t\t0DDD23F92B4DE70A00B2AE5C /* ChatInputView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatInputView.swift; sourceTree = \"<group>\"; };\n\t\t0DDD23FA2B4DE70A00B2AE5C /* ChatDataLoader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatDataLoader.swift; sourceTree = \"<group>\"; };\n\t\t0DDD23FF2B4DE79300B2AE5C /* AppConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppConstants.swift; sourceTree = \"<group>\"; };\n\t\t0DDD24012B4DE7AF00B2AE5C /* AppLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppLogger.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t0DDD22FF2B4DE02100B2AE5C /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2CE7709B2C9B59C000EC6C74 /* AIProxy in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t0DDD22F92B4DE02100B2AE5C = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0DDD23042B4DE02100B2AE5C /* Chat */,\n\t\t\t\t0DDD23032B4DE02100B2AE5C /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0DDD23032B4DE02100B2AE5C /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0DDD23022B4DE02100B2AE5C /* Chat.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0DDD23042B4DE02100B2AE5C /* Chat */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0DDD23FF2B4DE79300B2AE5C /* AppConstants.swift */,\n\t\t\t\t0DDD24012B4DE7AF00B2AE5C /* AppLogger.swift */,\n\t\t\t\t0DDD23052B4DE02100B2AE5C /* ChatApp.swift */,\n\t\t\t\t0DDD23F52B4DE6FA00B2AE5C /* ChatBubble.swift */,\n\t\t\t\t0DDD23FA2B4DE70A00B2AE5C /* ChatDataLoader.swift */,\n\t\t\t\t0DDD23F92B4DE70A00B2AE5C /* ChatInputView.swift */,\n\t\t\t\t0DDD23F82B4DE70A00B2AE5C /* ChatManager.swift */,\n\t\t\t\t0DDD23F72B4DE70A00B2AE5C /* ChatMessage.swift */,\n\t\t\t\t0DDD23F32B4DE6DC00B2AE5C /* ChatView.swift */,\n\t\t\t\t0DDD23092B4DE02200B2AE5C /* Assets.xcassets */,\n\t\t\t\t0DDD230B2B4DE02200B2AE5C /* Preview Content */,\n\t\t\t);\n\t\t\tpath = Chat;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0DDD230B2B4DE02200B2AE5C /* Preview Content */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0DDD230C2B4DE02200B2AE5C /* Preview Assets.xcassets */,\n\t\t\t);\n\t\t\tpath = \"Preview Content\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t0DDD23012B4DE02100B2AE5C /* Chat */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 0DDD23102B4DE02200B2AE5C /* Build configuration list for PBXNativeTarget \"Chat\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t0DDD22FE2B4DE02100B2AE5C /* Sources */,\n\t\t\t\t0DDD22FF2B4DE02100B2AE5C /* Frameworks */,\n\t\t\t\t0DDD23002B4DE02100B2AE5C /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = Chat;\n\t\t\tpackageProductDependencies = (\n\t\t\t\t2CE7709A2C9B59C000EC6C74 /* AIProxy */,\n\t\t\t);\n\t\t\tproductName = Chat;\n\t\t\tproductReference = 0DDD23022B4DE02100B2AE5C /* Chat.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t0DDD22FA2B4DE02100B2AE5C /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = 1;\n\t\t\t\tLastSwiftUpdateCheck = 1510;\n\t\t\t\tLastUpgradeCheck = 1510;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t0DDD23012B4DE02100B2AE5C = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 15.1;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 0DDD22FD2B4DE02100B2AE5C /* Build configuration list for PBXProject \"Chat\" */;\n\t\t\tcompatibilityVersion = \"Xcode 14.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 0DDD22F92B4DE02100B2AE5C;\n\t\t\tpackageReferences = (\n\t\t\t\t2CE770992C9B59C000EC6C74 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */,\n\t\t\t);\n\t\t\tproductRefGroup = 0DDD23032B4DE02100B2AE5C /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t0DDD23012B4DE02100B2AE5C /* Chat */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t0DDD23002B4DE02100B2AE5C /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t0DDD230D2B4DE02200B2AE5C /* Preview Assets.xcassets in Resources */,\n\t\t\t\t0DDD230A2B4DE02200B2AE5C /* Assets.xcassets in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t0DDD22FE2B4DE02100B2AE5C /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t0DDD23FE2B4DE70A00B2AE5C /* ChatDataLoader.swift in Sources */,\n\t\t\t\t0DDD23F42B4DE6DC00B2AE5C /* ChatView.swift in Sources */,\n\t\t\t\t0DDD23FD2B4DE70A00B2AE5C /* ChatInputView.swift in Sources */,\n\t\t\t\t0DDD24002B4DE79300B2AE5C /* AppConstants.swift in Sources */,\n\t\t\t\t0DDD23FB2B4DE70A00B2AE5C /* ChatMessage.swift in Sources */,\n\t\t\t\t0DDD23F62B4DE6FA00B2AE5C /* ChatBubble.swift in Sources */,\n\t\t\t\t0DDD24022B4DE7AF00B2AE5C /* AppLogger.swift in Sources */,\n\t\t\t\t0DDD23FC2B4DE70A00B2AE5C /* ChatManager.swift in Sources */,\n\t\t\t\t0DDD23062B4DE02100B2AE5C /* ChatApp.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t0DDD230E2B4DE02200B2AE5C /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.2;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"DEBUG $(inherited)\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t0DDD230F2B4DE02200B2AE5C /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.2;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t0DDD23112B4DE02200B2AE5C /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"Chat/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 9557YJ9D37;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.aiproxy.bootstrap.chat;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t0DDD23122B4DE02200B2AE5C /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"Chat/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 9557YJ9D37;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.aiproxy.bootstrap.chat;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t0DDD22FD2B4DE02100B2AE5C /* Build configuration list for PBXProject \"Chat\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t0DDD230E2B4DE02200B2AE5C /* Debug */,\n\t\t\t\t0DDD230F2B4DE02200B2AE5C /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t0DDD23102B4DE02200B2AE5C /* Build configuration list for PBXNativeTarget \"Chat\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t0DDD23112B4DE02200B2AE5C /* Debug */,\n\t\t\t\t0DDD23122B4DE02200B2AE5C /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCRemoteSwiftPackageReference section */\n\t\t2CE770992C9B59C000EC6C74 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/lzell/AIProxySwift\";\n\t\t\trequirement = {\n\t\t\t\tbranch = main;\n\t\t\t\tkind = branch;\n\t\t\t};\n\t\t};\n/* End XCRemoteSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */\n\t\t2CE7709A2C9B59C000EC6C74 /* AIProxy */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 2CE770992C9B59C000EC6C74 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */;\n\t\t\tproductName = AIProxy;\n\t\t};\n/* End XCSwiftPackageProductDependency section */\n\t};\n\trootObject = 0DDD22FA2B4DE02100B2AE5C /* Project object */;\n}\n"
  },
  {
    "path": "Demos/Classifier/Classifier/AppConstants.swift",
    "content": "//\n//  AppConstants.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport SwiftData\nimport AIProxy\n\nenum AppConstants {\n    \n    static let videoSampleQueue = DispatchQueue(label: \"com.AIProxyBootstrap.videoSampleQueue\")\n    \n    #error(\n        \"\"\"\n        Uncomment one of the methods below. To build and run on device you must follow the AIProxy integration guide.\n        Please see https://www.aiproxy.pro/docs/integration-guide.html\")\n        \"\"\"\n    )\n    \n    /* Uncomment for BYOK use cases */\n    static let openAIService = AIProxy.openAIDirectService(\n        unprotectedAPIKey: \"your-openai-key\"\n    )\n\n    /* Uncomment for all other production use cases */\n//    static let openAIService = AIProxy.openAIService(\n//        partialKey: \"partial-key-from-your-developer-dashboard\",\n//        serviceURL: \"service-url-from-your-developer-dashboard\"\n//    )\n}\n"
  },
  {
    "path": "Demos/Classifier/Classifier/AppLogger.swift",
    "content": "//\n//  AppLogger.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport OSLog\n\n/// Log levels available:\n///\n///     AppLogger.debug\n///     AppLogger.info\n///     AppLogger.warning\n///     AppLogger.error\n///     AppLogger.critical\n///\n/// Flip on metadata logging in Xcode's console to show which source line the log occurred from.\n///\n/// See my reddit post for a video instructions:\n/// https://www.reddit.com/r/SwiftUI/comments/15lsdtk/how_to_use_the_oslog_logger/\nlet AppLogger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"UnknownApp\",\n                       category: \"AIProxyBootstrapClassifier\")\n"
  },
  {
    "path": "Demos/Classifier/Classifier/Assets.xcassets/AccentColor.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/Classifier/Classifier/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"classify.png\",\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/Classifier/Classifier/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/Classifier/Classifier/CameraControlsView.swift",
    "content": "//\n//  CameraControlsView.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport SwiftUI\n\nstruct CameraControlsView: View {\n\n    let shutterButtonAction: () -> Void\n\n    var body: some View {\n\n        Button(action: shutterButtonAction) {\n            ZStack{\n                Circle()\n                    .fill(.clear)\n                    .stroke(.mint, lineWidth: 4)\n                    .frame(width:72, height: 72)\n                Circle()\n                    .fill(.mint.gradient)\n                    .frame(width:60, height: 60)\n                Image(systemName: \"camera\")\n                    .font(.title2)\n                    .fontWeight(.semibold)\n                    .foregroundColor(.black.opacity(0.4))\n            }\n        }\n        .buttonStyle(.plain)\n    }\n}\n\n#Preview {\n    CameraControlsView(shutterButtonAction: {})\n}\n"
  },
  {
    "path": "Demos/Classifier/Classifier/CameraDataLoader.swift",
    "content": "//\n//  CameraFrameHandler.swift\n//  AIProxyBootstrap\n//\n//  Created by Todd Hamilton\n//\n\nimport AVFoundation\nimport CoreImage\n\n/// Vends camera frames from the built-in back camera.\nfinal actor CameraDataLoader {\n    private let sampleBufferDelegate = CameraFrameSampleBufferDelegate()\n    private let captureSession = AVCaptureSession()\n\n    /// Streams images of the camera frame.\n    /// Use the returned stream in a `for await` loop.\n    func imageStream() -> AsyncStream<CGImage> {\n        self.setupCaptureSession()\n        self.captureSession.startRunning()\n        return AsyncStream { [weak self] continuation in\n            self?.sampleBufferDelegate.didReceiveImage = { image in\n                continuation.yield(image)\n            }\n        }\n    }\n\n    private func setupCaptureSession() {\n        let videoOutput = AVCaptureVideoDataOutput()\n        guard let videoDevice = AVCaptureDevice.default(.builtInDualWideCamera,for: .video, position: .back) else { return }\n        guard let videoDeviceInput = try? AVCaptureDeviceInput(device: videoDevice) else { return }\n        guard captureSession.canAddInput(videoDeviceInput) else { return }\n        captureSession.addInput(videoDeviceInput)\n\n        videoOutput.setSampleBufferDelegate(\n            sampleBufferDelegate,\n            queue: AppConstants.videoSampleQueue\n        )\n        captureSession.addOutput(videoOutput)\n\n        videoOutput.connection(with: .video)?.videoRotationAngle = 90\n    }\n}\n\n\nprivate final class CameraFrameSampleBufferDelegate: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate {\n    private let coreImageContext = CIContext()\n    var didReceiveImage: ((CGImage) -> Void)?\n\n    /// Delegate implementation for AVCaptureVideoDataOutputSampleBufferDelegate conformance\n    func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {\n        dispatchPrecondition(condition: .onQueue(AppConstants.videoSampleQueue))\n        guard let cgImage = self.imageFromSampleBuffer(sampleBuffer: sampleBuffer) else {\n            AppLogger.info(\"Could not convert a sample buffer from the camera into a CGImage\")\n            return\n        }\n\n        self.didReceiveImage?(cgImage)\n    }\n\n    private func imageFromSampleBuffer(sampleBuffer: CMSampleBuffer) -> CGImage? {\n        guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {\n            AppLogger.info(\"Could not get an image buffer from CMSampleBuffer\")\n            return nil\n        }\n\n        let ciImage = CIImage(cvPixelBuffer: imageBuffer)\n        guard let cgImage = self.coreImageContext.createCGImage(ciImage, from: ciImage.extent) else {\n            AppLogger.info(\"Could not create a CGImage using a core image context\")\n            return nil\n        }\n\n        return cgImage\n    }\n}\n"
  },
  {
    "path": "Demos/Classifier/Classifier/CameraFrameManager.swift",
    "content": "//\n//  CameraFrameManager.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport AVFoundation\nimport Foundation\nimport SwiftUI\n\n@MainActor\n@Observable\nfinal class CameraFrameManager {\n\n    /// The most recent camera frame of the back-facing built-in camera\n    private(set) var cameraFrameImage: CGImage?\n    private let cameraDataLoader = CameraDataLoader()\n\n    init() {\n        self.checkPermission() { [weak self] granted in\n            if granted {\n                self?.startCapturingCameraFrames()\n            }\n        }\n    }\n\n    private func startCapturingCameraFrames() {\n        Task {\n            let stream = await self.cameraDataLoader.imageStream()\n            for await image in stream {\n                self.cameraFrameImage = image\n            }\n        }\n    }\n\n    private func checkPermission(checkComplete: @escaping (Bool) -> Void) {\n        switch AVCaptureDevice.authorizationStatus(for: .video) {\n        case .authorized:\n            checkComplete(true)\n        case .notDetermined:\n            AVCaptureDevice.requestAccess(for: .video) { granted in\n                checkComplete(granted)\n            }\n        default:\n            checkComplete(false)\n        }\n    }\n}\n"
  },
  {
    "path": "Demos/Classifier/Classifier/CameraView.swift",
    "content": "//\n//  CameraView.swift\n//  AIProxyBootstrap\n//\n//  Created by Todd Hamilton\n//\n\nimport SwiftUI\n\nstruct CameraView: View {\n\n    /// The camera frame image to display\n    var image: CGImage?\n\n    private let label = Text(\"frame\")\n    \n    var body: some View {\n        GeometryReader { geo in\n           VStack {\n               if let image = image {\n                   Image(image, scale: 0.5, orientation: .up, label: label)\n                       .resizable()\n                       .scaledToFill()\n                       .frame(maxWidth:geo.size.width, maxHeight: geo.size.width)\n                       .clipShape(RoundedRectangle(cornerRadius: 14))\n                       .padding()\n\n               } else {\n                   Color.black\n                       .frame(maxWidth:geo.size.width, maxHeight: geo.size.width)\n                       .clipShape(RoundedRectangle(cornerRadius: 14))\n                       .padding()\n               }\n           }\n        }\n    }\n}\n\n#Preview {\n    CameraView()\n}\n"
  },
  {
    "path": "Demos/Classifier/Classifier/ClassifierApp.swift",
    "content": "//\n//  ClassifierApp.swift\n//  Classifier\n//\n//  Created by Lou Zell\n//\n\nimport SwiftUI\n\n@main\n@MainActor\nstruct ClassifierApp: App {\n\n    @State private var cameraFrameManager = CameraFrameManager()\n    @State private var classifierManager = ClassifierManager()\n\n    var body: some Scene {\n        WindowGroup {\n            ClassifierView(cameraFrameManager: cameraFrameManager,\n                           classifierManager: classifierManager)\n        }\n    }\n}\n"
  },
  {
    "path": "Demos/Classifier/Classifier/ClassifierDataLoader.swift",
    "content": "//\n//  ClassifierDataLoader.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport UIKit\nimport RegexBuilder\nimport AIProxy\n\nenum ClassifierDataLoaderError: Error {\n    case couldNotCreateImageURL\n    case couldNotIdentifyPlant\n}\n\n/// Sends requests to OpenAI to classify plant images, and returns the result asynchronously\nfinal actor ClassifierDataLoader {\n\n    /// Uses OpenAI to fetch a description of the image passed as argument\n    /// - Parameter image: The image to describe\n    /// - Returns: An OpenAI description of the image\n    func identify(fromImage image: CGImage) async throws -> (String, URL?) {\n\n        guard let localURL = image.openAILocalURLEncoding() else {\n            throw ClassifierDataLoaderError.couldNotCreateImageURL\n        }\n  \n        let prompt = \"What kind of plant is this and provide the wikipedia link for it, not in markdown\"\n        let response = try await AppConstants.openAIService.chatCompletionRequest(body: .init(\n            model: \"gpt-4o\",\n            messages: [\n                .user(\n                    content: .parts(\n                        [\n                            .text(prompt),\n                            .imageURL(localURL, detail: .auto)\n                        ]\n                    )\n                )\n            ]\n        ))\n        let choices = response.choices\n        guard let text = choices.first?.message.content else {\n            throw ClassifierDataLoaderError.couldNotIdentifyPlant\n        }\n\n        return extractDescriptionAndWikipediaURL(text)\n    }\n}\n\n\n// Assumes that the wikipedia link as at the end of input `text`\nprivate func extractDescriptionAndWikipediaURL(_ text: String) -> (String, URL?) {\n    var mutableText = text\n    let re = Regex {\n        TryCapture {\n           /https?:\\/\\/[^.]*\\.wikipedia\\.org[^\\b]+$/\n        } transform: {\n            URL(string: String($0))\n        }\n    }\n\n    var matchingURL: URL? = nil\n    mutableText.replace(re, maxReplacements: 1) { matchingURL = $0.1; return \"\" }\n    return (mutableText, matchingURL)\n}\n\nprivate extension CGImage {\n    func openAILocalURLEncoding() -> URL? {\n        if let data = UIImage(cgImage: self).jpegData(compressionQuality: 0.4) {\n            let base64String = data.base64EncodedString()\n            if let url = URL(string: \"data:image/jpeg;base64,\\(base64String)\") {\n                return url\n            }\n        }\n        return nil\n    }\n}\n"
  },
  {
    "path": "Demos/Classifier/Classifier/ClassifierManager.swift",
    "content": "//\n//  ClassifierManager.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport SwiftUI\n\n@MainActor\n@Observable\nfinal class ClassifierManager {\n    /// The description of a plant. Descriptions are generated by OpenAI\n    private(set) var plantDescription: String?\n\n    /// The image of a plant. This camera image is supplied by the user\n    private(set) var image: CGImage?\n\n    /// A wikipedia URL for the user to learn more about the identified plant. This URL is generated by OpenAI\n    private(set) var wikipediaURL: URL?\n\n    /// Loads data from OpenAI\n    private let classifierDataLoader = ClassifierDataLoader()\n\n    /// Identify a plant based on a passed in image\n    /// - Parameter image: a camera frame that the user took of a plant in their surroundings\n    func identify(_ image: CGImage) {\n        self.image = image\n        Task {\n            let (description, wikipediaURL) = try await classifierDataLoader.identify(fromImage: image)\n            self.plantDescription = description\n            self.wikipediaURL = wikipediaURL\n        }\n    }\n    \n    /// Reset all previously classified state\n    func reset() {\n        self.plantDescription = nil\n        self.image = nil\n        self.wikipediaURL = nil\n    }\n}\n"
  },
  {
    "path": "Demos/Classifier/Classifier/ClassifierView.swift",
    "content": "//\n//  ClassifierView.swift\n//  AIProxyBootstrap\n//\n//  Created by Todd Hamilton\n//\n\nimport SwiftUI\n\n@MainActor\nstruct ClassifierView: View {\n\n    let cameraFrameManager: CameraFrameManager\n    let classifierManager: ClassifierManager\n    @Environment(\\.dismiss) private var dismiss\n    @State private var showingSheet = false\n\n    var body: some View {\n        ZStack {\n            Rectangle()\n                .fill(Color(.secondarySystemBackground))\n                .ignoresSafeArea()\n\n            VStack {\n                CameraView(image: cameraFrameManager.cameraFrameImage)\n\n                Text(\"Take a photo to identify a plant\")\n                    .fontWeight(.semibold)\n                    .font(.subheadline)\n                    .padding(16)\n                    .background(Color(.tertiarySystemBackground))\n                    .cornerRadius(8)\n\n                CameraControlsView(shutterButtonAction: {\n                    if let image = cameraFrameManager.cameraFrameImage {\n                        classifierManager.identify(image)\n                        showingSheet = true\n                    }\n                })\n                .padding()\n                .sheet(isPresented: $showingSheet){\n                    SheetView(classifierManager: classifierManager)\n                        .presentationDetents([.medium, .large])\n                        .presentationBackground(Color(.systemBackground))\n                }\n            }\n        }\n    }\n}\n\n\n/// A sheet that slides up over the camera controls to display the results of plant classification\nprivate struct SheetView: View {\n\n    let classifierManager: ClassifierManager\n    @Environment(\\.dismiss) var dismiss\n\n    var body: some View {\n        \n        if let plantDescription = classifierManager.plantDescription,\n           let plantImage = classifierManager.image {\n            ZStack(alignment:.topTrailing){\n                Button(){\n                    classifierManager.reset()\n                    dismiss()\n                }label:{\n                    Image(systemName: \"xmark.circle.fill\")\n                        .font(.system(size: 32))\n                        .foregroundColor(.secondary)\n                }\n                VStack(spacing:16){\n                    Image(uiImage: UIImage(cgImage: plantImage))\n                        .resizable()\n                        .scaledToFill()\n                        .frame(width:80, height:80)\n                        .cornerRadius(8)\n                        .clipShape(Circle())\n                        .overlay(\n                            Circle()\n                                .fill(.clear)\n                                .stroke(.mint, lineWidth:2)\n                        )\n                        .shadow(radius: 8, x: 0, y: 4)\n                    \n                    VStack(spacing:8){\n                        Text(\"Description\")\n                            .font(.title)\n                        Text(plantDescription)\n                            .font(.subheadline)\n                            .foregroundColor(.secondary)\n                    }\n                    if let wikipediaURL = classifierManager.wikipediaURL {\n                        Button(){\n                            UIApplication.shared.open(wikipediaURL)\n                        } label:{\n                            Text(\"View on Wikipedia\")\n                                .frame(maxWidth:.infinity)\n                                .fontWeight(.semibold)\n                                .foregroundColor(.white)\n                        }\n                        .buttonStyle(.borderedProminent)\n                        .controlSize(.large)\n                    }\n                }\n                .padding(.top, 16)\n            }\n            .padding(.horizontal, 16)\n            .padding(.vertical, 24)\n            .frame(maxWidth: .infinity, maxHeight: .infinity, alignment:.topLeading)\n            .transition(.opacity)\n        } else {\n            ProgressView()\n        }\n    }\n}\n\n\n#Preview {\n    ClassifierView(cameraFrameManager: CameraFrameManager(),\n                   classifierManager: ClassifierManager())\n}\n"
  },
  {
    "path": "Demos/Classifier/Classifier/Preview Content/Preview Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/Classifier/Classifier.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 56;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t0DDD23B42B4DE37500B2AE5C /* ClassifierApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD23B32B4DE37500B2AE5C /* ClassifierApp.swift */; };\n\t\t0DDD23B82B4DE37500B2AE5C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0DDD23B72B4DE37500B2AE5C /* Assets.xcassets */; };\n\t\t0DDD23BB2B4DE37500B2AE5C /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0DDD23BA2B4DE37500B2AE5C /* Preview Assets.xcassets */; };\n\t\t0DDD240D2B4DEE9700B2AE5C /* ClassifierManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD24062B4DEE9700B2AE5C /* ClassifierManager.swift */; };\n\t\t0DDD240E2B4DEE9700B2AE5C /* CameraControlsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD24072B4DEE9700B2AE5C /* CameraControlsView.swift */; };\n\t\t0DDD240F2B4DEE9700B2AE5C /* CameraView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD24082B4DEE9700B2AE5C /* CameraView.swift */; };\n\t\t0DDD24102B4DEE9700B2AE5C /* CameraFrameManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD24092B4DEE9700B2AE5C /* CameraFrameManager.swift */; };\n\t\t0DDD24112B4DEE9700B2AE5C /* ClassifierView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD240A2B4DEE9700B2AE5C /* ClassifierView.swift */; };\n\t\t0DDD24122B4DEE9700B2AE5C /* ClassifierDataLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD240B2B4DEE9700B2AE5C /* ClassifierDataLoader.swift */; };\n\t\t0DDD24132B4DEE9700B2AE5C /* CameraDataLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD240C2B4DEE9700B2AE5C /* CameraDataLoader.swift */; };\n\t\t0DDD24162B4DEEB400B2AE5C /* AppLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD24142B4DEEB400B2AE5C /* AppLogger.swift */; };\n\t\t0DDD24172B4DEEB400B2AE5C /* AppConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD24152B4DEEB400B2AE5C /* AppConstants.swift */; };\n\t\t2CE770982C9B55D700EC6C74 /* AIProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 2CE770972C9B55D700EC6C74 /* AIProxy */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t0DDD23B02B4DE37500B2AE5C /* Classifier.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Classifier.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t0DDD23B32B4DE37500B2AE5C /* ClassifierApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClassifierApp.swift; sourceTree = \"<group>\"; };\n\t\t0DDD23B72B4DE37500B2AE5C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t0DDD23BA2B4DE37500B2AE5C /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = \"Preview Assets.xcassets\"; sourceTree = \"<group>\"; };\n\t\t0DDD24062B4DEE9700B2AE5C /* ClassifierManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClassifierManager.swift; sourceTree = \"<group>\"; };\n\t\t0DDD24072B4DEE9700B2AE5C /* CameraControlsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraControlsView.swift; sourceTree = \"<group>\"; };\n\t\t0DDD24082B4DEE9700B2AE5C /* CameraView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraView.swift; sourceTree = \"<group>\"; };\n\t\t0DDD24092B4DEE9700B2AE5C /* CameraFrameManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraFrameManager.swift; sourceTree = \"<group>\"; };\n\t\t0DDD240A2B4DEE9700B2AE5C /* ClassifierView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClassifierView.swift; sourceTree = \"<group>\"; };\n\t\t0DDD240B2B4DEE9700B2AE5C /* ClassifierDataLoader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClassifierDataLoader.swift; sourceTree = \"<group>\"; };\n\t\t0DDD240C2B4DEE9700B2AE5C /* CameraDataLoader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraDataLoader.swift; sourceTree = \"<group>\"; };\n\t\t0DDD24142B4DEEB400B2AE5C /* AppLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppLogger.swift; sourceTree = \"<group>\"; };\n\t\t0DDD24152B4DEEB400B2AE5C /* AppConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppConstants.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t0DDD23AD2B4DE37500B2AE5C /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2CE770982C9B55D700EC6C74 /* AIProxy in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t0DDD23A72B4DE37500B2AE5C = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0DDD23B22B4DE37500B2AE5C /* Classifier */,\n\t\t\t\t0DDD23B12B4DE37500B2AE5C /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0DDD23B12B4DE37500B2AE5C /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0DDD23B02B4DE37500B2AE5C /* Classifier.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0DDD23B22B4DE37500B2AE5C /* Classifier */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0DDD24152B4DEEB400B2AE5C /* AppConstants.swift */,\n\t\t\t\t0DDD24142B4DEEB400B2AE5C /* AppLogger.swift */,\n\t\t\t\t0DDD24072B4DEE9700B2AE5C /* CameraControlsView.swift */,\n\t\t\t\t0DDD240C2B4DEE9700B2AE5C /* CameraDataLoader.swift */,\n\t\t\t\t0DDD24092B4DEE9700B2AE5C /* CameraFrameManager.swift */,\n\t\t\t\t0DDD24082B4DEE9700B2AE5C /* CameraView.swift */,\n\t\t\t\t0DDD23B32B4DE37500B2AE5C /* ClassifierApp.swift */,\n\t\t\t\t0DDD240B2B4DEE9700B2AE5C /* ClassifierDataLoader.swift */,\n\t\t\t\t0DDD24062B4DEE9700B2AE5C /* ClassifierManager.swift */,\n\t\t\t\t0DDD240A2B4DEE9700B2AE5C /* ClassifierView.swift */,\n\t\t\t\t0DDD23B72B4DE37500B2AE5C /* Assets.xcassets */,\n\t\t\t\t0DDD23B92B4DE37500B2AE5C /* Preview Content */,\n\t\t\t);\n\t\t\tpath = Classifier;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0DDD23B92B4DE37500B2AE5C /* Preview Content */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0DDD23BA2B4DE37500B2AE5C /* Preview Assets.xcassets */,\n\t\t\t);\n\t\t\tpath = \"Preview Content\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t0DDD23AF2B4DE37500B2AE5C /* Classifier */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 0DDD23BE2B4DE37500B2AE5C /* Build configuration list for PBXNativeTarget \"Classifier\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t0DDD23AC2B4DE37500B2AE5C /* Sources */,\n\t\t\t\t0DDD23AD2B4DE37500B2AE5C /* Frameworks */,\n\t\t\t\t0DDD23AE2B4DE37500B2AE5C /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = Classifier;\n\t\t\tpackageProductDependencies = (\n\t\t\t\t2CE770972C9B55D700EC6C74 /* AIProxy */,\n\t\t\t);\n\t\t\tproductName = Classifier;\n\t\t\tproductReference = 0DDD23B02B4DE37500B2AE5C /* Classifier.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t0DDD23A82B4DE37500B2AE5C /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = 1;\n\t\t\t\tLastSwiftUpdateCheck = 1510;\n\t\t\t\tLastUpgradeCheck = 1510;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t0DDD23AF2B4DE37500B2AE5C = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 15.1;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 0DDD23AB2B4DE37500B2AE5C /* Build configuration list for PBXProject \"Classifier\" */;\n\t\t\tcompatibilityVersion = \"Xcode 14.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 0DDD23A72B4DE37500B2AE5C;\n\t\t\tpackageReferences = (\n\t\t\t\t2CE770962C9B55D700EC6C74 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */,\n\t\t\t);\n\t\t\tproductRefGroup = 0DDD23B12B4DE37500B2AE5C /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t0DDD23AF2B4DE37500B2AE5C /* Classifier */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t0DDD23AE2B4DE37500B2AE5C /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t0DDD23BB2B4DE37500B2AE5C /* Preview Assets.xcassets in Resources */,\n\t\t\t\t0DDD23B82B4DE37500B2AE5C /* Assets.xcassets in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t0DDD23AC2B4DE37500B2AE5C /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t0DDD24112B4DEE9700B2AE5C /* ClassifierView.swift in Sources */,\n\t\t\t\t0DDD23B42B4DE37500B2AE5C /* ClassifierApp.swift in Sources */,\n\t\t\t\t0DDD24102B4DEE9700B2AE5C /* CameraFrameManager.swift in Sources */,\n\t\t\t\t0DDD240D2B4DEE9700B2AE5C /* ClassifierManager.swift in Sources */,\n\t\t\t\t0DDD24132B4DEE9700B2AE5C /* CameraDataLoader.swift in Sources */,\n\t\t\t\t0DDD24122B4DEE9700B2AE5C /* ClassifierDataLoader.swift in Sources */,\n\t\t\t\t0DDD24162B4DEEB400B2AE5C /* AppLogger.swift in Sources */,\n\t\t\t\t0DDD240E2B4DEE9700B2AE5C /* CameraControlsView.swift in Sources */,\n\t\t\t\t0DDD240F2B4DEE9700B2AE5C /* CameraView.swift in Sources */,\n\t\t\t\t0DDD24172B4DEEB400B2AE5C /* AppConstants.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t0DDD23BC2B4DE37500B2AE5C /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.2;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"DEBUG $(inherited)\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t0DDD23BD2B4DE37500B2AE5C /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.2;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t0DDD23BF2B4DE37500B2AE5C /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"Classifier/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 9557YJ9D37;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_NSCameraUsageDescription = \"Access to the camera is required to take a photo of your plant\";\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.aiproxy.bootstrap.classifier;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t0DDD23C02B4DE37500B2AE5C /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"Classifier/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 9557YJ9D37;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_NSCameraUsageDescription = \"Access to the camera is required to take a photo of your plant\";\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.aiproxy.bootstrap.classifier;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t0DDD23AB2B4DE37500B2AE5C /* Build configuration list for PBXProject \"Classifier\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t0DDD23BC2B4DE37500B2AE5C /* Debug */,\n\t\t\t\t0DDD23BD2B4DE37500B2AE5C /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t0DDD23BE2B4DE37500B2AE5C /* Build configuration list for PBXNativeTarget \"Classifier\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t0DDD23BF2B4DE37500B2AE5C /* Debug */,\n\t\t\t\t0DDD23C02B4DE37500B2AE5C /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCRemoteSwiftPackageReference section */\n\t\t2CE770962C9B55D700EC6C74 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/lzell/AIProxySwift\";\n\t\t\trequirement = {\n\t\t\t\tbranch = main;\n\t\t\t\tkind = branch;\n\t\t\t};\n\t\t};\n/* End XCRemoteSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */\n\t\t2CE770972C9B55D700EC6C74 /* AIProxy */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 2CE770962C9B55D700EC6C74 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */;\n\t\t\tproductName = AIProxy;\n\t\t};\n/* End XCSwiftPackageProductDependency section */\n\t};\n\trootObject = 0DDD23A82B4DE37500B2AE5C /* Project object */;\n}\n"
  },
  {
    "path": "Demos/EmojiPuzzleMaker/EmojiPuzzleMaker/Assets.xcassets/AccentColor.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/EmojiPuzzleMaker/EmojiPuzzleMaker/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/EmojiPuzzleMaker/EmojiPuzzleMaker/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/EmojiPuzzleMaker/EmojiPuzzleMaker/ContentView.swift",
    "content": "//\n//  ContentView.swift\n//  EmojiPuzzleMaker\n//\n//  Created by Todd Hamilton on 8/1/24.\n//\n\nimport AIProxy\nimport SwiftUI\nimport WebKit\nimport Foundation\n\n#error(\n    \"\"\"\n    Uncomment one of the methods below. To build and run on device you must follow the AIProxy integration guide.\n    Please see https://www.aiproxy.pro/docs/integration-guide.html\")\n    \"\"\"\n)\n\n/* Uncomment for BYOK use cases */\nlet anthropicService = AIProxy.anthropicDirectService(\n    unprotectedAPIKey: \"your-anthropic-key\"\n)\n\n/* Uncomment for all other production use cases */\n//let anthropicService = AIProxy.anthropicService(\n//    partialKey: \"partial-key-from-your-developer-dashboard\",\n//    serviceURL: \"service-url-from-your-developer-dashboard\"\n//)\n\nstruct ContentView: View {\n\n    @State var emojis = \"🏔️💦\"\n    @State var hint = \"A fizzy green beverage\"\n    @State var prompt = \"\"\n    @State var color = \"blue\"\n    @State var json = \"\"\n    let instructions = \"\"\"\n    You are an AI tasked with generating a fun and interesting emoji puzzle based on a given word or phrase. Your goal is to create a puzzle using 2-3 emojis that represent the word or phrase, along with a hint to help solve the puzzle. Follow these guidelines:\n    \n    1. Analyze the given word or phrase and think of relevant emojis that can represent it.\n    2. Choose 2-3 emojis that, when combined, cleverly represent the word or phrase.\n    3. Ensure the emojis are not too obvious, but also not impossibly difficult to decipher.\n    4. Create a short, helpful hint that gives a clue about the word or phrase without directly stating it.\n    5. Choose a SwiftUI color to match the theme of the puzzle.\n    6. Your returned message content should only be valid JSON. Do not introduce the JSON with \"Here is my emoji puzzle response\" or any other introduction.\n    7. In the JSON for `emojis` field, always put a space between unicode characters\n    \n    Generate a hint text that provides a subtle clue about the word or phrase without giving it away completely. The hint should be concise and engaging, encouraging the puzzle solver to think creatively.\n    \n    Your response should be in valid JSON format with the following structure:\n    {\n      \"emojis\": \"unicode_emoji1 unicode_emoji2 ...\",\n      \"hint\": \"Your hint text here\",\n      \"color\": \"The SwiftUI color here\",\n      \"solution\": \"The original word or phrase\"\n    }\n    \n    Example output for the prompt 'Starbucks':\n    {\n      \"emojis\": \"⭐️ 💵\",\n      \"hint\": \"Your daily fix\",\n      \"color\": \"brown\",\n      \"solution\": \"Starbucks\"\n    }\n    \n    Remember to use unicode representations for the emojis and ensure your output is in valid JSON format.\n    \n    Here is the word or phrase to base your emoji puzzle on:\n    \"\"\"\n\n    var body: some View {\n\n        VStack{\n            Spacer()\n            Text(\"Make an emoji puzzle!\")\n                .font(.title)\n                .fontWeight(.bold)\n                .fontDesign(.rounded)\n            \n            if emojis == \"\" {\n                ProgressView()\n                    .controlSize(.large)\n                    .frame(maxHeight: 280)\n            }else {\n                VStack(spacing:12){\n                    Text(emojis)\n                        .font(.system(size: 72, weight: .bold, design: .rounded))\n                        .minimumScaleFactor(0.1)\n                        .frame(maxWidth:.infinity)\n                        .padding(.vertical, 72)\n                    Text(\"Hint: \\(hint)\")\n                        .font(.subheadline)\n                        .fontWeight(.medium)\n                        .fontDesign(.rounded)\n                        .fixedSize(horizontal: false, vertical: true)\n                        .multilineTextAlignment(.center)\n                        .padding(16)\n                        .foregroundStyle(.white)\n                        .background(.black.opacity(0.75))\n                        .cornerRadius(30)\n                }\n                .frame(maxWidth:.infinity, maxHeight: 280)\n                .transition(.scale)\n            }\n            \n\n            Spacer()\n\n            VStack(spacing:8){\n                TextField(\"ex. Mountain Dew\", text:$prompt)\n                    .keyboardType(.alphabet)\n                    .disableAutocorrection(true)\n                    .padding()\n                    .overlay(\n                        RoundedRectangle(cornerRadius: 10)\n                            .stroke(.black.opacity(0.24), lineWidth: 2)\n                    )\n                    .background(Color(.white))\n                    .cornerRadius(10)\n\n                Button{\n\n                    emojis = \"\"\n                    hint = \"\"\n\n                    Task{\n                        do{\n                            let prompt = \"\\n\\nHuman: \\(instructions + prompt)\\n\\nAssistant:\"\n                            let requestBody = AnthropicMessageRequestBody(\n                                maxTokens: 1024,\n                                messages: [\n                                    .init(content: [.text(prompt)], role: .user)\n                                ],\n                                model: \"claude-3-5-sonnet-20240620\"\n                            )\n                            let response = try await anthropicService.messageRequest(body: requestBody)\n                            if let puzzle = getPuzzle(fromClaudeResponse: response) {\n                                updateUI(withPuzzle: puzzle)\n                            }\n                        } catch {\n                            print(error.localizedDescription)\n                        }\n                    }\n                }label:{\n                    Text(\"Generate Puzzle\")\n                        .frame(maxWidth: .infinity)\n                }\n                .buttonStyle(.borderedProminent)\n                .controlSize(.large)\n                .tint(Color(string: color))\n                .fontWeight(.bold)\n\n            }\n            .padding(.horizontal,24)\n            Spacer()\n        }\n    }\n\n    func getPuzzle(fromClaudeResponse response: AnthropicMessageResponseBody) -> Puzzle? {\n        // We expected Claude to return a single text content in the response:\n        guard case .text(let messageContent) = response.content.first else {\n            print(\"Claude didn't return a text response\")\n            return nil\n        }\n\n        print(\"Puzzle content:\\n\\n\\(messageContent)\")\n        guard let jsonData = messageContent.data(using: .utf8) else {\n            print(\"Could not convert Claude's message to jsonData\")\n            return nil\n        }\n\n        do {\n            let decoder = JSONDecoder()\n            return try decoder.decode(Puzzle.self, from: jsonData)\n        } catch {\n            print(\"Error decoding puzzle JSON: \\(error)\")\n            return nil\n        }\n    }\n\n    func updateUI(withPuzzle puzzle: Puzzle) {\n        withAnimation(.snappy){\n            emojis = puzzle.emojis\n            hint = puzzle.hint\n            color = puzzle.color\n        }\n    }\n}\n\n// Define the struct that matches the JSON structure\nstruct Puzzle: Codable {\n    let emojis: String\n    let hint: String\n    let color: String\n    let solution: String\n}\n\nextension Color {\n    init?(string: String) {\n        switch string.lowercased() {\n        case \"red\":\n            self = .red\n        case \"orange\":\n            self = .orange\n        case \"yellow\":\n            self = .yellow\n        case \"green\":\n            self = .green\n        case \"blue\":\n            self = .blue\n        case \"purple\":\n            self = .purple\n        case \"pink\":\n            self = .pink\n        case \"black\":\n            self = .black\n        case \"white\":\n            self = .white\n        case \"gray\":\n            self = .gray\n        case \"teal\":\n            self = .teal\n        default:\n            return nil\n        }\n    }\n}\n\n#Preview {\n    ContentView()\n}\n"
  },
  {
    "path": "Demos/EmojiPuzzleMaker/EmojiPuzzleMaker/EmojiPuzzleMakerApp.swift",
    "content": "//\n//  EmojiPuzzleMakerApp.swift\n//  EmojiPuzzleMaker\n//\n//  Created by Todd Hamilton on 8/1/24.\n//\n\nimport SwiftUI\n\n@main\nstruct EmojiPuzzleMakerApp: App {\n    var body: some Scene {\n        WindowGroup {\n            ContentView()\n        }\n    }\n}\n"
  },
  {
    "path": "Demos/EmojiPuzzleMaker/EmojiPuzzleMaker/Preview Content/Preview Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/EmojiPuzzleMaker/EmojiPuzzleMaker.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 56;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t2C734B722C5C0415005EF970 /* EmojiPuzzleMakerApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C734B712C5C0415005EF970 /* EmojiPuzzleMakerApp.swift */; };\n\t\t2C734B742C5C0415005EF970 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C734B732C5C0415005EF970 /* ContentView.swift */; };\n\t\t2C734B762C5C0417005EF970 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2C734B752C5C0417005EF970 /* Assets.xcassets */; };\n\t\t2C734B792C5C0417005EF970 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2C734B782C5C0417005EF970 /* Preview Assets.xcassets */; };\n\t\t2C734B812C5C0445005EF970 /* AIProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 2C734B802C5C0445005EF970 /* AIProxy */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t2C734B6E2C5C0415005EF970 /* EmojiPuzzleMaker.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = EmojiPuzzleMaker.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t2C734B712C5C0415005EF970 /* EmojiPuzzleMakerApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPuzzleMakerApp.swift; sourceTree = \"<group>\"; };\n\t\t2C734B732C5C0415005EF970 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = \"<group>\"; };\n\t\t2C734B752C5C0417005EF970 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t2C734B782C5C0417005EF970 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = \"Preview Assets.xcassets\"; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t2C734B6B2C5C0415005EF970 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2C734B812C5C0445005EF970 /* AIProxy in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t2C734B652C5C0415005EF970 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2C734B702C5C0415005EF970 /* EmojiPuzzleMaker */,\n\t\t\t\t2C734B6F2C5C0415005EF970 /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2C734B6F2C5C0415005EF970 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2C734B6E2C5C0415005EF970 /* EmojiPuzzleMaker.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2C734B702C5C0415005EF970 /* EmojiPuzzleMaker */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2C734B712C5C0415005EF970 /* EmojiPuzzleMakerApp.swift */,\n\t\t\t\t2C734B732C5C0415005EF970 /* ContentView.swift */,\n\t\t\t\t2C734B752C5C0417005EF970 /* Assets.xcassets */,\n\t\t\t\t2C734B772C5C0417005EF970 /* Preview Content */,\n\t\t\t);\n\t\t\tpath = EmojiPuzzleMaker;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2C734B772C5C0417005EF970 /* Preview Content */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2C734B782C5C0417005EF970 /* Preview Assets.xcassets */,\n\t\t\t);\n\t\t\tpath = \"Preview Content\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t2C734B6D2C5C0415005EF970 /* EmojiPuzzleMaker */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 2C734B7C2C5C0417005EF970 /* Build configuration list for PBXNativeTarget \"EmojiPuzzleMaker\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t2C734B6A2C5C0415005EF970 /* Sources */,\n\t\t\t\t2C734B6B2C5C0415005EF970 /* Frameworks */,\n\t\t\t\t2C734B6C2C5C0415005EF970 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = EmojiPuzzleMaker;\n\t\t\tpackageProductDependencies = (\n\t\t\t\t2C734B802C5C0445005EF970 /* AIProxy */,\n\t\t\t);\n\t\t\tproductName = EmojiPuzzleMaker;\n\t\t\tproductReference = 2C734B6E2C5C0415005EF970 /* EmojiPuzzleMaker.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t2C734B662C5C0415005EF970 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = 1;\n\t\t\t\tLastSwiftUpdateCheck = 1540;\n\t\t\t\tLastUpgradeCheck = 1540;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t2C734B6D2C5C0415005EF970 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 15.4;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 2C734B692C5C0415005EF970 /* Build configuration list for PBXProject \"EmojiPuzzleMaker\" */;\n\t\t\tcompatibilityVersion = \"Xcode 14.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 2C734B652C5C0415005EF970;\n\t\t\tpackageReferences = (\n\t\t\t\t2C734B7F2C5C0445005EF970 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */,\n\t\t\t);\n\t\t\tproductRefGroup = 2C734B6F2C5C0415005EF970 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t2C734B6D2C5C0415005EF970 /* EmojiPuzzleMaker */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t2C734B6C2C5C0415005EF970 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2C734B792C5C0417005EF970 /* Preview Assets.xcassets in Resources */,\n\t\t\t\t2C734B762C5C0417005EF970 /* Assets.xcassets in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t2C734B6A2C5C0415005EF970 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2C734B742C5C0415005EF970 /* ContentView.swift in Sources */,\n\t\t\t\t2C734B722C5C0415005EF970 /* EmojiPuzzleMakerApp.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t2C734B7A2C5C0417005EF970 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.5;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"DEBUG $(inherited)\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2C734B7B2C5C0417005EF970 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.5;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t2C734B7D2C5C0417005EF970 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"EmojiPuzzleMaker/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 553LMX46SJ;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.toddham.EmojiPuzzleMaker;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2C734B7E2C5C0417005EF970 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"EmojiPuzzleMaker/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 553LMX46SJ;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.toddham.EmojiPuzzleMaker;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t2C734B692C5C0415005EF970 /* Build configuration list for PBXProject \"EmojiPuzzleMaker\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2C734B7A2C5C0417005EF970 /* Debug */,\n\t\t\t\t2C734B7B2C5C0417005EF970 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t2C734B7C2C5C0417005EF970 /* Build configuration list for PBXNativeTarget \"EmojiPuzzleMaker\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2C734B7D2C5C0417005EF970 /* Debug */,\n\t\t\t\t2C734B7E2C5C0417005EF970 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCRemoteSwiftPackageReference section */\n\t\t2C734B7F2C5C0445005EF970 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/lzell/AIProxySwift\";\n\t\t\trequirement = {\n\t\t\t\tbranch = main;\n\t\t\t\tkind = branch;\n\t\t\t};\n\t\t};\n/* End XCRemoteSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */\n\t\t2C734B802C5C0445005EF970 /* AIProxy */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 2C734B7F2C5C0445005EF970 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */;\n\t\t\tproductName = AIProxy;\n\t\t};\n/* End XCSwiftPackageProductDependency section */\n\t};\n\trootObject = 2C734B662C5C0415005EF970 /* Project object */;\n}\n"
  },
  {
    "path": "Demos/FilmFinder/FilmFinder/AppConstants.swift",
    "content": "//\n//  AppConstants.swift\n//  FilmFinder\n//\n//  Created by Todd Hamilton on 11/4/24.\n//\n\nimport AIProxy\n\n#error(\n    \"\"\"\n    Uncomment one of the methods below. To build and run on device you must follow the AIProxy integration guide.\n    Please see https://www.aiproxy.pro/docs/integration-guide.html\")\n    \n    You will also need a read access token from TMDB:\n    https://developer.themoviedb.org/docs/getting-started\n    \"\"\"\n)\n\n/* Uncomment for BYOK use cases */\nlet groqService = AIProxy.groqDirectService(\n    unprotectedAPIKey: \"your-groq-key\"\n)\n\n/* Uncomment for all other production use cases */\n//static let groqService = AIProxy.groqService(\n//    partialKey: \"partial-key-from-your-developer-dashboard\",\n//    serviceURL: \"service-url-from-your-developer-dashboard\"\n//)\n\nlet tmdb = \"api-read-access-token-from-tmdb\"\n"
  },
  {
    "path": "Demos/FilmFinder/FilmFinder/Assets.xcassets/AccentColor.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/FilmFinder/FilmFinder/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"icon.png\",\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ],\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"tinted\"\n        }\n      ],\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/FilmFinder/FilmFinder/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/FilmFinder/FilmFinder/ContentView.swift",
    "content": "//\n//  ContentView.swift\n//  FilmFinder\n//\n//  Created by Todd Hamilton on 10/28/24.\n//\n\nimport Foundation\nimport SwiftUI\nimport AIProxy\nimport UIKit\n\n\nstruct ContentView: View {\n    \n    @State private var isLoading = false\n    @State private var showingDetails = false\n    \n    @State var counter: Int = 0\n    @State var origin: CGPoint = CGPoint(x: 0.5, y: 0.5)\n\n    @State var movieID: String = \"335984\"\n    @State var movieTitle: String = \"Inside Out 2\"\n    @State var movieReleaseDate: String = \"10/06/2017 (US)\"\n    @State var moviePoster: String = \"vpnVM9B6NMmQpWeZvzLvDESb2QY.jpg\"\n    @State var movieBackdrop: String = \"p5ozvmdgsmbWe0H8Xk7Rc8SCwAB.jpg\"\n    @State var movieOverview: String = \"Teenager Riley's mind headquarters is undergoing a sudden demolition to make room for something entirely unexpected: new Emotions! Joy, Sadness, Anger, Fear and Disgust, who’ve long been running a successful operation by all accounts, aren’t sure how to feel when Anxiety shows up. And it looks like she’s not alone.\"\n    \n    @State var previousSuggestions:[String] = []\n    \n    @State var genreLabel: String = \"\"\n    let jsonExample:String = \"\"\"\n{\n  \"title\": \"the title of the movie\"\n}\n\"\"\"\n\n    var body: some View {\n        ZStack {\n            \n            // Background\n            Color.clear\n                .edgesIgnoringSafeArea(.all)\n                .background(\n                    AsyncImage(\n                        url: URL(string: \"https://image.tmdb.org/t/p/w500/\\(moviePoster)\"),\n                        content: { image in\n                            image.resizable()\n                                .ignoresSafeArea()\n                                .blur(radius: 50)\n                                .modifier(RippleEffect(at: origin, trigger: counter))\n                                .overlay(Color.black.opacity(0.5))\n                        },\n                        placeholder: {\n                            Color.clear\n                        }\n                    )\n                )\n            \n            VStack(spacing:0){\n                AsyncImage(\n                    url: URL(string: \"https://image.tmdb.org/t/p/w500/\\(moviePoster)\"),\n                    content: { image in\n                        image.resizable()\n                             .aspectRatio(contentMode: .fill)\n                             .frame(width: 192, height: 296)\n                             .cornerRadius(8)\n                             .shadow(radius: 8, x: 0, y: 4)\n                             .modifier(RippleEffect(at: origin, trigger: counter))\n                             .onTapGesture {\n                                 showingDetails.toggle()\n                             }\n                    },\n                    placeholder: {\n                        ProgressView()\n                            .frame(width: 192, height: 296)\n                    }\n                )\n                \n                Button{\n                    showingDetails.toggle()\n                }label:{\n                    if isLoading {\n                        ProgressView()\n                            .controlSize(.small)\n                            .padding(.horizontal, 12)\n                    } else {\n                        Text(\"\\(movieTitle)\")\n                            .font(.caption)\n                            .fontDesign(.monospaced)\n                            .lineLimit(1)\n                            .truncationMode(.tail)\n                            .padding(.horizontal, 12)\n                        \n                    }\n                }\n                .frame(maxHeight:34)\n                .background(\n                    Capsule()\n                        .fill(.thickMaterial)\n                        .stroke(.white.opacity(0.14))\n                )\n                .foregroundStyle(.white)\n                .padding()\n                .sheet(isPresented: $showingDetails) {\n                    MovieDetailsView(\n                        movieID: $movieID,\n                        movieBackdrop: $movieBackdrop,\n                        movieTitle: $movieTitle,\n                        movieReleaseDate: $movieReleaseDate,\n                        movieOverview: $movieOverview,\n                        genreLabel: $genreLabel\n                    )\n                    .presentationDetents([.large, .large])\n                    .presentationDragIndicator(.visible)\n                }\n                \n                GenreSelectorView(getMovieRecFromGroq: {\n                    Task{\n                        await getMovieRecFromGroq()\n                    }\n                    \n                }, genreLabel: $genreLabel)\n\n            }\n            \n        }\n        .preferredColorScheme(.dark)\n    }\n\n    \n    // Get the movie recommendation from Groq based on the selected genre\n    func getMovieRecFromGroq() async {\n    \n        isLoading = true\n\n        defer {\n            isLoading = false\n        }\n        do {\n            let response = try await groqService.chatCompletionRequest(body: .init(\n                messages: [\n                    .system(content: \"Recommend a \\(genreLabel) movie to watch. Respond with a single movie title and a description for why it was chosen only in json. Don't recommend any of the previous movies: \\(previousSuggestions). Do not include any other content in the repsonse. Use this example json as a template: \\(jsonExample). Make sure to recommend a wide variety of movies.\")\n                ],\n                model: \"llama3-8b-8192\",\n                responseFormat: .jsonObject\n                \n            ))\n            let movie = response.choices.first?.message.content ?? \"\"\n            await parseRecommendationFromGroq(movieData: movie)\n        }  catch AIProxyError.unsuccessfulRequest(let statusCode, let responseBody) {\n            print(\"Received non-200 status code: \\(statusCode) with response body: \\(responseBody)\")\n        } catch {\n            print(error.localizedDescription)\n        }\n    }\n    \n    // Parse the response from Groq, set variables, the fetch data from TMDB\n    func parseRecommendationFromGroq(movieData: String) async {\n        \n        let jsonData = movieData.data(using: .utf8)!\n        \n        // Decode JSON data\n        if let movie = try? JSONDecoder().decode(Recommendation.self, from: jsonData) {\n            movieTitle = movie.title\n            previousSuggestions.append(movieTitle)\n            await fetchMovieDataFromTMDB()\n        }\n    }\n    \n    // Fetch data from TMDB\n    func fetchMovieDataFromTMDB() async {\n        let url = URL(string: \"https://api.themoviedb.org/3/search/movie\")!\n        var components = URLComponents(url: url, resolvingAgainstBaseURL: true)!\n        let queryItems: [URLQueryItem] = [\n          URLQueryItem(name: \"query\", value: movieTitle),\n          URLQueryItem(name: \"include_adult\", value: \"false\"),\n          URLQueryItem(name: \"language\", value: \"en-US\"),\n          URLQueryItem(name: \"page\", value: \"1\"),\n        ]\n        components.queryItems = components.queryItems.map { $0 + queryItems } ?? queryItems\n\n        var request = URLRequest(url: components.url!)\n        request.httpMethod = \"GET\"\n        request.timeoutInterval = 10\n        request.allHTTPHeaderFields = [\n          \"accept\": \"application/json\",\n          \"Authorization\": \"Bearer \\(tmdb)\"\n        ]\n\n        do {\n            let (data, _) = try await URLSession.shared.data(for: request)\n            extractMovieDataFromTMDBResponse(tmdbResponse: String(decoding: data, as: UTF8.self))\n        } catch {\n            print(error.localizedDescription)\n        }\n    }\n    \n    // Parse the response from TMDB and store in state variables\n    func extractMovieDataFromTMDBResponse(tmdbResponse: String) {\n        // Convert JSON string to Data\n        if let jsonData = tmdbResponse.data(using: .utf8) {\n            do {\n                // Decode JSON to MovieResponse object\n                let movieResponse = try JSONDecoder().decode(MovieResponse.self, from: jsonData)\n                \n                // Access parsed data\n                if let firstMovie = movieResponse.results.first {\n                    movieID = String(firstMovie.id)\n                    movieReleaseDate = firstMovie.releaseDate\n                    movieOverview = firstMovie.overview\n                    moviePoster = firstMovie.posterPath ?? \"\"\n                    movieBackdrop = firstMovie.backdropPath ?? \"\"\n                    \n                    counter += 1\n                }\n            } catch {\n                print(\"Failed to decode JSON:\", error)\n            }\n        }\n    }\n    \n}\n\n#Preview {\n    ContentView()\n}\n"
  },
  {
    "path": "Demos/FilmFinder/FilmFinder/FilmFinderApp.swift",
    "content": "//\n//  FilmFinderApp.swift\n//  FilmFinder\n//\n//  Created by Todd Hamilton on 10/30/24.\n//\n\nimport SwiftUI\nimport TipKit\n\n@main\nstruct FilmFinderApp: App {\n    var body: some Scene {\n        WindowGroup {\n            ContentView()\n        }\n    }\n    \n    init() {\n        /// Load and configure the state of all the tips of the app\n        try? Tips.configure()\n    }\n}\n"
  },
  {
    "path": "Demos/FilmFinder/FilmFinder/GenreSelectorView.swift",
    "content": "//\n//  GenreSelectorView.swift\n//  FilmFinder\n//\n//  Created by Todd Hamilton on 11/3/24.\n//\n\nimport SwiftUI\nimport TipKit\n\nstruct GenreSelectorView: View {\n    \n    private let getStartedTip = GetStartedTip()\n    \n    private let modelSize: CGFloat = UIScreen.main.bounds.width - 40\n    private let gridSize = 40  // Adjust for more dots if desired\n    private let dotSize: CGFloat = 2\n    private let spacing: CGFloat = 20  // Increase spacing between dots\n    private let thresholdDistance: CGFloat = 75  // Max distance for attraction\n    \n    let getMovieRecFromGroq: () -> Void\n    \n    @State private var isDragging = false\n    @Binding var genreLabel: String\n    @State var genreScores: [String: Double] = [\n        \"Action\": 0.0,\n        \"Comedy\": 0.0,\n        \"Drama\": 0.0,\n        \"Horror\": 0.0,\n        \"Sci-Fi\": 0.0,\n        \"Fantasy\": 0.0,\n        \"Romance\": 0.0,\n        \"Documentary\": 0.0\n    ]\n    // Define genre centers (normalized)\n    @State var genreCenters: [String: CGPoint] = [\n        \"Drama\": CGPoint(x: 1.000, y: 0.500),\n        \"Horror\": CGPoint(x: 0.853, y: 0.853),\n        \"Sci-Fi\": CGPoint(x: 0.500, y: 1.000),\n        \"Fantasy\": CGPoint(x: 0.147, y: 0.853),\n        \"Romance\": CGPoint(x: 0.000, y: 0.500),\n        \"Documentary\": CGPoint(x: 0.147, y: 0.147),\n        \"Action\": CGPoint(x: 0.500, y: 0.000),\n        \"Comedy\": CGPoint(x: 0.853, y: 0.147)\n    ]\n    \n    @State var knobPosition: CGPoint = CGPoint(x: (UIScreen.main.bounds.width - 40) / 2, y: (UIScreen.main.bounds.width - 40) / 2)\n    \n    var body: some View {\n        ZStack {\n            \n            // Drag area background\n            RoundedRectangle(cornerRadius: 25)\n                .fill(.thinMaterial)\n                .frame(width: modelSize, height: modelSize)\n                .overlay(\n                    ZStack{\n                        RoundedRectangle(cornerRadius: 25)\n                            .stroke(.white.opacity(0.24))\n                    }\n                )\n                .shadow(radius: 8, x: 0, y: 4)\n            \n            // Dots\n            GeometryReader { geo in\n                let rows = Int(modelSize / spacing)\n                let cols = Int(modelSize / spacing)\n                \n                ZStack {\n                    ForEach(0..<rows, id: \\.self) { row in\n                        ForEach(0..<cols, id: \\.self) { col in\n                            Circle()\n                                .fill(Color.white.opacity(dotOpacity(row: row, col: col)))\n                                .frame(width: dotSize, height: dotSize)\n                                .position(self.dotPosition(row: row, col: col))\n                        }\n                    }\n                }\n                .background(Color.clear)\n                .padding(11)\n            }\n            \n            // Crosshare\n            Rectangle()\n                .fill(LinearGradient(colors: [.clear,.clear, .white.opacity(0.24),.clear, .clear], startPoint: .leading, endPoint: .trailing))\n                .frame(width: modelSize, height: 1)\n                \n            Rectangle()\n                .fill(LinearGradient(colors: [.clear,.clear, .white.opacity(0.24), .clear, .clear], startPoint: .top, endPoint: .bottom))\n                .frame(width: 1, height: modelSize)\n\n            // Y axis labels\n            VStack{\n                Text(\"Action\")\n                    .foregroundStyle(genreLabel == \"Action\" ? .primary : .secondary)\n                    .fontWeight(genreLabel == \"Action\" ? .bold : .regular)\n                    .scaleEffect(genreLabel == \"Action\" ? 1.1 : 1.0)\n                Spacer()\n                Text(\"Sci-Fi\")\n                    .foregroundStyle(genreLabel == \"Sci-Fi\" ? .primary : .secondary)\n                    .fontWeight(genreLabel == \"Sci-Fi\" ? .bold : .regular)\n                    .scaleEffect(genreLabel == \"Sci-Fi\" ? 1.1 : 1.0)\n            }\n            .padding()\n            .frame(width: modelSize, height: modelSize)\n            \n            // X axis labels\n            HStack{\n                Text(\"Romance\")\n                    .foregroundStyle(genreLabel == \"Romance\" ? .primary : .secondary)\n                    .fontWeight(genreLabel == \"Romance\" ? .bold : .regular)\n                    .scaleEffect(genreLabel == \"Romance\" ? 1.1 : 1.0)\n                Spacer()\n                Text(\"Drama\")\n                    .foregroundStyle(genreLabel == \"Drama\" ? .primary : .secondary)\n                    .fontWeight(genreLabel == \"Drama\" ? .bold : .regular)\n                    .scaleEffect(genreLabel == \"Drama\" ? 1.1 : 1.0)\n            }\n            .padding()\n            .frame(width: modelSize, height: modelSize)\n            \n            // Quadrant labels\n            Group {\n                Text(\"Documentary\").position(x: modelSize * 0.25, y: modelSize * 0.25)\n                    .foregroundStyle(genreLabel == \"Documentary\" ? .primary : .secondary)\n                    .fontWeight(genreLabel == \"Documentary\" ? .bold : .regular)\n                    .scaleEffect(genreLabel == \"Documentary\" ? 1.1 : 1.0)\n                Text(\"Comedy\").position(x: modelSize * 0.75, y: modelSize * 0.25)\n                    .foregroundStyle(genreLabel == \"Comedy\" ? .primary : .secondary)\n                    .fontWeight(genreLabel == \"Comedy\" ? .bold : .regular)\n                    .scaleEffect(genreLabel == \"Comedy\" ? 1.1 : 1.0)\n                Text(\"Fantasy\").position(x: modelSize * 0.25, y: modelSize * 0.75)\n                    .foregroundStyle(genreLabel == \"Fantasy\" ? .primary : .secondary)\n                    .fontWeight(genreLabel == \"Fantasy\" ? .bold : .regular)\n                    .scaleEffect(genreLabel == \"Fantasy\" ? 1.1 : 1.0)\n                Text(\"Horror\").position(x: modelSize * 0.75, y: modelSize * 0.75)\n                    .foregroundStyle(genreLabel == \"Horror\" ? .primary : .secondary)\n                    .fontWeight(genreLabel == \"Horror\" ? .bold : .regular)\n                    .scaleEffect(genreLabel == \"Horror\" ? 1.1 : 1.0)\n            }\n            \n            // Knob to drag around\n            Circle()\n                .fill(Color.white.gradient)\n                .stroke(.white.opacity(0.48), lineWidth:1)\n                .frame(width: 40, height: 40)\n                .popoverTip(getStartedTip)\n                .shadow(radius: 15)\n                .position(knobPosition)\n                .gesture(\n                    DragGesture()\n                        .onChanged { value in\n                            isDragging = true // Set isDragging to true when dragging starts\n                            getStartedTip.invalidate(reason: .actionPerformed)\n                            withAnimation(.easeOut(duration: 0.1)) {\n                                // Limit position within bounds\n                                knobPosition = CGPoint(\n                                    x: max(0, min(modelSize, value.location.x)),\n                                    y: max(0, min(modelSize, value.location.y))\n                                )\n                                calculateGenre()\n                                calculateGenreProximityScores()\n                            }\n                            \n                        }\n                        .onEnded { _ in\n                            withAnimation(.bouncy) {\n                                knobPosition = CGPoint(\n                                    x: modelSize / 2,\n                                    y: modelSize / 2\n                                )\n                            }\n                            // Delay setting isDragging to false until animation completes\n                            DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {\n                                withAnimation(.bouncy){\n                                    isDragging = false\n                                }\n                                \n                            }\n                            getMovieRecFromGroq()\n                        }\n                )\n            \n        }\n        .frame(width: modelSize, height: modelSize)\n        .font(.caption2)\n        .fontDesign(.monospaced)\n        .preferredColorScheme(.dark)\n    }\n    \n    // Initial grid positions with increased spacing\n    private func initialDotPosition(row: Int, col: Int) -> CGPoint {\n        CGPoint(x: CGFloat(col) * spacing, y: CGFloat(row) * spacing)\n    }\n    \n    private func dotPosition(row: Int, col: Int) -> CGPoint {\n        \n        guard isDragging else { // Check if dragging is active\n            return initialDotPosition(row: row, col: col)\n        }\n        \n        let fingerPosition = knobPosition\n        let dotPos = initialDotPosition(row: row, col: col)\n        let distance = hypot(dotPos.x  - fingerPosition.x + 10, dotPos.y - fingerPosition.y + 10)\n        \n        if distance < thresholdDistance {\n            // Calculate offset based on distance to create attraction\n            let offsetFactor = (thresholdDistance - distance) / thresholdDistance\n            let direction = CGPoint(x: (fingerPosition.x - dotPos.x) * offsetFactor,\n                                    y: (fingerPosition.y - dotPos.y) * offsetFactor)\n            return CGPoint(x: dotPos.x + direction.x, y: dotPos.y + direction.y)\n        } else {\n            // Outside of threshold, snap back to original position\n            return dotPos\n        }\n    }\n    \n    private func dotOpacity(row: Int, col: Int) -> Double {\n        \n        guard isDragging else { // Only change opacity if dragging\n            return 0.1\n        }\n        \n        let fingerPosition = knobPosition\n        let dotPos = initialDotPosition(row: row, col: col)\n        let distance = hypot(dotPos.x - fingerPosition.x + 10, dotPos.y - fingerPosition.y + 10)\n\n        // Calculate opacity based on proximity; closer dots are more opaque\n        let opacityFactor = max(0.1, min(1.0, (thresholdDistance - distance) / thresholdDistance))\n        return opacityFactor\n    }\n    \n    // Determine the closest genre based on knob position\n    private func calculateGenre() {\n\n        // Normalize knob position\n        let normalizedKnobPosition = CGPoint(x: knobPosition.x / modelSize, y: knobPosition.y / modelSize)\n        \n        // Find the genre with the minimum distance to the knob position\n        var closestGenre: String = \"Neutral\"\n        var minDistance: CGFloat = .greatestFiniteMagnitude\n        \n        for (genre, center) in genreCenters {\n            let distance = hypot(normalizedKnobPosition.x - center.x, normalizedKnobPosition.y - center.y)\n            if distance < minDistance {\n                minDistance = distance\n                closestGenre = genre\n            }\n        }\n        \n        // Update the genre label with the closest genre\n        withAnimation {\n            genreLabel = closestGenre\n        }\n    }\n    \n\n    // Calculate proximity scores for each emotion based on knob position\n    private func calculateGenreProximityScores() {\n        \n        // Calculate proximity scores\n        let normalizedKnobPosition = CGPoint(x: knobPosition.x / modelSize, y: knobPosition.y / modelSize)\n        var scores: [String: Double] = [:]\n        \n        for (genre, center) in genreCenters {\n            // Calculate inverse distance as proximity score (higher = closer)\n            let distance = hypot(normalizedKnobPosition.x - center.x, normalizedKnobPosition.y - center.y)\n            scores[genre] = max(0, 1 - distance) // Scale to 0-1 range\n        }\n    \n        withAnimation(.bouncy){\n            genreScores = scores\n        }\n\n    }\n    \n}\n\n#Preview {\n    GenreSelectorView(getMovieRecFromGroq: {}, genreLabel: .constant(\"\"))\n}\n"
  },
  {
    "path": "Demos/FilmFinder/FilmFinder/GetStartedTip.swift",
    "content": "//\n//  GetStartedTip.swift\n//  FilmFinder\n//\n//  Created by Todd Hamilton on 10/31/24.\n//\n\nimport SwiftUI\nimport TipKit\n\n// Tooltip for first time users\nstruct GetStartedTip: Tip {\n    var title: Text {\n        Text(\"Get movie recommendations\")\n    }\n    var message: Text? {\n        Text(\"Drag the circle to choose a genre.\")\n    }\n}\n"
  },
  {
    "path": "Demos/FilmFinder/FilmFinder/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict/>\n</plist>\n"
  },
  {
    "path": "Demos/FilmFinder/FilmFinder/Movie.swift",
    "content": "//\n//  Movie.swift\n//  FilmFinder\n//\n//  Created by Todd Hamilton on 10/29/24.\n//\n\nimport Foundation\n\nstruct Recommendation: Codable {\n    let title: String\n}\n\n// Define the structs to match the JSON structure\nstruct MovieResponse: Codable {\n    let page: Int\n    let results: [Movie]\n    let totalPages: Int\n    let totalResults: Int\n    \n    // Map JSON keys to Swift property names if they differ\n    enum CodingKeys: String, CodingKey {\n        case page, results\n        case totalPages = \"total_pages\"\n        case totalResults = \"total_results\"\n    }\n}\n\nstruct Movie: Codable {\n    let adult: Bool\n    let backdropPath: String?\n    let genreIds: [Int]\n    let id: Int\n    let originalLanguage: String\n    let originalTitle: String\n    let overview: String\n    let popularity: Double\n    let posterPath: String?\n    let releaseDate: String\n    let title: String\n    let video: Bool\n    let voteAverage: Double\n    let voteCount: Int\n    \n    enum CodingKeys: String, CodingKey {\n        case adult\n        case backdropPath = \"backdrop_path\"\n        case genreIds = \"genre_ids\"\n        case id\n        case originalLanguage = \"original_language\"\n        case originalTitle = \"original_title\"\n        case overview, popularity\n        case posterPath = \"poster_path\"\n        case releaseDate = \"release_date\"\n        case title, video\n        case voteAverage = \"vote_average\"\n        case voteCount = \"vote_count\"\n    }\n}\n"
  },
  {
    "path": "Demos/FilmFinder/FilmFinder/MovieDetailsView.swift",
    "content": "//\n//  MovieDetailsView.swift\n//  MovieMoods\n//\n//  Created by Todd Hamilton on 10/29/24.\n//\n\nimport SwiftUI\n\nstruct MovieDetailsView: View {\n    \n    @Binding var movieID: String\n    @Binding var movieBackdrop: String\n    @Binding var movieTitle: String\n    @Binding var movieReleaseDate: String\n    @Binding var movieOverview: String\n    @Binding var genreLabel: String\n    \n    @State var showPoster:Bool = false\n    @State var showTitle:Bool = false\n    @State var showRelease:Bool = false\n    @State var showOverview:Bool = false\n    @State var showCTA:Bool = false\n    \n    var body: some View {\n        VStack(spacing:24){\n            \n            \n            AsyncImage(\n                url: URL(string: \"https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/\\(movieBackdrop)\"),\n                content: { image in\n                    image\n                        .resizable()\n                        .scaledToFit()\n                        .frame(maxWidth:.infinity)\n                        .clipped()\n                        .cornerRadius(8)\n                        \n                },\n                placeholder: {\n                    Color.clear\n                }\n            )\n            .opacity(showPoster ? 1 : 0)\n\n            VStack(spacing:24){\n                \n                Text(movieTitle)\n                    .font(.title2)\n                    .fontWeight(.bold)\n                    .frame(maxWidth:.infinity, alignment: .leading)\n                    .opacity(showTitle ? 1 : 0)\n                \n                VStack(spacing:8){\n                    Text(\"Release date\")\n                        .frame(maxWidth:.infinity, alignment: .leading)\n                        .foregroundColor(.secondary)\n                        .textCase(.uppercase)\n                    Text(\"\\(movieReleaseDate)\")\n                        .frame(maxWidth:.infinity, alignment: .leading)\n                }\n                .font(.caption)\n                .opacity(showRelease ? 1 : 0)\n                \n                VStack(spacing:8){\n                    Text(\"Overview\")\n                        .frame(maxWidth:.infinity, alignment: .leading)\n                        .foregroundColor(.secondary)\n                        .textCase(.uppercase)\n                    Text(movieOverview)\n                        .frame(maxWidth:.infinity, alignment: .leading)\n                }\n                .font(.caption)\n                .opacity(showOverview ? 1 : 0)\n                \n            }\n            .fontDesign(.monospaced)\n            \n            Link(destination: URL(string: \"https://www.themoviedb.org/movie/\\(movieID)\")!){\n                Text(\"View on TMDB\")\n                    .foregroundColor(.black)\n                    .padding(6)\n                    .frame(maxWidth:.infinity)\n            }\n            .buttonStyle(.borderedProminent)\n            .tint(.white)\n            .fontDesign(.monospaced)\n            .fontWeight(.bold)\n            .opacity(showCTA ? 1 : 0)\n            \n            Spacer()\n        }\n        .padding(16)\n        .padding(.top, 12)\n        .preferredColorScheme(.dark)\n        .onAppear(){\n            withAnimation(.easeInOut.delay(0.2)){\n                showPoster.toggle()\n            }\n            withAnimation(.easeInOut.delay(0.25)){\n                showTitle.toggle()\n            }\n            withAnimation(.easeInOut.delay(0.3)){\n                showRelease.toggle()\n            }\n            withAnimation(.easeInOut.delay(0.35)){\n                showOverview.toggle()\n            }\n            withAnimation(.easeInOut.delay(0.4)){\n                showCTA.toggle()\n            }\n        }\n    }\n}\n\n#Preview {\n    MovieDetailsView(\n        movieID: .constant(\"23232\"),\n        movieBackdrop: .constant(\"p5ozvmdgsmbWe0H8Xk7Rc8SCwAB.jpg\"),\n        movieTitle: .constant(\"Inside Out 2\"),\n        movieReleaseDate: .constant(\"06/14/2024 (US)\"),\n        movieOverview: .constant(\"Teenager Riley's mind headquarters is undergoing a sudden demolition to make room for something entirely unexpected: new Emotions! Joy, Sadness, Anger, Fear and Disgust, who’ve long been running a successful operation by all accounts, aren’t sure how to feel when Anxiety shows up. And it looks like she’s not alone.\"),\n        genreLabel: .constant(\"Comedy\")\n    )\n}\n"
  },
  {
    "path": "Demos/FilmFinder/FilmFinder/Preview Content/Preview Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/FilmFinder/FilmFinder/Ripple.metal",
    "content": "//\n//  Ripple.metal\n//  FilmFinder\n//\n//  Created by Todd Hamilton on 6/21/24.\n//\n\n// Insert #include <metal_stdlib>\n#include <SwiftUI/SwiftUI.h>\nusing namespace metal;\n\n[[ stitchable ]]\nhalf4 Ripple(\n    float2 position,\n    SwiftUI::Layer layer,\n    float2 origin,\n    float time,\n    float amplitude,\n    float frequency,\n    float decay,\n    float speed\n) {\n    // The distance of the current pixel position from `origin`.\n    float distance = length(position - origin);\n    // The amount of time it takes for the ripple to arrive at the current pixel position.\n    float delay = distance / speed;\n\n    // Adjust for delay, clamp to 0.\n    time -= delay;\n    time = max(0.0, time);\n\n    // The ripple is a sine wave that Metal scales by an exponential decay\n    // function.\n    float rippleAmount = amplitude * sin(frequency * time) * exp(-decay * time);\n\n    // A vector of length `amplitude` that points away from position.\n    float2 n = normalize(position - origin);\n\n    // Scale `n` by the ripple amount at the current pixel position and add it\n    // to the current pixel position.\n    //\n    // This new position moves toward or away from `origin` based on the\n    // sign and magnitude of `rippleAmount`.\n    float2 newPosition = position + rippleAmount * n;\n\n    // Sample the layer at the new position.\n    half4 color = layer.sample(newPosition);\n\n    // Lighten or darken the color based on the ripple amount and its alpha\n    // component.\n    color.rgb += 0.3 * (rippleAmount / amplitude) * color.a;\n\n    return color;\n}\n\n\n"
  },
  {
    "path": "Demos/FilmFinder/FilmFinder/Ripple.swift",
    "content": "//\n//  Ripple.swift\n//  FilmFinder\n//\n//  Created by Todd Hamilton on 6/21/24.\n//\n\nimport SwiftUI\n\nstruct PushEffect<T: Equatable>: ViewModifier {\n    var trigger: T\n\n    func body(content: Content) -> some View {\n        content.keyframeAnimator(\n            initialValue: 1.0,\n            trigger: trigger\n        ) { view, value in\n            view.visualEffect { view, _ in\n                view.scaleEffect(value)\n            }\n        } keyframes: { _ in\n            SpringKeyframe(0.95, duration: 0.2, spring: .snappy)\n            SpringKeyframe(1.0, duration: 0.2, spring: .bouncy)\n        }\n    }\n}\n\n/// A modifer that performs a ripple effect to its content whenever its\n/// trigger value changes.\nstruct RippleEffect<T: Equatable>: ViewModifier {\n    var origin: CGPoint\n\n    var trigger: T\n\n    init(at origin: CGPoint, trigger: T) {\n        self.origin = origin\n        self.trigger = trigger\n    }\n\n    func body(content: Content) -> some View {\n        let origin = origin\n        let duration = duration\n\n        content.keyframeAnimator(\n            initialValue: 0,\n            trigger: trigger\n        ) { view, elapsedTime in\n            view.modifier(RippleModifier(\n                origin: origin,\n                elapsedTime: elapsedTime,\n                duration: duration\n            ))\n        } keyframes: { _ in\n            MoveKeyframe(0)\n            LinearKeyframe(duration, duration: duration)\n        }\n    }\n\n    var duration: TimeInterval { 3 }\n}\n\n/// A modifier that applies a ripple effect to its content.\nstruct RippleModifier: ViewModifier {\n    var origin: CGPoint\n\n    var elapsedTime: TimeInterval\n\n    var duration: TimeInterval\n\n    var amplitude: Double = 12\n    var frequency: Double = 15\n    var decay: Double = 8\n    var speed: Double = 1200\n\n    func body(content: Content) -> some View {\n        let shader = ShaderLibrary.Ripple(\n            .float2(origin),\n            .float(elapsedTime),\n\n            // Parameters\n            .float(amplitude),\n            .float(frequency),\n            .float(decay),\n            .float(speed)\n        )\n\n        let maxSampleOffset = maxSampleOffset\n        let elapsedTime = elapsedTime\n        let duration = duration\n\n        content.visualEffect { view, _ in\n            view.layerEffect(\n                shader,\n                maxSampleOffset: maxSampleOffset,\n                isEnabled: 0 < elapsedTime && elapsedTime < duration\n            )\n        }\n    }\n\n    var maxSampleOffset: CGSize {\n        CGSize(width: amplitude, height: amplitude)\n    }\n}\n\nextension View {\n    func onPressingChanged(_ action: @escaping (CGPoint?) -> Void) -> some View {\n        modifier(SpatialPressingGestureModifier(action: action))\n    }\n}\n\nstruct SpatialPressingGestureModifier: ViewModifier {\n    var onPressingChanged: (CGPoint?) -> Void\n\n    @State var currentLocation: CGPoint?\n\n    init(action: @escaping (CGPoint?) -> Void) {\n        self.onPressingChanged = action\n    }\n\n    func body(content: Content) -> some View {\n        let gesture = SpatialPressingGesture(location: $currentLocation)\n\n        content\n            .gesture(gesture)\n            .onChange(of: currentLocation, initial: false) { _, location in\n                onPressingChanged(location)\n            }\n    }\n}\n\nstruct SpatialPressingGesture: UIGestureRecognizerRepresentable {\n    final class Coordinator: NSObject, UIGestureRecognizerDelegate {\n        @objc\n        func gestureRecognizer(\n            _ gestureRecognizer: UIGestureRecognizer,\n            shouldRecognizeSimultaneouslyWith other: UIGestureRecognizer\n        ) -> Bool {\n            true\n        }\n    }\n\n    @Binding var location: CGPoint?\n\n    func makeCoordinator(converter: CoordinateSpaceConverter) -> Coordinator {\n        Coordinator()\n    }\n\n    func makeUIGestureRecognizer(context: Context) -> UILongPressGestureRecognizer {\n        let recognizer = UILongPressGestureRecognizer()\n        recognizer.minimumPressDuration = 0\n        recognizer.delegate = context.coordinator\n\n        return recognizer\n    }\n\n    func handleUIGestureRecognizerAction(\n        _ recognizer: UIGestureRecognizerType, context: Context) {\n            switch recognizer.state {\n                case .began:\n                    location = context.converter.localLocation\n                case .ended, .cancelled, .failed:\n                    location = nil\n                default:\n                    break\n            }\n        }\n    }\n"
  },
  {
    "path": "Demos/FilmFinder/FilmFinder.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 77;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t2CB7E6132CD2AC05004E3AFD /* AIProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 2CB7E6122CD2AC05004E3AFD /* AIProxy */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t2CB7E5F82CD2ABAA004E3AFD /* FilmFinder.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FilmFinder.app; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */\n\t\t2C658F572CD8797500300EDE /* Exceptions for \"FilmFinder\" folder in \"FilmFinder\" target */ = {\n\t\t\tisa = PBXFileSystemSynchronizedBuildFileExceptionSet;\n\t\t\tmembershipExceptions = (\n\t\t\t\tInfo.plist,\n\t\t\t);\n\t\t\ttarget = 2CB7E5F72CD2ABAA004E3AFD /* FilmFinder */;\n\t\t};\n/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */\n\n/* Begin PBXFileSystemSynchronizedRootGroup section */\n\t\t2CB7E5FA2CD2ABAA004E3AFD /* FilmFinder */ = {\n\t\t\tisa = PBXFileSystemSynchronizedRootGroup;\n\t\t\texceptions = (\n\t\t\t\t2C658F572CD8797500300EDE /* Exceptions for \"FilmFinder\" folder in \"FilmFinder\" target */,\n\t\t\t);\n\t\t\tpath = FilmFinder;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXFileSystemSynchronizedRootGroup section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t2CB7E5F52CD2ABAA004E3AFD /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2CB7E6132CD2AC05004E3AFD /* AIProxy in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t2CB7E5EF2CD2ABAA004E3AFD = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CB7E5FA2CD2ABAA004E3AFD /* FilmFinder */,\n\t\t\t\t2CB7E5F92CD2ABAA004E3AFD /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2CB7E5F92CD2ABAA004E3AFD /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2CB7E5F82CD2ABAA004E3AFD /* FilmFinder.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t2CB7E5F72CD2ABAA004E3AFD /* FilmFinder */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 2CB7E6062CD2ABAC004E3AFD /* Build configuration list for PBXNativeTarget \"FilmFinder\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t2CB7E5F42CD2ABAA004E3AFD /* Sources */,\n\t\t\t\t2CB7E5F52CD2ABAA004E3AFD /* Frameworks */,\n\t\t\t\t2CB7E5F62CD2ABAA004E3AFD /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tfileSystemSynchronizedGroups = (\n\t\t\t\t2CB7E5FA2CD2ABAA004E3AFD /* FilmFinder */,\n\t\t\t);\n\t\t\tname = FilmFinder;\n\t\t\tpackageProductDependencies = (\n\t\t\t\t2CB7E6122CD2AC05004E3AFD /* AIProxy */,\n\t\t\t);\n\t\t\tproductName = FilmFinder;\n\t\t\tproductReference = 2CB7E5F82CD2ABAA004E3AFD /* FilmFinder.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t2CB7E5F02CD2ABAA004E3AFD /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = 1;\n\t\t\t\tLastSwiftUpdateCheck = 1610;\n\t\t\t\tLastUpgradeCheck = 1610;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t2CB7E5F72CD2ABAA004E3AFD = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 16.1;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 2CB7E5F32CD2ABAA004E3AFD /* Build configuration list for PBXProject \"FilmFinder\" */;\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 2CB7E5EF2CD2ABAA004E3AFD;\n\t\t\tminimizedProjectReferenceProxies = 1;\n\t\t\tpackageReferences = (\n\t\t\t\t2CB7E6112CD2AC05004E3AFD /* XCRemoteSwiftPackageReference \"AIProxySwift\" */,\n\t\t\t);\n\t\t\tpreferredProjectObjectVersion = 77;\n\t\t\tproductRefGroup = 2CB7E5F92CD2ABAA004E3AFD /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t2CB7E5F72CD2ABAA004E3AFD /* FilmFinder */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t2CB7E5F62CD2ABAA004E3AFD /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t2CB7E5F42CD2ABAA004E3AFD /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t2CB7E6042CD2ABAC004E3AFD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 18.1;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"DEBUG $(inherited)\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2CB7E6052CD2ABAC004E3AFD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 18.1;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t2CB7E6072CD2ABAC004E3AFD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"FilmFinder/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 9557YJ9D37;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_FILE = FilmFinder/Info.plist;\n\t\t\t\tINFOPLIST_KEY_CFBundleDisplayName = \"Film Finder\";\n\t\t\t\tINFOPLIST_KEY_LSApplicationCategoryType = \"public.app-category.entertainment\";\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.1;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.HamiltonZell.FilmFinder;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSUPPORTED_PLATFORMS = \"iphoneos iphonesimulator\";\n\t\t\t\tSUPPORTS_MACCATALYST = NO;\n\t\t\t\tSUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;\n\t\t\t\tSUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 1;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2CB7E6082CD2ABAC004E3AFD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"FilmFinder/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 9557YJ9D37;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_FILE = FilmFinder/Info.plist;\n\t\t\t\tINFOPLIST_KEY_CFBundleDisplayName = \"Film Finder\";\n\t\t\t\tINFOPLIST_KEY_LSApplicationCategoryType = \"public.app-category.entertainment\";\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.1;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.HamiltonZell.FilmFinder;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSUPPORTED_PLATFORMS = \"iphoneos iphonesimulator\";\n\t\t\t\tSUPPORTS_MACCATALYST = NO;\n\t\t\t\tSUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;\n\t\t\t\tSUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 1;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t2CB7E5F32CD2ABAA004E3AFD /* Build configuration list for PBXProject \"FilmFinder\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2CB7E6042CD2ABAC004E3AFD /* Debug */,\n\t\t\t\t2CB7E6052CD2ABAC004E3AFD /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t2CB7E6062CD2ABAC004E3AFD /* Build configuration list for PBXNativeTarget \"FilmFinder\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2CB7E6072CD2ABAC004E3AFD /* Debug */,\n\t\t\t\t2CB7E6082CD2ABAC004E3AFD /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCRemoteSwiftPackageReference section */\n\t\t2CB7E6112CD2AC05004E3AFD /* XCRemoteSwiftPackageReference \"AIProxySwift\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/lzell/AIProxySwift\";\n\t\t\trequirement = {\n\t\t\t\tbranch = main;\n\t\t\t\tkind = branch;\n\t\t\t};\n\t\t};\n/* End XCRemoteSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */\n\t\t2CB7E6122CD2AC05004E3AFD /* AIProxy */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 2CB7E6112CD2AC05004E3AFD /* XCRemoteSwiftPackageReference \"AIProxySwift\" */;\n\t\t\tproductName = AIProxy;\n\t\t};\n/* End XCSwiftPackageProductDependency section */\n\t};\n\trootObject = 2CB7E5F02CD2ABAA004E3AFD /* Project object */;\n}\n"
  },
  {
    "path": "Demos/PuLIDDemo/PuLIDDemo/AppConstants.swift",
    "content": "//\n//  AppConstants.swift\n//  PuLIDDemo\n//\n//  Created by Todd Hamilton on 9/28/24.\n//\n\nimport AIProxy\n\n#error(\n    \"\"\"\n    Uncomment one of the methods below. To build and run on device you must follow the AIProxy integration guide.\n    Please see https://www.aiproxy.pro/docs/integration-guide.html\")\n    \"\"\"\n)\n\n/* Uncomment for BYOK use cases */\nlet replicateService = AIProxy.replicateDirectService(\n    unprotectedAPIKey: \"your-replicate-key\"\n)\n\n/* Uncomment for all other production use cases */\n//let replicateService = AIProxy.replicateService(\n//    partialKey: \"partial-key-from-your-developer-dashboard\",\n//    serviceURL: \"service-url-from-your-developer-dashboard\"\n//)\n"
  },
  {
    "path": "Demos/PuLIDDemo/PuLIDDemo/Assets.xcassets/AccentColor.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/PuLIDDemo/PuLIDDemo/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ],\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"tinted\"\n        }\n      ],\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/PuLIDDemo/PuLIDDemo/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/PuLIDDemo/PuLIDDemo/Assets.xcassets/pulid.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"pulid.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/PuLIDDemo/PuLIDDemo/ContentView.swift",
    "content": "//\n//  ContentView.swift\n//  PuLIDDemo\n//\n//  Created by Todd Hamilton on 9/26/24.\n//\n\nimport SwiftUI\nimport AIProxy\nimport PhotosUI\n\nstruct ContentView: View {\n\n    @State var isAnimating = false\n    @State private var selectedPhoto: PhotosPickerItem?\n    @State private var image: UIImage? = UIImage(named: \"pulid\")\n    @State var prompt = \"\"\n    @State private var isLoading = false\n    @State var counter: Int = 0\n    @State var origin: CGPoint = .zero\n    @FocusState var isFocused : Bool\n    \n    var body: some View {\n        ZStack {\n            \n            if #available(iOS 18.0, *) {\n                MeshGradient(width: 2, height: 2, points: [\n                    [0, 0], [1, 0], [0, 1], [1, 1]\n                ], colors: [.blue, .teal, .cyan, .blue])\n                .ignoresSafeArea()\n            } else {\n                // Fallback on earlier versions\n                Color.purple\n            }\n            \n            LinearGradient(gradient: Gradient(colors: [.white.opacity(0), .black]), startPoint: .top, endPoint: .bottom)\n                .ignoresSafeArea()\n                    \n            VStack{\n                \n                ZStack(alignment: .bottom){\n\n                    if let image = image {\n                        Image(uiImage: image)\n                            .resizable()\n                            .scaledToFill()\n                            .frame(height:400)\n                            .overlay(\n                                RoundedRectangle(cornerRadius: 16)\n                                    .stroke(\n                                        LinearGradient(\n                                            gradient: Gradient(colors: [.white.opacity(0.75), .white.opacity(0.25), .white.opacity(0.25), .white.opacity(0.15), .white.opacity(0.15)]),\n                                            startPoint: .topLeading,\n                                            endPoint: .bottomTrailing\n                                        ),\n                                        lineWidth: 2\n                                    )\n                                    .blendMode(.overlay)\n                            )\n                            .cornerRadius(16)\n                            .modifier(RippleEffect(at: origin, trigger: counter))\n                            .shadow(color:.black.opacity(0.14),radius: 24)\n                            .shadow(radius: 25)\n                        \n\n                        PhotosPicker(selection: $selectedPhoto, matching: .images){\n                            Image(systemName: \"photo.circle.fill\")\n                        }\n                        .foregroundStyle(.regularMaterial)\n                        .buttonBorderShape(.circle)\n                        .padding()\n                        .font(.largeTitle)\n                        .textCase(.uppercase)\n\n                        if isLoading{\n                            ProgressView(){\n                                Text(\"Generating\")\n                                    .foregroundStyle(.white)\n                                    .font(.system(size: 12, weight:.semibold, design: .monospaced))\n                            }\n                            .tint(.white)\n                            .frame(maxWidth: .infinity, maxHeight: 400)\n                            .background(.black.opacity(0.5))\n                            .cornerRadius(16)\n                        }\n                    }\n                }\n                .padding()\n                .task(id: selectedPhoto) {\n                    if let data = try? await selectedPhoto?.loadTransferable(type: Data.self),\n                       let uiImage = UIImage(data: data) {\n                        image = uiImage\n                    }\n                }\n                \n                VStack(spacing:12){\n                    \n                    Text(\"Type a prompt to generate a new image.\")\n                        .font(.caption)\n                        .fontWeight(.medium)\n                        .textCase(.uppercase)\n                        .foregroundStyle(.white)\n                        .fontDesign(.monospaced)\n                    \n                    ZStack{\n                        TextField(\"Prompt\", text: $prompt)\n                            .focused($isFocused)\n                            .submitLabel(.done)\n                            .onSubmit {\n                                isFocused = false\n                                Task{ try await generateImage() }\n                            }\n                    }\n                    .padding(.vertical)\n                    .padding(.horizontal, 12)\n                    .fontDesign(.monospaced)\n                    .background(.white)\n                    .clipShape(RoundedRectangle(cornerRadius: 8))\n                    .font(.system(size: 14))\n                    .shadow(radius: 24)\n                    \n                    HStack{\n                        Button(\"Generate\"){\n                            isFocused = false\n                            Task{ try await generateImage() }\n                        }\n                        .font(.system(size: 16, weight: .semibold, design: .monospaced))\n                        .textCase(.uppercase)\n                        .controlSize(.large)\n                        .padding(8)\n                        .buttonStyle(.borderedProminent)\n                        .tint(.teal)\n                        .disabled(isLoading ? true : false)\n                    }\n                    \n                }\n                .padding(16)\n                \n                Spacer()\n            }\n        }\n        .preferredColorScheme(.light)\n    }\n    \n    private func generateImage() async throws {\n        \n        withAnimation(.default.delay(0.5)){ isLoading = true }\n        \n        defer {\n            withAnimation(){ isLoading = false }\n        }\n        \n        guard let imageURL = AIProxy.encodeImageAsURL(image: image!, compressionQuality: 0.8) else {\n            print(\"Could not convert image to a local data URI\")\n            return\n        }\n\n        do {\n            let input = ReplicateFluxPulidInputSchema(\n                mainFaceImage: imageURL,\n                prompt: prompt,\n                numOutputs: 1,\n                startStep: 4\n            )\n            let output = try await replicateService.createFluxPulidImage(\n                input: input\n            )\n            print(\"Done creating Flux-PuLID image: \", output)\n            \n            if let url = output.first?.absoluteString {\n                image = await loadImage(from: url)\n            }\n            \n            counter += 1\n            \n        }  catch AIProxyError.unsuccessfulRequest(let statusCode, let responseBody) {\n            print(\"Received non-200 status code: \\(statusCode) with response body: \\(responseBody)\")\n        } catch {\n            print(\"Could not create Flux-Pulid images: \\(error.localizedDescription)\")\n        }\n       \n    }\n    \n    // Function to load an image from a URL\n    private func loadImage(from url: String) async -> UIImage? {\n        guard let url = URL(string: url) else { return nil }\n        do {\n            let (data, _) = try await URLSession.shared.data(from: url)\n            return UIImage(data: data)\n        } catch {\n            print(\"Failed to load image from URL: \\(error.localizedDescription)\")\n            return nil\n        }\n    }\n    \n}\n\n#Preview {\n    ContentView()\n}\n"
  },
  {
    "path": "Demos/PuLIDDemo/PuLIDDemo/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict/>\n</plist>\n"
  },
  {
    "path": "Demos/PuLIDDemo/PuLIDDemo/Preview Content/Preview Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/PuLIDDemo/PuLIDDemo/PuLIDDemoApp.swift",
    "content": "//\n//  PuLIDDemoApp.swift\n//  PuLIDDemo\n//\n//  Created by Todd Hamilton on 9/26/24.\n//\n\nimport SwiftUI\n\n@main\nstruct PuLIDDemoApp: App {\n    var body: some Scene {\n        WindowGroup {\n            ContentView()\n        }\n    }\n}\n"
  },
  {
    "path": "Demos/PuLIDDemo/PuLIDDemo/Ripple.metal",
    "content": "//\n//  Ripple.metal\n//  AIColorPalette\n//\n//  Created by Todd Hamilton on 6/21/24.\n//\n\n// Insert #include <metal_stdlib>\n#include <SwiftUI/SwiftUI.h>\nusing namespace metal;\n\n[[ stitchable ]]\nhalf4 Ripple(\n    float2 position,\n    SwiftUI::Layer layer,\n    float2 origin,\n    float time,\n    float amplitude,\n    float frequency,\n    float decay,\n    float speed\n) {\n    // The distance of the current pixel position from `origin`.\n    float distance = length(position - origin);\n    // The amount of time it takes for the ripple to arrive at the current pixel position.\n    float delay = distance / speed;\n\n    // Adjust for delay, clamp to 0.\n    time -= delay;\n    time = max(0.0, time);\n\n    // The ripple is a sine wave that Metal scales by an exponential decay\n    // function.\n    float rippleAmount = amplitude * sin(frequency * time) * exp(-decay * time);\n\n    // A vector of length `amplitude` that points away from position.\n    float2 n = normalize(position - origin);\n\n    // Scale `n` by the ripple amount at the current pixel position and add it\n    // to the current pixel position.\n    //\n    // This new position moves toward or away from `origin` based on the\n    // sign and magnitude of `rippleAmount`.\n    float2 newPosition = position + rippleAmount * n;\n\n    // Sample the layer at the new position.\n    half4 color = layer.sample(newPosition);\n\n    // Lighten or darken the color based on the ripple amount and its alpha\n    // component.\n    color.rgb += 0.3 * (rippleAmount / amplitude) * color.a;\n\n    return color;\n}\n\n\n"
  },
  {
    "path": "Demos/PuLIDDemo/PuLIDDemo/Ripple.swift",
    "content": "//\n//  Ripple.swift\n//  AIColorPalette\n//\n//  Created by Todd Hamilton on 6/21/24.\n//\n\nimport SwiftUI\n\nstruct PushEffect<T: Equatable>: ViewModifier {\n    var trigger: T\n\n    func body(content: Content) -> some View {\n        content.keyframeAnimator(\n            initialValue: 1.0,\n            trigger: trigger\n        ) { view, value in\n            view.visualEffect { view, _ in\n                view.scaleEffect(value)\n            }\n        } keyframes: { _ in\n            SpringKeyframe(0.95, duration: 0.2, spring: .snappy)\n            SpringKeyframe(1.0, duration: 0.2, spring: .bouncy)\n        }\n    }\n}\n\n/// A modifer that performs a ripple effect to its content whenever its\n/// trigger value changes.\nstruct RippleEffect<T: Equatable>: ViewModifier {\n    var origin: CGPoint\n\n    var trigger: T\n\n    init(at origin: CGPoint, trigger: T) {\n        self.origin = origin\n        self.trigger = trigger\n    }\n\n    func body(content: Content) -> some View {\n        let origin = origin\n        let duration = duration\n\n        content.keyframeAnimator(\n            initialValue: 0,\n            trigger: trigger\n        ) { view, elapsedTime in\n            view.modifier(RippleModifier(\n                origin: origin,\n                elapsedTime: elapsedTime,\n                duration: duration\n            ))\n        } keyframes: { _ in\n            MoveKeyframe(0)\n            LinearKeyframe(duration, duration: duration)\n        }\n    }\n\n    var duration: TimeInterval { 3 }\n}\n\n/// A modifier that applies a ripple effect to its content.\nstruct RippleModifier: ViewModifier {\n    var origin: CGPoint\n\n    var elapsedTime: TimeInterval\n\n    var duration: TimeInterval\n\n    var amplitude: Double = 12\n    var frequency: Double = 15\n    var decay: Double = 8\n    var speed: Double = 1200\n\n    func body(content: Content) -> some View {\n        let shader = ShaderLibrary.Ripple(\n            .float2(origin),\n            .float(elapsedTime),\n\n            // Parameters\n            .float(amplitude),\n            .float(frequency),\n            .float(decay),\n            .float(speed)\n        )\n\n        let maxSampleOffset = maxSampleOffset\n        let elapsedTime = elapsedTime\n        let duration = duration\n\n        content.visualEffect { view, _ in\n            view.layerEffect(\n                shader,\n                maxSampleOffset: maxSampleOffset,\n                isEnabled: 0 < elapsedTime && elapsedTime < duration\n            )\n        }\n    }\n\n    var maxSampleOffset: CGSize {\n        CGSize(width: amplitude, height: amplitude)\n    }\n}\n\nextension View {\n    func onPressingChanged(_ action: @escaping (CGPoint?) -> Void) -> some View {\n        modifier(SpatialPressingGestureModifier(action: action))\n    }\n}\n\nstruct SpatialPressingGestureModifier: ViewModifier {\n    var onPressingChanged: (CGPoint?) -> Void\n\n    @State var currentLocation: CGPoint?\n\n    init(action: @escaping (CGPoint?) -> Void) {\n        self.onPressingChanged = action\n    }\n\n    func body(content: Content) -> some View {\n        let gesture = SpatialPressingGesture(location: $currentLocation)\n\n        content\n            .gesture(gesture)\n            .onChange(of: currentLocation, initial: false) { _, location in\n                onPressingChanged(location)\n            }\n    }\n}\n\nstruct SpatialPressingGesture: UIGestureRecognizerRepresentable {\n    final class Coordinator: NSObject, UIGestureRecognizerDelegate {\n        @objc\n        func gestureRecognizer(\n            _ gestureRecognizer: UIGestureRecognizer,\n            shouldRecognizeSimultaneouslyWith other: UIGestureRecognizer\n        ) -> Bool {\n            true\n        }\n    }\n\n    @Binding var location: CGPoint?\n\n    func makeCoordinator(converter: CoordinateSpaceConverter) -> Coordinator {\n        Coordinator()\n    }\n\n    func makeUIGestureRecognizer(context: Context) -> UILongPressGestureRecognizer {\n        let recognizer = UILongPressGestureRecognizer()\n        recognizer.minimumPressDuration = 0\n        recognizer.delegate = context.coordinator\n\n        return recognizer\n    }\n\n    func handleUIGestureRecognizerAction(\n        _ recognizer: UIGestureRecognizerType, context: Context) {\n            switch recognizer.state {\n                case .began:\n                    location = context.converter.localLocation\n                case .ended, .cancelled, .failed:\n                    location = nil\n                default:\n                    break\n            }\n        }\n    }\n"
  },
  {
    "path": "Demos/PuLIDDemo/PuLIDDemo.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 77;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t2C4C32D22CA5A8EA001B3CDF /* AIProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 2C4C32D12CA5A8EA001B3CDF /* AIProxy */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t2C4C32BF2CA5A8DD001B3CDF /* PuLIDDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PuLIDDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */\n\t\t2CEFF9DF2CA85CFB001959B4 /* Exceptions for \"PuLIDDemo\" folder in \"PuLIDDemo\" target */ = {\n\t\t\tisa = PBXFileSystemSynchronizedBuildFileExceptionSet;\n\t\t\tmembershipExceptions = (\n\t\t\t\tInfo.plist,\n\t\t\t);\n\t\t\ttarget = 2C4C32BE2CA5A8DD001B3CDF /* PuLIDDemo */;\n\t\t};\n/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */\n\n/* Begin PBXFileSystemSynchronizedRootGroup section */\n\t\t2C4C32C12CA5A8DD001B3CDF /* PuLIDDemo */ = {\n\t\t\tisa = PBXFileSystemSynchronizedRootGroup;\n\t\t\texceptions = (\n\t\t\t\t2CEFF9DF2CA85CFB001959B4 /* Exceptions for \"PuLIDDemo\" folder in \"PuLIDDemo\" target */,\n\t\t\t);\n\t\t\tpath = PuLIDDemo;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXFileSystemSynchronizedRootGroup section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t2C4C32BC2CA5A8DD001B3CDF /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2C4C32D22CA5A8EA001B3CDF /* AIProxy in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t2C4C32B62CA5A8DD001B3CDF = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2C4C32C12CA5A8DD001B3CDF /* PuLIDDemo */,\n\t\t\t\t2C4C32C02CA5A8DD001B3CDF /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2C4C32C02CA5A8DD001B3CDF /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2C4C32BF2CA5A8DD001B3CDF /* PuLIDDemo.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t2C4C32BE2CA5A8DD001B3CDF /* PuLIDDemo */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 2C4C32CD2CA5A8DE001B3CDF /* Build configuration list for PBXNativeTarget \"PuLIDDemo\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t2C4C32BB2CA5A8DD001B3CDF /* Sources */,\n\t\t\t\t2C4C32BC2CA5A8DD001B3CDF /* Frameworks */,\n\t\t\t\t2C4C32BD2CA5A8DD001B3CDF /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tfileSystemSynchronizedGroups = (\n\t\t\t\t2C4C32C12CA5A8DD001B3CDF /* PuLIDDemo */,\n\t\t\t);\n\t\t\tname = PuLIDDemo;\n\t\t\tpackageProductDependencies = (\n\t\t\t\t2C4C32D12CA5A8EA001B3CDF /* AIProxy */,\n\t\t\t);\n\t\t\tproductName = PuLIDDemo;\n\t\t\tproductReference = 2C4C32BF2CA5A8DD001B3CDF /* PuLIDDemo.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t2C4C32B72CA5A8DD001B3CDF /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = 1;\n\t\t\t\tLastSwiftUpdateCheck = 1600;\n\t\t\t\tLastUpgradeCheck = 1600;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t2C4C32BE2CA5A8DD001B3CDF = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 16.0;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 2C4C32BA2CA5A8DD001B3CDF /* Build configuration list for PBXProject \"PuLIDDemo\" */;\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 2C4C32B62CA5A8DD001B3CDF;\n\t\t\tminimizedProjectReferenceProxies = 1;\n\t\t\tpackageReferences = (\n\t\t\t\t2C4C32D02CA5A8EA001B3CDF /* XCRemoteSwiftPackageReference \"AIProxySwift\" */,\n\t\t\t);\n\t\t\tpreferredProjectObjectVersion = 77;\n\t\t\tproductRefGroup = 2C4C32C02CA5A8DD001B3CDF /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t2C4C32BE2CA5A8DD001B3CDF /* PuLIDDemo */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t2C4C32BD2CA5A8DD001B3CDF /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t2C4C32BB2CA5A8DD001B3CDF /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t2C4C32CB2CA5A8DE001B3CDF /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 18.0;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"DEBUG $(inherited)\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2C4C32CC2CA5A8DE001B3CDF /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 18.0;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t2C4C32CE2CA5A8DE001B3CDF /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"PuLIDDemo/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 553LMX46SJ;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_FILE = PuLIDDemo/Info.plist;\n\t\t\t\tINFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = \"App needs permission to save photos.\";\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 18.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.toddham.PuLIDDemo;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2C4C32CF2CA5A8DE001B3CDF /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"PuLIDDemo/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 553LMX46SJ;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_FILE = PuLIDDemo/Info.plist;\n\t\t\t\tINFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = \"App needs permission to save photos.\";\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 18.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.toddham.PuLIDDemo;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t2C4C32BA2CA5A8DD001B3CDF /* Build configuration list for PBXProject \"PuLIDDemo\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2C4C32CB2CA5A8DE001B3CDF /* Debug */,\n\t\t\t\t2C4C32CC2CA5A8DE001B3CDF /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t2C4C32CD2CA5A8DE001B3CDF /* Build configuration list for PBXNativeTarget \"PuLIDDemo\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2C4C32CE2CA5A8DE001B3CDF /* Debug */,\n\t\t\t\t2C4C32CF2CA5A8DE001B3CDF /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCRemoteSwiftPackageReference section */\n\t\t2C4C32D02CA5A8EA001B3CDF /* XCRemoteSwiftPackageReference \"AIProxySwift\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/lzell/AIProxySwift\";\n\t\t\trequirement = {\n\t\t\t\tbranch = main;\n\t\t\t\tkind = branch;\n\t\t\t};\n\t\t};\n/* End XCRemoteSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */\n\t\t2C4C32D12CA5A8EA001B3CDF /* AIProxy */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 2C4C32D02CA5A8EA001B3CDF /* XCRemoteSwiftPackageReference \"AIProxySwift\" */;\n\t\t\tproductName = AIProxy;\n\t\t};\n/* End XCSwiftPackageProductDependency section */\n\t};\n\trootObject = 2C4C32B72CA5A8DD001B3CDF /* Project object */;\n}\n"
  },
  {
    "path": "Demos/Stickers/Stickers/AppConstants.swift",
    "content": "//\n//  AppConstants.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport AIProxy\n\nenum AppConstants {\n    #error(\n        \"\"\"\n        Uncomment one of the methods below. To build and run on device you must follow the AIProxy integration guide.\n        Please see https://www.aiproxy.pro/docs/integration-guide.html\")\n        \"\"\"\n    )\n    \n    /* Uncomment for BYOK use cases */\n    static let openAIService = AIProxy.openAIDirectService(\n        unprotectedAPIKey: \"your-openai-key\"\n    )\n\n    /* Uncomment for all other production use cases */\n//    let openAIService = AIProxy.openAIService(\n//        partialKey: \"partial-key-from-your-developer-dashboard\",\n//        serviceURL: \"service-url-from-your-developer-dashboard\"\n//    )\n\n}\n"
  },
  {
    "path": "Demos/Stickers/Stickers/AppLogger.swift",
    "content": "//\n//  AppLogger.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport OSLog\n\n/// Log levels available:\n///\n///     AppLogger.debug\n///     AppLogger.info\n///     AppLogger.warning\n///     AppLogger.error\n///     AppLogger.critical\n///\n/// Flip on metadata logging in Xcode's console to show which source line the log occurred from.\n///\n/// See my reddit post for a video instructions:\n/// https://www.reddit.com/r/SwiftUI/comments/15lsdtk/how_to_use_the_oslog_logger/\nlet AppLogger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"UnknownApp\",\n                       category: \"AIProxyBootstrapStickers\")\n"
  },
  {
    "path": "Demos/Stickers/Stickers/Assets.xcassets/AccentColor.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/Stickers/Stickers/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"sticker.png\",\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/Stickers/Stickers/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/Stickers/Stickers/ButtonStyles.swift",
    "content": "//\n//  ButtonStyles.swift\n//  AIProxyBootstrap\n//\n//  Created by Todd Hamilton\n//\n\nimport SwiftUI\n\nstruct ButtonStyles: View {\n    var body: some View {\n        \n        ZStack{\n            Color(.systemGroupedBackground)\n                .ignoresSafeArea()\n            \n            VStack(spacing:48){\n                \n                Button{\n                    /// do something\n                }label:{\n                    HStack(spacing:6){\n                        Image(systemName: \"play.circle.fill\")\n                            .font(.system(size: 15, weight:.semibold, design: .rounded))\n                        Text(\"10s\")\n                            .font(.system(size: 11, weight: .regular, design: .monospaced))\n                            .fontDesign(.monospaced)\n                    }\n                }\n                .buttonStyle(TranscriptionButtonStyle())\n\n                Button(){\n                    /// do something\n                } label:{\n                    Label(\"Chunky Button\", systemImage: \"sparkles\")\n                }\n                .buttonStyle(ChunkyButtonStyle(offsetSize: 10.0))\n\n                Button{\n                    /// do something\n                } label: {\n                    ZStack{\n                        RoundedRectangle(cornerRadius: 45, style:.continuous)\n                            .fill(.red.gradient)\n                            .frame(width:85, height:85)\n                        Image(systemName: \"waveform\")\n                            .font(.title)\n                            .foregroundColor(.white)\n                    }\n                }\n                .buttonStyle(RecordButton())\n                \n                Button(){\n                    /// do something\n                }label:{\n                    Image(systemName: \"arrow.forward\")\n                        .font(.system(size: 17, weight: .bold))\n                }\n                .buttonStyle(TranslateButton())\n                \n            }\n            .padding()\n        }\n        \n    }\n}\n\nstruct ChunkyButtonStyle: ButtonStyle {\n\n    var offsetSize = 10.0\n\n    func makeBody(configuration: Configuration) -> some View {\n        configuration.label\n            .font(.system(size: 24, weight: .bold, design: .rounded))\n            .foregroundColor(.black)\n            .padding()\n            .offset(y: configuration.isPressed ? offsetSize-2 : 0)\n            .background(\n                GeometryReader{ geo in\n                    RoundedRectangle(cornerRadius: 17)\n                        .strokeBorder(Color.black, lineWidth: 4)\n                        .background(\n                            RoundedRectangle(cornerRadius: 17)\n                                .fill(.white)\n                        )\n                        .offset(y:offsetSize)\n\n                        .overlay(\n                            RoundedRectangle(cornerRadius: 17)\n                                .fill(.white)\n                                .strokeBorder(Color.black, lineWidth: 4)\n                                .background(RoundedRectangle(cornerRadius: 17).fill(Color.white))\n                                .offset(y: configuration.isPressed ? offsetSize : 0)\n                        )\n                }\n            )\n    }\n}\n\nstruct RecordButton: ButtonStyle {\n    func makeBody(configuration: Configuration) -> some View {\n        configuration.label\n            .frame(maxWidth:80, maxHeight: 80)\n            .shadow(color:.black.opacity(0.28), radius: 10, y:8)\n            .scaleEffect(configuration.isPressed ? 0.9 : 1, anchor: .center)\n            .animation(.easeOut(duration: 0.2), value: configuration.isPressed)\n            .padding(.bottom, 40)\n            \n    }\n}\n\nstruct TranslateButton: ButtonStyle {\n    func makeBody(configuration: Configuration) -> some View {\n        configuration.label\n            .foregroundColor(.white)\n            .frame(width:56, height:56)\n            .background(\n                Circle()\n                    .fill(.teal.gradient)\n            )\n            .brightness(configuration.isPressed ? -0.1 : 0.0)\n            .scaleEffect(configuration.isPressed ? 0.9 : 1, anchor: .center)\n            .animation(.easeOut(duration: 0.2), value: configuration.isPressed)\n    }\n}\n\nstruct TranscriptionButtonStyle: ButtonStyle {\n\n    func makeBody(configuration: Configuration) -> some View {\n        configuration.label\n            .foregroundColor(.secondary)\n            .padding(.leading, 4)\n            .padding(.trailing, 8)\n            .padding(.vertical, 4)\n            .background(\n                Capsule().fill(.secondary.opacity(configuration.isPressed ? 0.28 : 0.14))\n            )\n            .scaleEffect(configuration.isPressed ? 0.9 : 1.0)\n    }\n}\n\n#Preview {\n    ButtonStyles()\n}\n"
  },
  {
    "path": "Demos/Stickers/Stickers/Preview Content/Preview Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/Stickers/Stickers/StickerDataLoader.swift",
    "content": "//\n//  StickerDataLoader.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport Vision\nimport UIKit\nimport AIProxy\n\nfinal actor StickerDataLoader {\n    /// Creates a sticker from a given `prompt` using OpenAI's APIs\n    /// On simulator, the sticker has an opaque background because the Vision framework is not available.\n    /// On device, the sticker has a transparent background\n    ///\n    /// - Parameter prompt: The user-entered prompt\n    /// - Returns: A sticker as a UIImage if we were able to get one from OpenAI, or nil otherwise\n    func create(fromPrompt prompt: String) async throws -> UIImage? {\n        let requestBody = OpenAICreateImageRequestBody(\n            prompt: \"cute design of a \" + prompt + \" kawaii sticker. nothing in the bg. white bg.\",\n            model: \"dall-e-3\"\n        )\n        let response = try await AppConstants.openAIService.createImageRequest(body: requestBody)\n        print(response.data.first?.url ?? \"\")\n        \n        guard let url = response.data.first?.url, let data = try? Data(contentsOf: url) else {\n            AppLogger.error(\"OpenAI returned a sticker imageURL that we could not fetch\")\n            return nil\n        }\n\n        guard let img = UIImage(data: data) else {\n            AppLogger.error(\"Could not create a UIImage from the imageURL provided by OpenAI\")\n            return nil\n        }\n        return img.extractForegroundWithVision() ?? img\n    }\n}\n\n\nprivate extension UIImage {\n\n    convenience init?(pixelBuffer: CVPixelBuffer) {\n        let ciImage = CIImage(cvPixelBuffer: pixelBuffer)\n        let context = CIContext(options: nil)\n        guard let cgImage = context.createCGImage(ciImage, from: ciImage.extent) else {\n            return nil\n        }\n        self.init(cgImage: cgImage)\n    }\n\n    func extractForegroundWithVision() -> UIImage? {\n        guard let cgImage = self.cgImage else { return nil }\n        let request = VNGenerateForegroundInstanceMaskRequest()\n        let handler = VNImageRequestHandler(cgImage: cgImage)\n        do {\n            try handler.perform([request])\n            guard let result = request.results?.first else { return nil }\n\n            let foregroundPixelBuffer = try result.generateMaskedImage(\n                ofInstances: result.allInstances,\n                from: handler,\n                croppedToInstancesExtent: false\n            )\n\n            if let foregroundImage = UIImage(pixelBuffer: foregroundPixelBuffer) {\n                return foregroundImage\n            }\n        } catch {\n            AppLogger.info(\"Could not use Vision to cut the sticker out. Perhaps you are running on simulator?\")\n        }\n        return nil\n    }\n}\n"
  },
  {
    "path": "Demos/Stickers/Stickers/StickerImageView.swift",
    "content": "//\n//  StickerImageView.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport SwiftUI\n\n/// Holds a sticker image.\n/// The sticker animates into view with a scale effect, and then floats in the Y-axis.\nstruct StickerImageView: View {\n\n    /// The sticker as UIImage\n    let uiImage: UIImage\n\n    @State private var floating = false\n    @State private var showSticker = false\n    private let floatingAnimation = Animation.easeInOut(duration: 2.0).repeatForever(autoreverses: true)\n\n    var body: some View {\n        Image(uiImage: uiImage)\n            .resizable()\n            .scaledToFit()\n            .cornerRadius(14)\n            .shadow(color:.black.opacity(0.28), radius: 8, x:0, y:4)\n            .padding()\n            .offset(y:floating ? 8.0 : -8.0)\n            .animation(floatingAnimation, value: floating)\n            .scaleEffect(showSticker ? 1.0 : 0.5)\n            .animation(.bouncy, value: showSticker)\n            .onAppear{\n                withAnimation(.bouncy){\n                    floating = true\n                    showSticker = true\n                }\n            }\n    }\n}\n\n"
  },
  {
    "path": "Demos/Stickers/Stickers/StickerInputView.swift",
    "content": "//\n//  StickerInputView.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport SwiftUI\n\n/// The user enters a sticker prompt using this view.\nstruct StickerInputView: View {\n\n    enum FocusedField {\n        case currentPrompt\n    }\n\n    /// Bind to a UI model's property for that property to change as the user enters text,\n    /// and for programmatic changes to the UI model's property to be reflected in this view\n    @Binding var currentPrompt: String\n    @FocusState private var focusedField: FocusedField?\n\n    var body: some View {\n        VStack(spacing:8){\n            Text(\"Describe your sticker below\")\n                .frame(maxWidth: .infinity, alignment: .topLeading)\n                .font(.system(size: 20, weight: .bold, design: .rounded))\n                .foregroundColor(.black.opacity(0.28))\n            TextField(\"type here...\", text: $currentPrompt, axis: .vertical)\n                .focused($focusedField, equals: .currentPrompt)\n                .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)\n                .font(.system(size: 36, weight: .bold, design: .rounded))\n                .textFieldStyle(.plain)\n                .foregroundColor(.black.opacity(0.75))\n                .onAppear {\n                    focusedField = .currentPrompt\n                }\n        }\n        .padding()\n    }\n}\n\n"
  },
  {
    "path": "Demos/Stickers/Stickers/StickerLoadingView.swift",
    "content": "//\n//  StickerLoadingView.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport SwiftUI\n\n@MainActor\nstruct StickerLoadingView: View {\n\n    /// Loading text to display while long requests to OpenAI are fulfilled\n    @State private var currentLoadState = \"Hold tight\"\n\n    var body: some View {\n        VStack(spacing:16){\n            ProgressView()\n                .controlSize(.extraLarge)\n                .tint(.white)\n            Text(currentLoadState)\n                .transition(.move(edge: .bottom))\n                .font(.system(size: 20, weight: .semibold, design: .rounded))\n                .foregroundColor(.black.opacity(0.28))\n        }\n        .frame(maxWidth:.infinity, maxHeight:.infinity)\n        .onAppear {\n            Task {\n                try await Task.sleep(for: .seconds(4))\n                currentLoadState = \"Generating sticker\"\n                try await Task.sleep(for: .seconds(4))\n                currentLoadState = \"Finalizing\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Demos/Stickers/Stickers/StickerManager.swift",
    "content": "//\n//  StickerManager.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport UIKit\nimport SwiftUI\n\n/// The default message to display in the result view of the sticker experience.\nprivate let defaultUserMessage = \"Tap on the image to copy to your clipboard.\"\n\n@MainActor\n@Observable\nfinal class StickerManager {\n\n    /// The user-entered prompt\n    var prompt: String = \"\"\n\n    /// The current background color to use for the view\n    var currentColor: Color = .teal\n\n    /// The generated sticker as a UIImage\n    private(set) var image: UIImage?\n\n    /// A flag to indicate that the sticker is being generated and we are waiting on I/O from OpenAI\n    private(set) var isProcessing = false\n\n    /// The user message to display along with the generated sticker\n    private(set) var userMessage = defaultUserMessage\n\n    /// The set of potential background colors for the view\n    private var bgColors: Set<Color> = [.teal, .mint, .indigo, .red, .pink, .purple, .orange, .brown, .blue, .cyan, .green, .yellow, .gray]\n\n    /// A few examples to get the user's wheels turning\n    private let placeholderExamples = [\n        \"a cactus wearing a sombrero...\",\n        \"a hedgehog riding a motorcycle...\",\n        \"a kangaroo holding a basketball...\"\n    ]\n    private var placeholderIndex = 0\n\n    private let stickerDataLoader = StickerDataLoader()\n\n    /// Changes the user message briefly away from the default text.\n    /// After two seconds, the user message reverts to the default message\n    func flashUserMessage(_ message: String) {\n        withAnimation(.bouncy) {\n            userMessage = message\n        }\n        Task { [weak self] in\n            try await Task.sleep(for: .seconds(2))\n            withAnimation(.bouncy) { [weak self] in\n                self?.userMessage = defaultUserMessage\n           }\n        }\n    }\n\n    /// Creates a sticker from the current prompt stored in `self.prompt`\n    func createSticker() {\n        guard !self.isProcessing else {\n            AppLogger.info(\"Already creating a sticker. Please wait\")\n            return\n        }\n\n        let prompt = self.prompt\n        guard prompt.count > 0 else {\n            AppLogger.error(\"Trying to submit a sticker without a prompt. This is a programmer error\")\n            return\n        }\n\n        self.isProcessing = true\n        Task {\n            self.image = try await stickerDataLoader.create(fromPrompt: prompt)\n            self.isProcessing = false\n        }\n    }\n\n    /// Change the placeholder prompt\n    func nextPlaceholder() {\n        self.placeholderIndex = (self.placeholderIndex + 1) % self.placeholderExamples.count\n        self.prompt = self.placeholderExamples[self.placeholderIndex]\n    }\n\n    /// Returns to the starting point of the sticker experience, e.g. where no sticker is in the UI\n    func startOver() {\n        self.image = nil\n        self.nextPlaceholder()\n        self.currentColor = self.bgColors.randomElement()!\n    }\n\n    /// Regenerate a sticker using the same prompt\n    func regenerate() {\n        self.image = nil\n        self.createSticker()\n        self.currentColor = self.bgColors.randomElement()!\n    }\n}\n\n"
  },
  {
    "path": "Demos/Stickers/Stickers/StickerView.swift",
    "content": "//\n//  StickerView.swift\n//  AIProxyBootstrap\n//\n//  Created by Todd Hamilton\n//\n\nimport SwiftUI\n\n@MainActor\nstruct StickerView: View {\n    @Environment(\\.dismiss) private var dismiss\n\n    /// The manager that drives this view\n    @Bindable var stickerManager: StickerManager\n\n    var body: some View {\n        VStack{\n            if let image = stickerManager.image {\n                buildResultView(withUIImage: image)\n            } else {\n                promptView\n            }\n        } \n        .toolbar {\n            stickerToolbar\n        }\n        .onAppear() {\n            stickerManager.startOver()\n        }\n    }\n\n    private func buildResultView(withUIImage uiImage: UIImage) -> some View {\n        VStack(spacing:16) {\n            VStack{\n                StickerImageView(uiImage: uiImage)\n                    .onTapGesture {\n                        self.copyImage(uiImage: uiImage)\n                    }\n                Spacer()\n                userMessageView\n                Spacer()\n            }\n            .background(stickerManager.currentColor.gradient)\n            .cornerRadius(17)\n            startOverButton\n            regenerateButton\n        }\n        .padding()\n    }\n\n    private var promptView: some View {\n        VStack(spacing:16) {\n            if stickerManager.isProcessing {\n                StickerLoadingView()\n                    .background(stickerManager.currentColor.gradient)\n                    .cornerRadius(17)\n            } else {\n                StickerInputView(currentPrompt: $stickerManager.prompt)\n                    .background(stickerManager.currentColor.gradient)\n                    .cornerRadius(17)\n                generateButton\n            }\n        }\n        .padding()\n    }\n\n    private var stickerToolbar: some View {\n        Button(\"Clear\") {\n            stickerManager.prompt = \"\"\n        }\n        .disabled(stickerManager.prompt.count == 0)\n    }\n\n    private var userMessageView: some View {\n        Text(stickerManager.userMessage)\n            .font(.system(size: 24, weight: .semibold, design: .rounded))\n            .multilineTextAlignment(.center)\n            .transition(.scale)\n    }\n\n    // MARK: - Actions\n\n    /// Copy the passed `uiImage` to system clipboard\n    private func copyImage(uiImage: UIImage) {\n        UIPasteboard.general.image = uiImage\n        stickerManager.flashUserMessage(\"Copied!\")\n    }\n\n    // MARK: - Buttons\n\n    /// Button to start from the prompt input view and dispose of the existing sticker\n    private var startOverButton: some View {\n        Button {\n            withAnimation {\n                stickerManager.startOver()\n            }\n        } label: {\n            Label(\"Start Over\", systemImage: \"sparkles\")\n                .frame(maxWidth:.infinity)\n        }\n        .buttonStyle(ChunkyButtonStyle())\n    }\n    \n    /// Button to regenerate a sticker from the current prompt, disposing of the existing sticker.\n    private var regenerateButton: some View {\n        Button{\n            withAnimation{\n                stickerManager.regenerate()\n            }\n        }label:{\n            Label(\"Regenerate\", systemImage: \"arrow.triangle.2.circlepath\")\n                .frame(maxWidth:.infinity)\n        }\n        .buttonStyle(ChunkyButtonStyle())\n    }\n\n    /// Button to generate a sticker from the current user prompt\n    private var generateButton: some View {\n        Button {\n            withAnimation() {\n                stickerManager.createSticker()\n            }\n        } label: {\n            Label(\"Generate\", systemImage: \"sparkles\")\n                .frame(maxWidth: .infinity)\n        }\n        .buttonStyle(ChunkyButtonStyle())\n    }\n}\n\n#Preview {\n    StickerView(stickerManager: StickerManager())\n}\n"
  },
  {
    "path": "Demos/Stickers/Stickers/StickersApp.swift",
    "content": "//\n//  StickersApp.swift\n//  Stickers\n//\n//  Created by Lou Zell\n//\n\nimport SwiftUI\n\n@main\n@MainActor\nstruct StickersApp: App {\n\n    @State var stickerManager = StickerManager()\n\n    var body: some Scene {\n        WindowGroup {\n            StickerView(stickerManager: stickerManager)\n        }\n    }\n}\n"
  },
  {
    "path": "Demos/Stickers/Stickers.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 56;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t0DDD23262B4DE0A300B2AE5C /* StickersApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD23252B4DE0A300B2AE5C /* StickersApp.swift */; };\n\t\t0DDD232A2B4DE0A400B2AE5C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0DDD23292B4DE0A400B2AE5C /* Assets.xcassets */; };\n\t\t0DDD232D2B4DE0A400B2AE5C /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0DDD232C2B4DE0A400B2AE5C /* Preview Assets.xcassets */; };\n\t\t0DDD24642B4DF17C00B2AE5C /* StickerDataLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD245E2B4DF17C00B2AE5C /* StickerDataLoader.swift */; };\n\t\t0DDD24652B4DF17C00B2AE5C /* StickerInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD245F2B4DF17C00B2AE5C /* StickerInputView.swift */; };\n\t\t0DDD24662B4DF17C00B2AE5C /* StickerLoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD24602B4DF17C00B2AE5C /* StickerLoadingView.swift */; };\n\t\t0DDD24672B4DF17C00B2AE5C /* StickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD24612B4DF17C00B2AE5C /* StickerView.swift */; };\n\t\t0DDD24682B4DF17C00B2AE5C /* StickerImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD24622B4DF17C00B2AE5C /* StickerImageView.swift */; };\n\t\t0DDD24692B4DF17C00B2AE5C /* StickerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD24632B4DF17C00B2AE5C /* StickerManager.swift */; };\n\t\t0DDD246C2B4DF18100B2AE5C /* AppConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD246A2B4DF18100B2AE5C /* AppConstants.swift */; };\n\t\t0DDD246D2B4DF18100B2AE5C /* AppLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD246B2B4DF18100B2AE5C /* AppLogger.swift */; };\n\t\t0DDD24722B4DF1B000B2AE5C /* ButtonStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD24712B4DF1B000B2AE5C /* ButtonStyles.swift */; };\n\t\t2CE770902C9B43CD00EC6C74 /* AIProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 2CE7708F2C9B43CD00EC6C74 /* AIProxy */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t0DDD23222B4DE0A300B2AE5C /* Stickers.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Stickers.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t0DDD23252B4DE0A300B2AE5C /* StickersApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StickersApp.swift; sourceTree = \"<group>\"; };\n\t\t0DDD23292B4DE0A400B2AE5C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t0DDD232C2B4DE0A400B2AE5C /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = \"Preview Assets.xcassets\"; sourceTree = \"<group>\"; };\n\t\t0DDD245E2B4DF17C00B2AE5C /* StickerDataLoader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StickerDataLoader.swift; sourceTree = \"<group>\"; };\n\t\t0DDD245F2B4DF17C00B2AE5C /* StickerInputView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StickerInputView.swift; sourceTree = \"<group>\"; };\n\t\t0DDD24602B4DF17C00B2AE5C /* StickerLoadingView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StickerLoadingView.swift; sourceTree = \"<group>\"; };\n\t\t0DDD24612B4DF17C00B2AE5C /* StickerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StickerView.swift; sourceTree = \"<group>\"; };\n\t\t0DDD24622B4DF17C00B2AE5C /* StickerImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StickerImageView.swift; sourceTree = \"<group>\"; };\n\t\t0DDD24632B4DF17C00B2AE5C /* StickerManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StickerManager.swift; sourceTree = \"<group>\"; };\n\t\t0DDD246A2B4DF18100B2AE5C /* AppConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppConstants.swift; sourceTree = \"<group>\"; };\n\t\t0DDD246B2B4DF18100B2AE5C /* AppLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppLogger.swift; sourceTree = \"<group>\"; };\n\t\t0DDD24712B4DF1B000B2AE5C /* ButtonStyles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ButtonStyles.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t0DDD231F2B4DE0A300B2AE5C /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2CE770902C9B43CD00EC6C74 /* AIProxy in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t0DDD23192B4DE0A300B2AE5C = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0DDD23242B4DE0A300B2AE5C /* Stickers */,\n\t\t\t\t0DDD23232B4DE0A300B2AE5C /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0DDD23232B4DE0A300B2AE5C /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0DDD23222B4DE0A300B2AE5C /* Stickers.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0DDD23242B4DE0A300B2AE5C /* Stickers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0DDD246A2B4DF18100B2AE5C /* AppConstants.swift */,\n\t\t\t\t0DDD246B2B4DF18100B2AE5C /* AppLogger.swift */,\n\t\t\t\t0DDD24712B4DF1B000B2AE5C /* ButtonStyles.swift */,\n\t\t\t\t0DDD245E2B4DF17C00B2AE5C /* StickerDataLoader.swift */,\n\t\t\t\t0DDD24622B4DF17C00B2AE5C /* StickerImageView.swift */,\n\t\t\t\t0DDD245F2B4DF17C00B2AE5C /* StickerInputView.swift */,\n\t\t\t\t0DDD24602B4DF17C00B2AE5C /* StickerLoadingView.swift */,\n\t\t\t\t0DDD24632B4DF17C00B2AE5C /* StickerManager.swift */,\n\t\t\t\t0DDD23252B4DE0A300B2AE5C /* StickersApp.swift */,\n\t\t\t\t0DDD24612B4DF17C00B2AE5C /* StickerView.swift */,\n\t\t\t\t0DDD23292B4DE0A400B2AE5C /* Assets.xcassets */,\n\t\t\t\t0DDD232B2B4DE0A400B2AE5C /* Preview Content */,\n\t\t\t);\n\t\t\tpath = Stickers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0DDD232B2B4DE0A400B2AE5C /* Preview Content */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0DDD232C2B4DE0A400B2AE5C /* Preview Assets.xcassets */,\n\t\t\t);\n\t\t\tpath = \"Preview Content\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t0DDD23212B4DE0A300B2AE5C /* Stickers */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 0DDD23302B4DE0A400B2AE5C /* Build configuration list for PBXNativeTarget \"Stickers\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t0DDD231E2B4DE0A300B2AE5C /* Sources */,\n\t\t\t\t0DDD231F2B4DE0A300B2AE5C /* Frameworks */,\n\t\t\t\t0DDD23202B4DE0A300B2AE5C /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = Stickers;\n\t\t\tpackageProductDependencies = (\n\t\t\t\t2CE7708F2C9B43CD00EC6C74 /* AIProxy */,\n\t\t\t);\n\t\t\tproductName = Stickers;\n\t\t\tproductReference = 0DDD23222B4DE0A300B2AE5C /* Stickers.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t0DDD231A2B4DE0A300B2AE5C /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = 1;\n\t\t\t\tLastSwiftUpdateCheck = 1510;\n\t\t\t\tLastUpgradeCheck = 1510;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t0DDD23212B4DE0A300B2AE5C = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 15.1;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 0DDD231D2B4DE0A300B2AE5C /* Build configuration list for PBXProject \"Stickers\" */;\n\t\t\tcompatibilityVersion = \"Xcode 14.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 0DDD23192B4DE0A300B2AE5C;\n\t\t\tpackageReferences = (\n\t\t\t\t2CE7708E2C9B43CD00EC6C74 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */,\n\t\t\t);\n\t\t\tproductRefGroup = 0DDD23232B4DE0A300B2AE5C /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t0DDD23212B4DE0A300B2AE5C /* Stickers */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t0DDD23202B4DE0A300B2AE5C /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t0DDD232D2B4DE0A400B2AE5C /* Preview Assets.xcassets in Resources */,\n\t\t\t\t0DDD232A2B4DE0A400B2AE5C /* Assets.xcassets in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t0DDD231E2B4DE0A300B2AE5C /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t0DDD24642B4DF17C00B2AE5C /* StickerDataLoader.swift in Sources */,\n\t\t\t\t0DDD24692B4DF17C00B2AE5C /* StickerManager.swift in Sources */,\n\t\t\t\t0DDD24672B4DF17C00B2AE5C /* StickerView.swift in Sources */,\n\t\t\t\t0DDD24722B4DF1B000B2AE5C /* ButtonStyles.swift in Sources */,\n\t\t\t\t0DDD246C2B4DF18100B2AE5C /* AppConstants.swift in Sources */,\n\t\t\t\t0DDD24682B4DF17C00B2AE5C /* StickerImageView.swift in Sources */,\n\t\t\t\t0DDD24662B4DF17C00B2AE5C /* StickerLoadingView.swift in Sources */,\n\t\t\t\t0DDD246D2B4DF18100B2AE5C /* AppLogger.swift in Sources */,\n\t\t\t\t0DDD24652B4DF17C00B2AE5C /* StickerInputView.swift in Sources */,\n\t\t\t\t0DDD23262B4DE0A300B2AE5C /* StickersApp.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t0DDD232E2B4DE0A400B2AE5C /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.2;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"DEBUG $(inherited)\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t0DDD232F2B4DE0A400B2AE5C /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.2;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t0DDD23312B4DE0A400B2AE5C /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"Stickers/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 9557YJ9D37;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.aiproxy.bootstrap.stickers;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t0DDD23322B4DE0A400B2AE5C /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"Stickers/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 9557YJ9D37;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.aiproxy.bootstrap.stickers;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t0DDD231D2B4DE0A300B2AE5C /* Build configuration list for PBXProject \"Stickers\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t0DDD232E2B4DE0A400B2AE5C /* Debug */,\n\t\t\t\t0DDD232F2B4DE0A400B2AE5C /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t0DDD23302B4DE0A400B2AE5C /* Build configuration list for PBXNativeTarget \"Stickers\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t0DDD23312B4DE0A400B2AE5C /* Debug */,\n\t\t\t\t0DDD23322B4DE0A400B2AE5C /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCRemoteSwiftPackageReference section */\n\t\t2CE7708E2C9B43CD00EC6C74 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/lzell/AIProxySwift\";\n\t\t\trequirement = {\n\t\t\t\tbranch = main;\n\t\t\t\tkind = branch;\n\t\t\t};\n\t\t};\n/* End XCRemoteSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */\n\t\t2CE7708F2C9B43CD00EC6C74 /* AIProxy */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 2CE7708E2C9B43CD00EC6C74 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */;\n\t\t\tproductName = AIProxy;\n\t\t};\n/* End XCSwiftPackageProductDependency section */\n\t};\n\trootObject = 0DDD231A2B4DE0A300B2AE5C /* Project object */;\n}\n"
  },
  {
    "path": "Demos/Transcriber/Transcriber/AppConstants.swift",
    "content": "//\n//  AppConstants.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport SwiftData\nimport AIProxy\n\n/// Use this actor for audio work\n@globalActor actor AudioActor {\n    static let shared = AudioActor()\n}\n\nenum AppConstants {\n\n    static let swiftDataModels: [any PersistentModel.Type] = [AudioRecording.self, TranscribedAudioRecording.self]\n    static let swiftDataContainer = try! ModelContainer(for: AudioRecording.self, TranscribedAudioRecording.self)\n\n    static let audioSampleQueue = DispatchQueue(label: \"com.AIProxyBootstrap.audioSampleQueue\")\n\n    #error(\n        \"\"\"\n        Uncomment one of the methods below. To build and run on device you must follow the AIProxy integration guide.\n        Please see https://www.aiproxy.pro/docs/integration-guide.html\")\n        \"\"\"\n    )\n\n    /* Uncomment for BYOK use cases */\n    static let openAIService = AIProxy.openAIDirectService(\n        unprotectedAPIKey: \"your-openai-key\"\n    )\n\n    /* Uncomment for all other production use cases */\n//    let openAIService = AIProxy.openAIService(\n//        partialKey: \"partial-key-from-your-developer-dashboard\",\n//        serviceURL: \"service-url-from-your-developer-dashboard\"\n//    )\n}\n"
  },
  {
    "path": "Demos/Transcriber/Transcriber/AppLogger.swift",
    "content": "//\n//  AppLogger.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport OSLog\n\n/// Log levels available:\n///\n///     AppLogger.debug\n///     AppLogger.info\n///     AppLogger.warning\n///     AppLogger.error\n///     AppLogger.critical\n///\n/// Flip on metadata logging in Xcode's console to show which source line the log occurred from.\n///\n/// See my reddit post for a video instructions:\n/// https://www.reddit.com/r/SwiftUI/comments/15lsdtk/how_to_use_the_oslog_logger/\nlet AppLogger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"UnknownApp\",\n                       category: \"AIProxyBootstrapTranscriber\")\n"
  },
  {
    "path": "Demos/Transcriber/Transcriber/Assets.xcassets/AccentColor.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/Transcriber/Transcriber/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"transcribe.png\",\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/Transcriber/Transcriber/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/Transcriber/Transcriber/AudioFileWriter.swift",
    "content": "//\n//  AudioFileWriter.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport AVFoundation\n\n/// One of the following errors will be thrown at initialization if the microphone vendor can't vend samples.\nenum AudioFileWriterError: Error {\n    case couldNotWriteToDestinationURL\n    case couldNotCreateAudioInput\n}\n\n\n/// Writes an m4a file out of audio sample buffers.\n/// Samples passed to the `append` method will be written to the m4a file between calls to `init()` and `finishWriting()`.\n/// Create one instance of AudioFileWriter for each audio file that you'd like to write.\n@AudioActor\nfinal class AudioFileWriter {\n    /// The location to write the audio file to\n    let fileURL: URL\n\n    private let assetWriter: AVAssetWriter\n    private let microphoneWriter: AVAssetWriterInput\n    private let audioSettings: [String: Any] = [\n        AVFormatIDKey: kAudioFormatMPEG4AAC,\n        AVSampleRateKey: 48_000,\n        AVNumberOfChannelsKey: 2,\n        AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue\n    ]\n\n    private var isWriting = false\n    \n    /// Throws one of `AudioFileWriterError` if we can't initialize the AVFoundation dependencies\n    /// - Parameter fileURL: The location to write the audio file to\n    init(fileURL: URL) throws {\n        self.fileURL = fileURL\n        do {\n            self.assetWriter = try AVAssetWriter(outputURL: fileURL, fileType: .m4a)\n        } catch {\n            throw AudioFileWriterError.couldNotWriteToDestinationURL\n        }\n\n        self.microphoneWriter = AVAssetWriterInput(mediaType: .audio, outputSettings: self.audioSettings)\n        self.microphoneWriter.expectsMediaDataInRealTime = true\n\n        if self.assetWriter.canAdd(self.microphoneWriter) {\n            self.assetWriter.add(self.microphoneWriter)\n        } else {\n            throw AudioFileWriterError.couldNotCreateAudioInput\n        }\n    }\n    \n    /// Append a sample buffer to the audio file\n    /// - Parameter sample: A core media sample buffer. See the `MicrophoneSampleVendor` file for an example of how to source these.\n    func append(sample: CMSampleBuffer) {\n        if !self.isWriting {\n            self.assetWriter.startWriting()\n            self.assetWriter.startSession(atSourceTime: sample.presentationTimeStamp)\n            self.isWriting = true\n        }\n        if self.microphoneWriter.isReadyForMoreMediaData {\n            self.microphoneWriter.append(sample)\n        } else {\n            AppLogger.warning(\"The AudioFileWriter is not ready for more audio data\")\n        }\n    }\n    \n    /// Finishes writing the file to disk\n    /// - Returns: URL location of the m4a file on disk\n    func finishWriting() async -> URL {\n        self.microphoneWriter.markAsFinished()\n        await self.assetWriter.finishWriting()\n        self.isWriting = false\n        return self.fileURL\n    }\n}\n"
  },
  {
    "path": "Demos/Transcriber/Transcriber/AudioRecorder.swift",
    "content": "//\n//  Manager.swift\n//  OpenAIExperiment\n//\n//  Created by Lou Zell\n//\n\nimport AVFoundation\nimport Foundation\n\n@AudioActor\nfinal class AudioRecorder {\n    private var microphoneSampleVendor: MicrophoneSampleVendor?\n    private var audioFileWriter: AudioFileWriter?\n\n    nonisolated init() {}\n    \n    /// Start recording an audio file\n    /// - Returns: true if the audio recorder was able to start recording, false otherwise\n    func start() -> Bool {\n        do {\n            self.microphoneSampleVendor = try MicrophoneSampleVendor()\n        } catch {\n            AppLogger.error(\"Could not create a MicrophoneSampleVendor: \\(error)\")\n            return false\n        }\n\n        do {\n            self.audioFileWriter = try AudioFileWriter(fileURL: FileUtils.getFileURL())\n        } catch {\n            AppLogger.error(\"Could not create an audio file writer: \\(error)\")\n            return false\n        }\n\n        self.microphoneSampleVendor?.start(onSample: { [weak self] sampleBuffer in\n            self?.audioFileWriter?.append(sample: sampleBuffer)\n        })\n        return true\n    }\n\n    /// Returns the recording created between calls to `startRecording` and `stopRecording`\n    func stopRecording(duration: String) async -> AudioRecording? {\n        guard let fileWriter = self.audioFileWriter,\n              let sampleVendor = self.microphoneSampleVendor else\n        {\n            AppLogger.warning(\"Expected audio dependencies to be set\")\n            return nil\n        }\n        sampleVendor.stop()\n        let url = await fileWriter.finishWriting()\n        return AudioRecording(localUrl: url, duration: duration)\n    }\n}\n"
  },
  {
    "path": "Demos/Transcriber/Transcriber/AudioRecording.swift",
    "content": "//\n//  AudioRecording.swift\n//  Transcriber\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport SwiftData\n\n/// Encapsulates a recording. The `url` is the location on disk of the raw audio file (an m4a).\n@Model\nfinal class AudioRecording {\n    @Attribute(.unique) let localUrl: URL\n    let duration: String\n\n    init(localUrl: URL, duration: String) {\n        self.localUrl = localUrl\n        self.duration = duration\n    }\n\n    var resolvedURL: URL? {\n        // There is a little nuance here. Every time you build and run the app the apple sandbox changes.\n        // We first try to find the associated file at the spot that we stored it, but if it's not there then\n        // we construct a new URL based on the current apple sandbox\n        if (FileManager.default.fileExists(atPath: self.localUrl.path)) {\n            return self.localUrl\n        } else {\n            let resolvedURL = FileUtils.getDocumentsURL().appending(component: self.localUrl.lastPathComponent)\n            if FileManager.default.fileExists(atPath: resolvedURL.path) {\n                return resolvedURL\n            }\n        }\n        return nil\n    }\n}\n"
  },
  {
    "path": "Demos/Transcriber/Transcriber/ButtonStyles.swift",
    "content": "//\n//  ButtonStyles.swift\n//  AIProxyBootstrap\n//\n//  Created by Todd Hamilton\n//\n\nimport SwiftUI\n\nstruct ButtonStyles: View {\n    var body: some View {\n        \n        ZStack{\n            Color(.systemGroupedBackground)\n                .ignoresSafeArea()\n            \n            VStack(spacing:48){\n                \n                Button{\n                    /// do something\n                }label:{\n                    HStack(spacing:6){\n                        Image(systemName: \"play.circle.fill\")\n                            .font(.system(size: 15, weight:.semibold, design: .rounded))\n                        Text(\"10s\")\n                            .font(.system(size: 11, weight: .regular, design: .monospaced))\n                            .fontDesign(.monospaced)\n                    }\n                }\n                .buttonStyle(TranscriptionButtonStyle())\n\n                Button(){\n                    /// do something\n                } label:{\n                    Label(\"Chunky Button\", systemImage: \"sparkles\")\n                }\n                .buttonStyle(ChunkyButtonStyle(offsetSize: 10.0))\n\n                Button{\n                    /// do something\n                } label: {\n                    ZStack{\n                        RoundedRectangle(cornerRadius: 45, style:.continuous)\n                            .fill(.red.gradient)\n                            .frame(width:85, height:85)\n                        Image(systemName: \"waveform\")\n                            .font(.title)\n                            .foregroundColor(.white)\n                    }\n                }\n                .buttonStyle(RecordButton())\n                \n                Button(){\n                    /// do something\n                }label:{\n                    Image(systemName: \"arrow.forward\")\n                        .font(.system(size: 17, weight: .bold))\n                }\n                .buttonStyle(TranslateButton())\n                \n            }\n            .padding()\n        }\n        \n    }\n}\n\nstruct ChunkyButtonStyle: ButtonStyle {\n\n    var offsetSize = 10.0\n\n    func makeBody(configuration: Configuration) -> some View {\n        configuration.label\n            .font(.system(size: 24, weight: .bold, design: .rounded))\n            .foregroundColor(.black)\n            .padding()\n            .offset(y: configuration.isPressed ? offsetSize-2 : 0)\n            .background(\n                GeometryReader{ geo in\n                    RoundedRectangle(cornerRadius: 17)\n                        .strokeBorder(Color.black, lineWidth: 4)\n                        .background(\n                            RoundedRectangle(cornerRadius: 17)\n                                .fill(.white)\n                        )\n                        .offset(y:offsetSize)\n\n                        .overlay(\n                            RoundedRectangle(cornerRadius: 17)\n                                .fill(.white)\n                                .strokeBorder(Color.black, lineWidth: 4)\n                                .background(RoundedRectangle(cornerRadius: 17).fill(Color.white))\n                                .offset(y: configuration.isPressed ? offsetSize : 0)\n                        )\n                }\n            )\n    }\n}\n\nstruct RecordButton: ButtonStyle {\n    func makeBody(configuration: Configuration) -> some View {\n        configuration.label\n            .frame(maxWidth:80, maxHeight: 80)\n            .shadow(color:.black.opacity(0.28), radius: 10, y:8)\n            .scaleEffect(configuration.isPressed ? 0.9 : 1, anchor: .center)\n            .animation(.easeOut(duration: 0.2), value: configuration.isPressed)\n            .padding(.bottom, 40)\n            \n    }\n}\n\nstruct TranslateButton: ButtonStyle {\n    func makeBody(configuration: Configuration) -> some View {\n        configuration.label\n            .foregroundColor(.white)\n            .frame(width:56, height:56)\n            .background(\n                Circle()\n                    .fill(.teal.gradient)\n            )\n            .brightness(configuration.isPressed ? -0.1 : 0.0)\n            .scaleEffect(configuration.isPressed ? 0.9 : 1, anchor: .center)\n            .animation(.easeOut(duration: 0.2), value: configuration.isPressed)\n    }\n}\n\nstruct TranscriptionButtonStyle: ButtonStyle {\n\n    func makeBody(configuration: Configuration) -> some View {\n        configuration.label\n            .foregroundColor(.secondary)\n            .padding(.leading, 4)\n            .padding(.trailing, 8)\n            .padding(.vertical, 4)\n            .background(\n                Capsule().fill(.secondary.opacity(configuration.isPressed ? 0.28 : 0.14))\n            )\n            .scaleEffect(configuration.isPressed ? 0.9 : 1.0)\n    }\n}\n\n#Preview {\n    ButtonStyles()\n}\n"
  },
  {
    "path": "Demos/Transcriber/Transcriber/FileUtils.swift",
    "content": "//\n//  FileUtils.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\n\n\nstruct FileUtils {\n    private init() {\n        fatalError(\"FileUtils is a namespace only\")\n    }\n\n    static func getDocumentsURL() -> URL {\n        guard let documentsUrl = FileManager.default.urls(\n            for: .documentDirectory, in: .userDomainMask).first\n        else {\n            fatalError(\"Could could not find the Documents directory\")\n        }\n        return documentsUrl\n    }\n\n    static func getFileURL() -> URL {\n        let documentsUrl = self.getDocumentsURL()\n        let isoFormatter = ISO8601DateFormatter()\n        isoFormatter.formatOptions = [.withFullDate, .withTime, .withColonSeparatorInTime]\n        isoFormatter.timeZone = .current\n\n        var dateString = isoFormatter.string(from: Date())\n        dateString = dateString.replacingOccurrences(of: \":\", with: \".\")\n        let filename = \"AIProxyBootstrap-\\(dateString).m4a\"\n\n        return documentsUrl.appendingPathComponent(filename)\n    }\n\n    static func deleteFile(at url: URL) {\n        do {\n            try FileManager.default.removeItem(at: url)\n        } catch {\n            AppLogger.info(\"Could not find file to delete at \\(url)\")\n        }\n    }\n}\n"
  },
  {
    "path": "Demos/Transcriber/Transcriber/MicrophoneSampleVendor.swift",
    "content": "//\n//  MicrophoneSampleVendor.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport CoreMedia\nimport AVFoundation\n\n/// One of the following errors will be thrown at initialization if the microphone vendor can't vend samples.\nenum MicrophoneSampleVendorError: Error {\n    case micNotFound\n    case micNotUsableAsCaptureDevice\n    case captureSessionRejectedMic\n    case captureSessionRejectedOutput\n}\n\n\n/// Vends samples of the microphone audio\n///\n/// ## Requirements\n///\n/// - Assumes an `NSMicrophoneUsageDescription` description has been added to Target > Info\n/// - Assumes that microphone permissions have already been granted\n///\n/// ## Usage\n///\n/// ```\n///     self.microphoneVendor = try MicrophoneSampleVendor()\n///     self.microphoneVendor.start { sample in\n///        // Do something with `sample`\n///        // Note: this callback is invoked on a background thread\n///     }\n/// ```\n///\n@AudioActor\nfinal class MicrophoneSampleVendor {\n\n    private let captureSession = AVCaptureSession()\n    private let audioOutput = AVCaptureAudioDataOutput()\n    private let sampleBufferDelegate = SampleBufferDelegate()\n\n    init() throws {\n        let mic = try findMic()\n        let micInput = try mic.asInput()\n        try self.captureSession.addMicInput(micInput)\n        try self.captureSession.addAudioOutput(self.audioOutput)\n        self.audioOutput.setSampleBufferDelegate(self.sampleBufferDelegate,\n                                                 queue: AppConstants.audioSampleQueue)\n    }\n\n    func start(onSample: @escaping (CMSampleBuffer) -> Void) {\n        self.sampleBufferDelegate.sampleCallback = onSample\n        self.captureSession.startRunning()\n    }\n\n    func stop() {\n        self.captureSession.stopRunning()\n    }\n}\n\nprivate class SampleBufferDelegate: NSObject, AVCaptureAudioDataOutputSampleBufferDelegate {\n    var sampleCallback: ((CMSampleBuffer) -> Void)?\n\n    func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {\n        dispatchPrecondition(condition: .onQueue(AppConstants.audioSampleQueue))\n        self.sampleCallback?(sampleBuffer)\n    }\n}\n\nprivate func findMic() throws -> AVCaptureDevice {\n    let microphones = AVCaptureDevice.DiscoverySession(deviceTypes: [.microphone], mediaType: .audio, position: .unspecified).devices\n    if let mic = microphones.first {\n        return mic\n    }\n    throw MicrophoneSampleVendorError.micNotFound\n}\n\nprivate extension AVCaptureDevice {\n    func asInput() throws -> AVCaptureDeviceInput {\n        do {\n            return try AVCaptureDeviceInput(device: self)\n        } catch {\n            throw MicrophoneSampleVendorError.micNotUsableAsCaptureDevice\n        }\n    }\n}\n\nprivate extension AVCaptureSession {\n    func addMicInput(_ micInput: AVCaptureDeviceInput) throws {\n        if self.canAddInput(micInput) {\n            self.addInput(micInput)\n        } else {\n            throw MicrophoneSampleVendorError.captureSessionRejectedMic\n        }\n    }\n\n    func addAudioOutput(_ audioOutput: AVCaptureAudioDataOutput) throws {\n        if self.canAddOutput(audioOutput) {\n            self.addOutput(audioOutput)\n        } else {\n            throw MicrophoneSampleVendorError.captureSessionRejectedMic\n        }\n    }\n}\n"
  },
  {
    "path": "Demos/Transcriber/Transcriber/ModelContext+Extensions.swift",
    "content": "//\n//  ModelContext+Extensions.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport SwiftData\n\nextension ModelContext {\n\n    /// Deletes all models in `AppConstants.swiftDataModels` from SwiftData.\n    /// Use this during development to return to a clean slate.\n    func reset() {\n        do {\n            for model in AppConstants.swiftDataModels {\n                try self.delete(model: model)\n            }\n        } catch {\n            AppLogger.error(\"Failed to reset swift data for all models. Error: \\(error.localizedDescription)\")\n        }\n    }\n}\n"
  },
  {
    "path": "Demos/Transcriber/Transcriber/NoRecordingsView.swift",
    "content": "//\n//  NoRecordingsView.swift\n//  AIProxyBootstrap\n//\n//  Created by Todd Hamilton\n//\n\nimport SwiftUI\n\nstruct NoRecordingsView: View {\n    var body: some View {\n        VStack{\n            Image(systemName: \"waveform\")\n                .font(.largeTitle)\n                .foregroundColor(.secondary)\n                .padding(.bottom, 8)\n\n            Text(\"No recordings\")\n                .font(.headline)\n            Text(\"Tap the record button below to start transcribing.\")\n                .multilineTextAlignment(.center)\n                .frame(maxWidth:240)\n                .foregroundColor(.secondary)\n                .font(.subheadline)\n        }\n        .frame(maxHeight:.infinity)\n        .foregroundColor(.primary)\n        .padding(.bottom, 48)\n    }\n}\n\n#Preview {\n    NoRecordingsView()\n}\n"
  },
  {
    "path": "Demos/Transcriber/Transcriber/Preview Content/Preview Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/Transcriber/Transcriber/RecordingRowView.swift",
    "content": "//\n//  RecordingRowView.swift\n//  AIProxyBootstrap\n//\n//  Created by Todd Hamilton\n//\n\nimport SwiftUI\n\n\nstruct RecordingRowView: View {\n\n    let recording: TranscribedAudioRecording\n    @State private var startAnimation = false\n    \n    var body: some View {\n        HStack(spacing:0){\n            Text(recording.transcript)\n                .font(.body)\n\n            Spacer()\n\n            Button{\n                recording.play()\n            }label:{\n                HStack(spacing:6){\n                    Image(systemName: \"play.circle.fill\")\n                        .font(.system(size: 15, weight:.semibold, design: .rounded))\n                    Text(\"\\(recording.audioRecording.duration)s\")\n                        .font(.system(size: 11, weight: .regular, design: .monospaced))\n                }\n            }\n            .buttonStyle(TranscriptionButtonStyle())\n        }\n        .padding(.vertical, 8)\n        .opacity(startAnimation ? 1 : 0)\n        .offset(y:startAnimation ? 0 : -10)\n        .onAppear{\n            withAnimation(.smooth.delay(0.2)){\n                startAnimation = true\n            }\n        }   \n    }\n}\n\n#Preview {\n    RecordingRowView(recording: previewRecording())\n        .padding()\n}\n\nprivate func previewRecording() -> TranscribedAudioRecording {\n    let audioRecording = AudioRecording(localUrl: URL(fileURLWithPath: \"/dev/null\"),\n                                        duration: \"1.2s\")\n    return TranscribedAudioRecording(\n        audioRecording: audioRecording,\n        transcript: \"hello world\",\n        createdAt: Date()\n    )\n}\n\n"
  },
  {
    "path": "Demos/Transcriber/Transcriber/TranscribedAudioRecording.swift",
    "content": "//\n//  TranscribedAudioRecording.swift\n//  Transcriber\n//\n//  Created by Lou Zell\n//\n\nimport AVFoundation\nimport Foundation\nimport SwiftData\n\n/// Encapsulates a transcribed audio recording\n@Model\nfinal class TranscribedAudioRecording {\n    @Relationship(deleteRule: .cascade) var audioRecording: AudioRecording\n    let transcript: String\n    let createdAt: Date\n    @Transient var player: AVAudioPlayer?\n\n    init(audioRecording: AudioRecording, transcript: String, createdAt: Date) {\n        self.audioRecording = audioRecording\n        self.transcript = transcript\n        self.createdAt = createdAt\n    }\n\n    func play() {\n        guard let resolvedURL = self.audioRecording.resolvedURL else {\n            AppLogger.error(\"The audio recording model does not have an associated audio file\")\n            return\n        }\n        AppLogger.info(\"Playing file at \\(resolvedURL), which exists? \\(FileManager.default.fileExists(atPath: resolvedURL.path))\")\n\n        Task.detached {\n            do {\n                try AVAudioSession.sharedInstance().setCategory(.playback)\n                self.player = try AVAudioPlayer(contentsOf: resolvedURL)\n                self.player?.play()\n            } catch {\n                AppLogger.error(\"Could not play audio file. Error: \\(error.localizedDescription)\")\n            }\n        }\n     }\n}\n"
  },
  {
    "path": "Demos/Transcriber/Transcriber/TranscriberApp.swift",
    "content": "//\n//  TranscriberApp.swift\n//  Transcriber\n//\n//  Created by Lou Zell\n//\n\nimport SwiftUI\n\n@main\n@MainActor\nstruct TranscriberApp: App {\n\n    @State var transcriberManager = TranscriberManager()\n\n    var body: some Scene {\n        WindowGroup {\n            TranscriberView(transcriberManager: transcriberManager)\n        }\n    }\n}\n"
  },
  {
    "path": "Demos/Transcriber/Transcriber/TranscriberDataLoader.swift",
    "content": "//\n//  TranscriberDataLoader.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport AIProxy\n\n/// Interfaces with OpenAI to convert a recording into a transcript\nfinal actor TranscriberDataLoader {\n    \n    /// Run the OpenAI transcriber on an audio recording\n    /// - Parameter recording: the audio recording to transcribe\n    /// - Returns: a transcript of the recording created by OpenAI's Whisper model\n    func run(onRecording recording: AudioRecording) async -> String {\n        do {\n            let requestBody = OpenAICreateTranscriptionRequestBody(\n                file: try Data(contentsOf: recording.localUrl),\n                model: \"whisper-1\"\n            )\n            let response = try await AppConstants.openAIService.createTranscriptionRequest(body: requestBody)\n            return response.text\n        } catch {\n            AppLogger.error(\"Could not get transcript from OpenAI: \\(error.localizedDescription)\")\n            return \"Transcription Error\"\n        }\n    }\n}\n"
  },
  {
    "path": "Demos/Transcriber/Transcriber/TranscriberManager.swift",
    "content": "//\n//  TranscriberManager.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport SwiftUI\nimport SwiftData\n\n@MainActor\n@Observable\nfinal class TranscriberManager {\n\n    private(set) var isRecording = false\n    private let audioRecorder = AudioRecorder()\n    private let transcriber = TranscriberDataLoader()\n    private let modelContext: ModelContext\n    var recordings = [TranscribedAudioRecording]()\n\n    init() {\n        let context = AppConstants.swiftDataContainer.mainContext\n        self.recordings = fetchPersistedRecordings(context)\n        self.modelContext = context\n    }\n\n    /// This pollutes the manager a bit.\n    /// I wrote of a better way to do this, here: https://stackoverflow.com/a/77772091/143447\n    /// - Parameter newValue: The value to set `isRecording` to\n    private func setIsRecording(_ newValue: Bool) {\n        withAnimation(.smooth(duration: 0.75)) {\n            self.isRecording = newValue\n        }\n    }\n\n    /// Start recording an audio file\n    func startRecording() async {\n        self.setIsRecording(await self.audioRecorder.start())\n        if !self.isRecording {\n            AppLogger.error(\"Could not start the audio recorder\")\n        }\n    }\n\n    /// Stop recording the audio file and transcribe it to text with Whisper\n    /// - Parameter duration: Annotate the audio file with this duration.\n    func stopRecording(duration: String) async {\n        if let recording = await self.audioRecorder.stopRecording(duration: duration) {\n            let transcript = await self.transcriber.run(onRecording: recording)\n            let transcribed = TranscribedAudioRecording(audioRecording: recording, transcript: transcript, createdAt: Date())\n            self.modelContext.insert(transcribed)\n            self.recordings = fetchPersistedRecordings(self.modelContext)\n        }\n        self.setIsRecording(false)\n    }\n\n    /// Removes a recording from persistent storage and deletes the associated audio file from disk\n    /// - Parameter index: the index in `recordings` to delete\n    func deleteRecording(at index: Int) {\n        FileUtils.deleteFile(at: self.recordings[index].audioRecording.localUrl)\n        self.modelContext.delete(self.recordings[index])\n        self.recordings = fetchPersistedRecordings(self.modelContext)\n    }\n}\n\nprivate func fetchPersistedRecordings(_ modelContext: ModelContext) -> [TranscribedAudioRecording] {\n    do {\n        let descriptor = FetchDescriptor<TranscribedAudioRecording>(\n            sortBy: [SortDescriptor(\\TranscribedAudioRecording.createdAt, order: .reverse)]\n        )\n        return try modelContext.fetch(descriptor)\n    } catch {\n        AppLogger.error(\"Could not fetch audio recordings with SwiftData\")\n        return []\n    }\n}\n"
  },
  {
    "path": "Demos/Transcriber/Transcriber/TranscriberView.swift",
    "content": "//\n//  TranscribeView.swift\n//  AIProxyBootstrap\n//\n//  Created by Todd Hamilton\n//\n\nimport SwiftData\nimport SwiftUI\nimport AVFoundation\n\n@MainActor\nstruct TranscriberView: View {\n    let transcriberManager: TranscriberManager\n\n    var isRecording: Bool {\n        transcriberManager.isRecording\n    }\n\n    @State private var showDot = false\n    @State private var isPulsing = false\n    @State private var isProcessing = false\n    \n    @State var isTimerRunning = false\n    @State private var startTime =  Date()\n    @State private var timerString = \"0:00\"\n    @State private var timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()\n    \n    // With vibration\n    private let startSFX: SystemSoundID = 1113\n    private let stopSFX: SystemSoundID = 1114\n\n    private let deviceWidth = UIScreen.main.bounds.width\n    private let deviceHeight = UIScreen.main.bounds.height\n    \n    private var initialX: Double {\n        deviceWidth / 2.0\n    }\n    private var midY: Double {\n        -deviceHeight / 2.0 + 80\n    }\n    \n    var body: some View {\n        ZStack(alignment:.bottom){\n            \n            if transcriberManager.recordings.count > 0 {\n                List{\n                    ForEach(transcriberManager.recordings) { recording in\n                        RecordingRowView(recording: recording)\n                    }\n                    .onDelete { indexSet in\n                        if let index = indexSet.first {\n                            self.transcriberManager.deleteRecording(at: index)\n                        }\n                    }\n                }\n                .listStyle(.plain)\n                \n            }  else {\n                NoRecordingsView()\n            }\n            \n            /// Overlay when recording\n            if isRecording {\n                ZStack{\n                    VStack(spacing:4){\n                        Text(isProcessing ? \"Processing\" : \"Recording\")\n                            .font(.title2)\n                            .fontWeight(.bold)\n                            .foregroundColor(.primary)\n                        Text(isProcessing ? \"This may take a second\" : \"\\(self.timerString)s\")\n                            .font(.system(size: 13, weight: .medium, design: .monospaced))\n                            .foregroundColor(.secondary)\n                            .onReceive(timer) { _ in\n                                if self.isTimerRunning {\n                                    timerString = String(format: \"%.2f\", (Date().timeIntervalSince( self.startTime)))\n                                }\n                            }\n                    }\n                    .offset(y:-140)\n                }\n                .frame(maxWidth: .infinity, maxHeight:.infinity)\n                .ignoresSafeArea()\n                .background(.ultraThinMaterial)\n                .transition(.opacity)\n            }\n            \n            GeometryReader { geometry in\n                /// Gooey button effect\n                Canvas { context, size in\n                    let circle0 = context.resolveSymbol(id: 0)!\n                    let circle1 = context.resolveSymbol(id: 1)!\n                    context.addFilter(.alphaThreshold(min: 0.25, color: .primary))\n                    context.addFilter(.blur(radius: 15))\n                    context.drawLayer {context in\n                        context.draw(circle0, at: CGPoint(x:initialX, y:geometry.size.height - 80))\n                        context.draw(circle1, at: CGPoint(x:initialX, y:geometry.size.height - 80))\n                    }\n                } symbols: {\n                    Circle()\n                        .frame(width: 80, height: 80)\n                        .scaleEffect(isProcessing ? 0.75 : 1, anchor: .center)\n                        .tag(0)\n                    Circle()\n                        .frame(width: 80, height: 80)\n                        .tag(1)\n                        .scaleEffect(showDot ? 1 : 0.5, anchor: .center)\n                        .scaleEffect(isPulsing ? 1.15 : 1, anchor: .center)\n                        .offset(y: showDot ? midY : 0)\n                }\n            }\n            \n            Button{\n                UIImpactFeedbackGenerator(style: .medium).impactOccurred()\n                /// Start  recording\n                if !isRecording{\n                    Task {\n                        await transcriberManager.startRecording()\n                    }\n                    AudioServicesPlaySystemSound(startSFX)\n                    timerString = \"0.00\"\n                    startTime = Date()\n                    // start UI updates\n                    self.startTimer()\n                    withAnimation(.smooth(duration:0.75)){\n                        showDot = true\n                    }\n                    withAnimation(.easeInOut(duration: 0.75).repeatForever(autoreverses: true)){\n                        isPulsing = true\n                    }\n                    isTimerRunning = true\n                } else { /// Stop recording\n                    Task {\n                        await transcriberManager.stopRecording(duration: self.timerString)\n                        withAnimation(.bouncy){\n                            isProcessing = false\n                        }\n                    }\n\n                    AudioServicesPlaySystemSound(stopSFX)\n                    self.stopTimer()\n                    isTimerRunning = false\n                    withAnimation(.smooth(duration: 0.75)){\n                        showDot = false\n                    }\n                    withAnimation(.default){\n                        isProcessing = true\n                        isPulsing = false\n                    }\n                }\n            } label: {\n                ZStack{\n                    RoundedRectangle(cornerRadius: isRecording ? 8 : 45, style:.continuous)\n                        .fill(.red.gradient)\n                        .frame(width:isRecording ? 40 : 85, height:isRecording ? 40 : 85)\n                        .opacity(isProcessing ? 0 : 1)\n                    if isRecording {\n                        ProgressView()\n                            .opacity(isProcessing ? 1.0 : 0)\n                            .tint(.primary)\n                            .colorInvert()\n                    } else {\n                        Image(systemName: \"waveform\")\n                            .font(.title)\n                            .foregroundColor(.white)\n                            .transition(.scale)\n                    }\n                    \n                }\n            }\n            .buttonStyle(RecordButton())\n            .disabled(isProcessing ? true : false)\n        }\n    }\n\n    func stopTimer() {\n        self.timer.upstream.connect().cancel()\n    }\n    \n    func startTimer() {\n        self.timer = Timer.publish(every: 00.01, on: .main, in: .common).autoconnect()\n    }\n}\n\n\n#Preview {\n    TranscriberView(transcriberManager: TranscriberManager())\n}\n"
  },
  {
    "path": "Demos/Transcriber/Transcriber.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 56;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t0DA9CE802B51186E000D047E /* TranscribedAudioRecording.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DA9CE7F2B51186E000D047E /* TranscribedAudioRecording.swift */; };\n\t\t0DA9CE822B51193D000D047E /* AudioRecording.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DA9CE812B51193D000D047E /* AudioRecording.swift */; };\n\t\t0DDD239A2B4DE36300B2AE5C /* TranscriberApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD23992B4DE36300B2AE5C /* TranscriberApp.swift */; };\n\t\t0DDD239E2B4DE36400B2AE5C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0DDD239D2B4DE36400B2AE5C /* Assets.xcassets */; };\n\t\t0DDD23A12B4DE36400B2AE5C /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0DDD23A02B4DE36400B2AE5C /* Preview Assets.xcassets */; };\n\t\t0DDD24232B4DEF8E00B2AE5C /* TranscriberView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD241B2B4DEF8E00B2AE5C /* TranscriberView.swift */; };\n\t\t0DDD24242B4DEF8E00B2AE5C /* MicrophoneSampleVendor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD241C2B4DEF8E00B2AE5C /* MicrophoneSampleVendor.swift */; };\n\t\t0DDD24252B4DEF8E00B2AE5C /* AudioRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD241D2B4DEF8E00B2AE5C /* AudioRecorder.swift */; };\n\t\t0DDD24262B4DEF8E00B2AE5C /* TranscriberDataLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD241E2B4DEF8E00B2AE5C /* TranscriberDataLoader.swift */; };\n\t\t0DDD24272B4DEF8E00B2AE5C /* AudioFileWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD241F2B4DEF8E00B2AE5C /* AudioFileWriter.swift */; };\n\t\t0DDD24282B4DEF8E00B2AE5C /* NoRecordingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD24202B4DEF8E00B2AE5C /* NoRecordingsView.swift */; };\n\t\t0DDD24292B4DEF8E00B2AE5C /* TranscriberManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD24212B4DEF8E00B2AE5C /* TranscriberManager.swift */; };\n\t\t0DDD242A2B4DEF8E00B2AE5C /* RecordingRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD24222B4DEF8E00B2AE5C /* RecordingRowView.swift */; };\n\t\t0DDD242D2B4DEF9C00B2AE5C /* AppConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD242B2B4DEF9C00B2AE5C /* AppConstants.swift */; };\n\t\t0DDD242E2B4DEF9C00B2AE5C /* AppLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD242C2B4DEF9C00B2AE5C /* AppLogger.swift */; };\n\t\t0DDD24302B4DEFB100B2AE5C /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD242F2B4DEFB100B2AE5C /* FileUtils.swift */; };\n\t\t0DDD24322B4DEFC700B2AE5C /* ButtonStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD24312B4DEFC700B2AE5C /* ButtonStyles.swift */; };\n\t\t0DDD24742B4DF1DF00B2AE5C /* ModelContext+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD24732B4DF1DF00B2AE5C /* ModelContext+Extensions.swift */; };\n\t\t2CE7709E2C9B83F500EC6C74 /* AIProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 2CE7709D2C9B83F500EC6C74 /* AIProxy */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t0DA9CE7F2B51186E000D047E /* TranscribedAudioRecording.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranscribedAudioRecording.swift; sourceTree = \"<group>\"; };\n\t\t0DA9CE812B51193D000D047E /* AudioRecording.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRecording.swift; sourceTree = \"<group>\"; };\n\t\t0DDD23962B4DE36300B2AE5C /* Transcriber.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Transcriber.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t0DDD23992B4DE36300B2AE5C /* TranscriberApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranscriberApp.swift; sourceTree = \"<group>\"; };\n\t\t0DDD239D2B4DE36400B2AE5C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t0DDD23A02B4DE36400B2AE5C /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = \"Preview Assets.xcassets\"; sourceTree = \"<group>\"; };\n\t\t0DDD241B2B4DEF8E00B2AE5C /* TranscriberView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TranscriberView.swift; sourceTree = \"<group>\"; };\n\t\t0DDD241C2B4DEF8E00B2AE5C /* MicrophoneSampleVendor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MicrophoneSampleVendor.swift; sourceTree = \"<group>\"; };\n\t\t0DDD241D2B4DEF8E00B2AE5C /* AudioRecorder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioRecorder.swift; sourceTree = \"<group>\"; };\n\t\t0DDD241E2B4DEF8E00B2AE5C /* TranscriberDataLoader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TranscriberDataLoader.swift; sourceTree = \"<group>\"; };\n\t\t0DDD241F2B4DEF8E00B2AE5C /* AudioFileWriter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioFileWriter.swift; sourceTree = \"<group>\"; };\n\t\t0DDD24202B4DEF8E00B2AE5C /* NoRecordingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoRecordingsView.swift; sourceTree = \"<group>\"; };\n\t\t0DDD24212B4DEF8E00B2AE5C /* TranscriberManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TranscriberManager.swift; sourceTree = \"<group>\"; };\n\t\t0DDD24222B4DEF8E00B2AE5C /* RecordingRowView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecordingRowView.swift; sourceTree = \"<group>\"; };\n\t\t0DDD242B2B4DEF9C00B2AE5C /* AppConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppConstants.swift; sourceTree = \"<group>\"; };\n\t\t0DDD242C2B4DEF9C00B2AE5C /* AppLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppLogger.swift; sourceTree = \"<group>\"; };\n\t\t0DDD242F2B4DEFB100B2AE5C /* FileUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileUtils.swift; sourceTree = \"<group>\"; };\n\t\t0DDD24312B4DEFC700B2AE5C /* ButtonStyles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ButtonStyles.swift; sourceTree = \"<group>\"; };\n\t\t0DDD24732B4DF1DF00B2AE5C /* ModelContext+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = \"ModelContext+Extensions.swift\"; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t0DDD23932B4DE36300B2AE5C /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2CE7709E2C9B83F500EC6C74 /* AIProxy in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t0DDD238D2B4DE36300B2AE5C = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0DDD23982B4DE36300B2AE5C /* Transcriber */,\n\t\t\t\t0DDD23972B4DE36300B2AE5C /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0DDD23972B4DE36300B2AE5C /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0DDD23962B4DE36300B2AE5C /* Transcriber.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0DDD23982B4DE36300B2AE5C /* Transcriber */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0DDD242B2B4DEF9C00B2AE5C /* AppConstants.swift */,\n\t\t\t\t0DDD242C2B4DEF9C00B2AE5C /* AppLogger.swift */,\n\t\t\t\t0DDD241F2B4DEF8E00B2AE5C /* AudioFileWriter.swift */,\n\t\t\t\t0DDD241D2B4DEF8E00B2AE5C /* AudioRecorder.swift */,\n\t\t\t\t0DA9CE812B51193D000D047E /* AudioRecording.swift */,\n\t\t\t\t0DDD24312B4DEFC700B2AE5C /* ButtonStyles.swift */,\n\t\t\t\t0DDD242F2B4DEFB100B2AE5C /* FileUtils.swift */,\n\t\t\t\t0DDD241C2B4DEF8E00B2AE5C /* MicrophoneSampleVendor.swift */,\n\t\t\t\t0DDD24732B4DF1DF00B2AE5C /* ModelContext+Extensions.swift */,\n\t\t\t\t0DDD24202B4DEF8E00B2AE5C /* NoRecordingsView.swift */,\n\t\t\t\t0DDD24222B4DEF8E00B2AE5C /* RecordingRowView.swift */,\n\t\t\t\t0DA9CE7F2B51186E000D047E /* TranscribedAudioRecording.swift */,\n\t\t\t\t0DDD23992B4DE36300B2AE5C /* TranscriberApp.swift */,\n\t\t\t\t0DDD241E2B4DEF8E00B2AE5C /* TranscriberDataLoader.swift */,\n\t\t\t\t0DDD24212B4DEF8E00B2AE5C /* TranscriberManager.swift */,\n\t\t\t\t0DDD241B2B4DEF8E00B2AE5C /* TranscriberView.swift */,\n\t\t\t\t0DDD239D2B4DE36400B2AE5C /* Assets.xcassets */,\n\t\t\t\t0DDD239F2B4DE36400B2AE5C /* Preview Content */,\n\t\t\t);\n\t\t\tpath = Transcriber;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0DDD239F2B4DE36400B2AE5C /* Preview Content */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0DDD23A02B4DE36400B2AE5C /* Preview Assets.xcassets */,\n\t\t\t);\n\t\t\tpath = \"Preview Content\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t0DDD23952B4DE36300B2AE5C /* Transcriber */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 0DDD23A42B4DE36400B2AE5C /* Build configuration list for PBXNativeTarget \"Transcriber\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t0DDD23922B4DE36300B2AE5C /* Sources */,\n\t\t\t\t0DDD23932B4DE36300B2AE5C /* Frameworks */,\n\t\t\t\t0DDD23942B4DE36300B2AE5C /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = Transcriber;\n\t\t\tpackageProductDependencies = (\n\t\t\t\t2CE7709D2C9B83F500EC6C74 /* AIProxy */,\n\t\t\t);\n\t\t\tproductName = Transcriber;\n\t\t\tproductReference = 0DDD23962B4DE36300B2AE5C /* Transcriber.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t0DDD238E2B4DE36300B2AE5C /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = 1;\n\t\t\t\tLastSwiftUpdateCheck = 1510;\n\t\t\t\tLastUpgradeCheck = 1510;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t0DDD23952B4DE36300B2AE5C = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 15.1;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 0DDD23912B4DE36300B2AE5C /* Build configuration list for PBXProject \"Transcriber\" */;\n\t\t\tcompatibilityVersion = \"Xcode 14.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 0DDD238D2B4DE36300B2AE5C;\n\t\t\tpackageReferences = (\n\t\t\t\t2CE7709C2C9B83F500EC6C74 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */,\n\t\t\t);\n\t\t\tproductRefGroup = 0DDD23972B4DE36300B2AE5C /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t0DDD23952B4DE36300B2AE5C /* Transcriber */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t0DDD23942B4DE36300B2AE5C /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t0DDD23A12B4DE36400B2AE5C /* Preview Assets.xcassets in Resources */,\n\t\t\t\t0DDD239E2B4DE36400B2AE5C /* Assets.xcassets in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t0DDD23922B4DE36300B2AE5C /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t0DDD24282B4DEF8E00B2AE5C /* NoRecordingsView.swift in Sources */,\n\t\t\t\t0DDD24292B4DEF8E00B2AE5C /* TranscriberManager.swift in Sources */,\n\t\t\t\t0DDD24232B4DEF8E00B2AE5C /* TranscriberView.swift in Sources */,\n\t\t\t\t0DDD24302B4DEFB100B2AE5C /* FileUtils.swift in Sources */,\n\t\t\t\t0DA9CE802B51186E000D047E /* TranscribedAudioRecording.swift in Sources */,\n\t\t\t\t0DDD24242B4DEF8E00B2AE5C /* MicrophoneSampleVendor.swift in Sources */,\n\t\t\t\t0DDD242A2B4DEF8E00B2AE5C /* RecordingRowView.swift in Sources */,\n\t\t\t\t0DDD24252B4DEF8E00B2AE5C /* AudioRecorder.swift in Sources */,\n\t\t\t\t0DDD24742B4DF1DF00B2AE5C /* ModelContext+Extensions.swift in Sources */,\n\t\t\t\t0DDD24322B4DEFC700B2AE5C /* ButtonStyles.swift in Sources */,\n\t\t\t\t0DDD239A2B4DE36300B2AE5C /* TranscriberApp.swift in Sources */,\n\t\t\t\t0DDD24262B4DEF8E00B2AE5C /* TranscriberDataLoader.swift in Sources */,\n\t\t\t\t0DDD24272B4DEF8E00B2AE5C /* AudioFileWriter.swift in Sources */,\n\t\t\t\t0DDD242E2B4DEF9C00B2AE5C /* AppLogger.swift in Sources */,\n\t\t\t\t0DA9CE822B51193D000D047E /* AudioRecording.swift in Sources */,\n\t\t\t\t0DDD242D2B4DEF9C00B2AE5C /* AppConstants.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t0DDD23A22B4DE36400B2AE5C /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.2;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"DEBUG $(inherited)\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t0DDD23A32B4DE36400B2AE5C /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.2;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t0DDD23A52B4DE36400B2AE5C /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"Transcriber/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 9557YJ9D37;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_NSMicrophoneUsageDescription = \"The microphone is required to create audio recordings\";\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.2;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.aiproxy.bootstrap.transcriber;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t0DDD23A62B4DE36400B2AE5C /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"Transcriber/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 9557YJ9D37;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_NSMicrophoneUsageDescription = \"The microphone is required to create audio recordings\";\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.2;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.aiproxy.bootstrap.transcriber;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t0DDD23912B4DE36300B2AE5C /* Build configuration list for PBXProject \"Transcriber\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t0DDD23A22B4DE36400B2AE5C /* Debug */,\n\t\t\t\t0DDD23A32B4DE36400B2AE5C /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t0DDD23A42B4DE36400B2AE5C /* Build configuration list for PBXNativeTarget \"Transcriber\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t0DDD23A52B4DE36400B2AE5C /* Debug */,\n\t\t\t\t0DDD23A62B4DE36400B2AE5C /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCRemoteSwiftPackageReference section */\n\t\t2CE7709C2C9B83F500EC6C74 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/lzell/AIProxySwift\";\n\t\t\trequirement = {\n\t\t\t\tbranch = main;\n\t\t\t\tkind = branch;\n\t\t\t};\n\t\t};\n/* End XCRemoteSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */\n\t\t2CE7709D2C9B83F500EC6C74 /* AIProxy */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 2CE7709C2C9B83F500EC6C74 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */;\n\t\t\tproductName = AIProxy;\n\t\t};\n/* End XCSwiftPackageProductDependency section */\n\t};\n\trootObject = 0DDD238E2B4DE36300B2AE5C /* Project object */;\n}\n"
  },
  {
    "path": "Demos/Translator/Translator/AppConstants.swift",
    "content": "//\n//  AppConstants.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport AIProxy\n\nenum AppConstants {\n    #error(\n        \"\"\"\n        Uncomment one of the methods below. To build and run on device you must follow the AIProxy integration guide.\n        Please see https://www.aiproxy.pro/docs/integration-guide.html\")\n        \"\"\"\n    )\n    \n    /* Uncomment for BYOK use cases */\n    static let openAIService = AIProxy.openAIDirectService(\n        unprotectedAPIKey: \"your-openai-key\"\n    )\n\n    /* Uncomment for all other production use cases */\n//    let openAIService = AIProxy.openAIService(\n//        partialKey: \"partial-key-from-your-developer-dashboard\",\n//        serviceURL: \"service-url-from-your-developer-dashboard\"\n//    )\n}\n"
  },
  {
    "path": "Demos/Translator/Translator/AppLogger.swift",
    "content": "//\n//  AppLogger.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport OSLog\n\n/// Log levels available:\n///\n///     AppLogger.debug\n///     AppLogger.info\n///     AppLogger.warning\n///     AppLogger.error\n///     AppLogger.critical\n///\n/// Flip on metadata logging in Xcode's console to show which source line the log occurred from.\n///\n/// See my reddit post for a video instructions:\n/// https://www.reddit.com/r/SwiftUI/comments/15lsdtk/how_to_use_the_oslog_logger/\nlet AppLogger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"UnknownApp\",\n                       category: \"AIProxyBootstrapTranslator\")\n"
  },
  {
    "path": "Demos/Translator/Translator/Assets.xcassets/AccentColor.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/Translator/Translator/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"translate.png\",\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/Translator/Translator/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/Translator/Translator/BottomTranslateView.swift",
    "content": "//\n//  BottomTranslateView.swift\n//  AIProxyBootstrap\n//\n//  Created by Todd Hamilton\n//\n\nimport SwiftUI\n\nstruct BottomTranslateView: View {\n\n    @Binding var processing:Bool\n    @Binding var translatedText:String\n\n    var body: some View {\n        VStack{\n\n            VStack(alignment:.leading, spacing:8){\n                Text(\"Spanish\")\n                    .font(.callout)\n                    .foregroundColor(.secondary)\n                if processing {\n                    ProgressView()\n                        .frame(maxWidth: .infinity, maxHeight:.infinity)\n                } else{\n                    Text(translatedText)\n                        .font(.title2)\n                }\n            }\n            .frame(maxWidth: .infinity, maxHeight:.infinity, alignment:.topLeading)\n\n\n            HStack(spacing:0){\n                Button(){\n                    /// copy result\n                } label:{\n                    Image(systemName: \"square.on.square\")\n                        .font(.title2)\n                }\n                .frame(width:44, height:44)\n            }\n            .frame(maxWidth: .infinity, alignment:.leading)\n        }\n        .frame(maxWidth: .infinity, maxHeight:.infinity)\n        .padding(16)\n        .background(\n            RoundedRectangle(cornerRadius: 14, style: .continuous)\n                .fill(Color(.tertiarySystemBackground))\n                .shadow(color:.black.opacity(0.14), radius: 1)\n        )\n    }\n}\n\n\n#Preview {\n    BottomTranslateView(processing: .constant(false), translatedText: .constant(\"\"))\n}\n"
  },
  {
    "path": "Demos/Translator/Translator/ButtonStyles.swift",
    "content": "//\n//  ButtonStyles.swift\n//  AIProxyBootstrap\n//\n//  Created by Todd Hamilton\n//\n\nimport SwiftUI\n\nstruct ButtonStyles: View {\n    var body: some View {\n        \n        ZStack{\n            Color(.systemGroupedBackground)\n                .ignoresSafeArea()\n            \n            VStack(spacing:48){\n                \n                Button{\n                    /// do something\n                }label:{\n                    HStack(spacing:6){\n                        Image(systemName: \"play.circle.fill\")\n                            .font(.system(size: 15, weight:.semibold, design: .rounded))\n                        Text(\"10s\")\n                            .font(.system(size: 11, weight: .regular, design: .monospaced))\n                            .fontDesign(.monospaced)\n                    }\n                }\n                .buttonStyle(TranscriptionButtonStyle())\n\n                Button(){\n                    /// do something\n                } label:{\n                    Label(\"Chunky Button\", systemImage: \"sparkles\")\n                }\n                .buttonStyle(ChunkyButtonStyle(offsetSize: 10.0))\n\n                Button{\n                    /// do something\n                } label: {\n                    ZStack{\n                        RoundedRectangle(cornerRadius: 45, style:.continuous)\n                            .fill(.red.gradient)\n                            .frame(width:85, height:85)\n                        Image(systemName: \"waveform\")\n                            .font(.title)\n                            .foregroundColor(.white)\n                    }\n                }\n                .buttonStyle(RecordButton())\n                \n                Button(){\n                    /// do something\n                }label:{\n                    HStack(spacing:4){\n                        Text(\"Translate\")\n                        Image(systemName: \"arrow.forward\")\n                    }\n                }\n                .buttonStyle(TranslateButton())\n                \n            }\n            .padding()\n        }\n        \n    }\n}\n\nstruct ChunkyButtonStyle: ButtonStyle {\n\n    var offsetSize = 10.0\n\n    func makeBody(configuration: Configuration) -> some View {\n        configuration.label\n            .font(.system(size: 24, weight: .bold, design: .rounded))\n            .foregroundColor(.black)\n            .padding()\n            .offset(y: configuration.isPressed ? offsetSize-2 : 0)\n            .background(\n                GeometryReader{ geo in\n                    RoundedRectangle(cornerRadius: 17)\n                        .strokeBorder(Color.black, lineWidth: 4)\n                        .background(\n                            RoundedRectangle(cornerRadius: 17)\n                                .fill(.white)\n                        )\n                        .offset(y:offsetSize)\n\n                        .overlay(\n                            RoundedRectangle(cornerRadius: 17)\n                                .fill(.white)\n                                .strokeBorder(Color.black, lineWidth: 4)\n                                .background(RoundedRectangle(cornerRadius: 17).fill(Color.white))\n                                .offset(y: configuration.isPressed ? offsetSize : 0)\n                        )\n                }\n            )\n    }\n}\n\nstruct RecordButton: ButtonStyle {\n    func makeBody(configuration: Configuration) -> some View {\n        configuration.label\n            .frame(maxWidth:80, maxHeight: 80)\n            .shadow(color:.black.opacity(0.28), radius: 10, y:8)\n            .scaleEffect(configuration.isPressed ? 0.9 : 1, anchor: .center)\n            .animation(.easeOut(duration: 0.2), value: configuration.isPressed)\n            .padding(.bottom, 40)\n            \n    }\n}\n\nstruct TranslateButton: ButtonStyle {\n    func makeBody(configuration: Configuration) -> some View {\n        configuration.label\n            .foregroundColor(.white)\n            .padding(.vertical, 12)\n            .padding(.horizontal, 16)\n            .font(.system(size: 13, weight: .bold, design: .rounded))\n            .background(.teal.gradient)\n            .clipShape(Capsule())\n            .brightness(configuration.isPressed ? -0.1 : 0.0)\n            .scaleEffect(configuration.isPressed ? 0.9 : 1, anchor: .center)\n    }\n}\n\nstruct TranscriptionButtonStyle: ButtonStyle {\n\n    func makeBody(configuration: Configuration) -> some View {\n        configuration.label\n            .foregroundColor(.secondary)\n            .padding(.leading, 4)\n            .padding(.trailing, 8)\n            .padding(.vertical, 4)\n            .background(\n                Capsule().fill(.secondary.opacity(configuration.isPressed ? 0.28 : 0.14))\n            )\n            .scaleEffect(configuration.isPressed ? 0.9 : 1.0)\n    }\n}\n\n#Preview {\n    ButtonStyles()\n}\n"
  },
  {
    "path": "Demos/Translator/Translator/Preview Content/Preview Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/Translator/Translator/TopTranslateView.swift",
    "content": "//\n//  TopTranslateView.swift\n//  AIProxyBootstrap\n//\n//  Created by Todd Hamilton\n//\n\nimport SwiftUI\n\nstruct TopTranslateView: View {\n\n    @Binding var newText:String\n    @Binding var translatedText:String\n    @State private var showButton: Bool = false\n    var translate: () -> Void\n\n    var body: some View {\n        VStack(alignment:.leading){\n            Text(\"English\")\n                .font(.callout)\n                .foregroundColor(.secondary)\n            TextField(\"Type something...\", text: $newText, axis: .vertical)\n                .font(.title2)\n                .lineLimit(...2)\n                .textFieldStyle(.plain)\n                .frame(maxHeight: .infinity, alignment:.topLeading)\n                .onChange(of: newText) { _, newValue in\n                    withAnimation(.bouncy){\n                        if !newValue.isEmpty {\n                            showButton = true\n                        } else {\n                            showButton = false\n                        }\n                    }\n                }\n\n            if showButton {\n                HStack(alignment:.bottom){\n                    Button{\n                        newText = \"\"\n                        translatedText = \"\"\n                        showButton = false\n                    } label:{\n                        Text(\"Clear\")\n                    }\n\n                    Spacer()\n\n                    Button{\n                        self.translate()\n                    }label:{\n                        HStack(spacing:4){\n                            Text(\"Translate\")\n                            Image(systemName: \"arrow.forward\")\n                        }\n                    }\n                    .buttonStyle(TranslateButton())\n                }\n                .transition(.opacity)\n            }\n        }\n        .frame(maxWidth: .infinity)\n        .padding(16)\n        .background(\n            RoundedRectangle(cornerRadius: 14, style: .continuous)\n                .fill(Color(.tertiarySystemBackground))\n                .shadow(color:.black.opacity(0.14), radius: 1)\n        )\n    }\n}\n\n#Preview {\n    TopTranslateView(newText: .constant(\"\"), translatedText: .constant(\"\"), translate: {})\n}\n"
  },
  {
    "path": "Demos/Translator/Translator/TranslateView.swift",
    "content": "//\n//  TranslateView.swift\n//  AIProxyBootstrap\n//\n//  Created by Todd Hamilton\n//\n\nimport SwiftUI\n\n@MainActor\nstruct TranslateView: View {\n\n    @State private var newText:String = \"\"\n    @State private var translatedText:String = \"\"\n    @State private var processing:Bool = false\n    \n    private let prompt = \"The response is an exact translation from english to spanish. You don't respond with any english.\"\n\n    var body: some View {\n        ZStack{\n            Color(.systemGroupedBackground)\n                .ignoresSafeArea()\n            \n            VStack{\n                TopTranslateView(\n                    newText: $newText,\n                    translatedText: $translatedText,\n                    translate: { self.translate() }\n                )\n                BottomTranslateView(\n                    processing: $processing,\n                    translatedText: $translatedText\n                )\n            }\n            .padding()\n        }\n    }\n\n    func translate(){\n        withAnimation(.smooth){\n            processing = true\n        }\n        Task {\n            translatedText = await TranslationDataLoader.run(on: self.newText)\n            withAnimation(.smooth){\n                processing = false\n            }\n        }\n    }\n}\n\n#Preview {\n    TranslateView()\n}\n"
  },
  {
    "path": "Demos/Translator/Translator/TranslationDataLoader.swift",
    "content": "//\n//  Translator.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\n\nprivate let prompt = \"The response is an exact translation from english to spanish. You don't respond with any english.\"\n\n/// Interfaces with OpenAI to translate input text from english to spanish\nstruct TranslationDataLoader {\n    private init() {\n        fatalError(\"Translator is a namespace only\")\n    }\n    \n    /// Translate `input` from english to spanish\n    /// - Parameter input: the english input\n    /// - Returns: the spanish translation\n    static func run(on input: String) async -> String {\n        do {\n            let response = try await AppConstants.openAIService.chatCompletionRequest(body: .init(\n                model: \"gpt-4o\",\n                messages: [\n                    .system(content: .text(prompt)),\n                    .user(content: .text(input))\n                ]\n            ))\n            if let text = response.choices.first?.message.content {\n                return text\n            }\n        } catch {\n            AppLogger.error(\"Could not translate using gpt4o: \\(error)\")\n        }\n        return \"Translation failed!\"\n    }\n}\n"
  },
  {
    "path": "Demos/Translator/Translator/TranslatorApp.swift",
    "content": "//\n//  TranslatorApp.swift\n//  Translator\n//\n//  Created by Lou Zell\n//\n\nimport SwiftUI\n\n@main\nstruct TranslatorApp: App {\n    var body: some Scene {\n        WindowGroup {\n            TranslateView()\n        }\n    }\n}\n"
  },
  {
    "path": "Demos/Translator/Translator.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 56;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t0DDD23802B4DE34F00B2AE5C /* TranslatorApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD237F2B4DE34F00B2AE5C /* TranslatorApp.swift */; };\n\t\t0DDD23842B4DE35000B2AE5C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0DDD23832B4DE35000B2AE5C /* Assets.xcassets */; };\n\t\t0DDD23872B4DE35000B2AE5C /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0DDD23862B4DE35000B2AE5C /* Preview Assets.xcassets */; };\n\t\t0DDD243C2B4DF06A00B2AE5C /* TopTranslateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD24372B4DF06A00B2AE5C /* TopTranslateView.swift */; };\n\t\t0DDD243D2B4DF06A00B2AE5C /* BottomTranslateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD24382B4DF06A00B2AE5C /* BottomTranslateView.swift */; };\n\t\t0DDD243F2B4DF06A00B2AE5C /* TranslateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD243A2B4DF06A00B2AE5C /* TranslateView.swift */; };\n\t\t0DDD24422B4DF07600B2AE5C /* AppLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD24402B4DF07600B2AE5C /* AppLogger.swift */; };\n\t\t0DDD24432B4DF07600B2AE5C /* AppConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD24412B4DF07600B2AE5C /* AppConstants.swift */; };\n\t\t0DDD24482B4DF0DD00B2AE5C /* ButtonStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD24472B4DF0DD00B2AE5C /* ButtonStyles.swift */; };\n\t\t2CE7708D2C9B37A600EC6C74 /* AIProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 2CE7708C2C9B37A600EC6C74 /* AIProxy */; };\n\t\t2CE770922C9B459F00EC6C74 /* TranslationDataLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE770912C9B459800EC6C74 /* TranslationDataLoader.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t0DDD237C2B4DE34F00B2AE5C /* Translator.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Translator.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t0DDD237F2B4DE34F00B2AE5C /* TranslatorApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranslatorApp.swift; sourceTree = \"<group>\"; };\n\t\t0DDD23832B4DE35000B2AE5C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t0DDD23862B4DE35000B2AE5C /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = \"Preview Assets.xcassets\"; sourceTree = \"<group>\"; };\n\t\t0DDD24372B4DF06A00B2AE5C /* TopTranslateView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopTranslateView.swift; sourceTree = \"<group>\"; };\n\t\t0DDD24382B4DF06A00B2AE5C /* BottomTranslateView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BottomTranslateView.swift; sourceTree = \"<group>\"; };\n\t\t0DDD243A2B4DF06A00B2AE5C /* TranslateView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TranslateView.swift; sourceTree = \"<group>\"; };\n\t\t0DDD24402B4DF07600B2AE5C /* AppLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppLogger.swift; sourceTree = \"<group>\"; };\n\t\t0DDD24412B4DF07600B2AE5C /* AppConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppConstants.swift; sourceTree = \"<group>\"; };\n\t\t0DDD24472B4DF0DD00B2AE5C /* ButtonStyles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ButtonStyles.swift; sourceTree = \"<group>\"; };\n\t\t2CE770912C9B459800EC6C74 /* TranslationDataLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranslationDataLoader.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t0DDD23792B4DE34F00B2AE5C /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2CE7708D2C9B37A600EC6C74 /* AIProxy in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t0DDD23732B4DE34F00B2AE5C = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0DDD237E2B4DE34F00B2AE5C /* Translator */,\n\t\t\t\t0DDD237D2B4DE34F00B2AE5C /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0DDD237D2B4DE34F00B2AE5C /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0DDD237C2B4DE34F00B2AE5C /* Translator.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0DDD237E2B4DE34F00B2AE5C /* Translator */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0DDD24412B4DF07600B2AE5C /* AppConstants.swift */,\n\t\t\t\t0DDD24402B4DF07600B2AE5C /* AppLogger.swift */,\n\t\t\t\t0DDD24382B4DF06A00B2AE5C /* BottomTranslateView.swift */,\n\t\t\t\t0DDD24472B4DF0DD00B2AE5C /* ButtonStyles.swift */,\n\t\t\t\t0DDD24372B4DF06A00B2AE5C /* TopTranslateView.swift */,\n\t\t\t\t0DDD243A2B4DF06A00B2AE5C /* TranslateView.swift */,\n\t\t\t\t2CE770912C9B459800EC6C74 /* TranslationDataLoader.swift */,\n\t\t\t\t0DDD237F2B4DE34F00B2AE5C /* TranslatorApp.swift */,\n\t\t\t\t0DDD23832B4DE35000B2AE5C /* Assets.xcassets */,\n\t\t\t\t0DDD23852B4DE35000B2AE5C /* Preview Content */,\n\t\t\t);\n\t\t\tpath = Translator;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0DDD23852B4DE35000B2AE5C /* Preview Content */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0DDD23862B4DE35000B2AE5C /* Preview Assets.xcassets */,\n\t\t\t);\n\t\t\tpath = \"Preview Content\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t0DDD237B2B4DE34F00B2AE5C /* Translator */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 0DDD238A2B4DE35000B2AE5C /* Build configuration list for PBXNativeTarget \"Translator\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t0DDD23782B4DE34F00B2AE5C /* Sources */,\n\t\t\t\t0DDD23792B4DE34F00B2AE5C /* Frameworks */,\n\t\t\t\t0DDD237A2B4DE34F00B2AE5C /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = Translator;\n\t\t\tpackageProductDependencies = (\n\t\t\t\t2CE7708C2C9B37A600EC6C74 /* AIProxy */,\n\t\t\t);\n\t\t\tproductName = Translator;\n\t\t\tproductReference = 0DDD237C2B4DE34F00B2AE5C /* Translator.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t0DDD23742B4DE34F00B2AE5C /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = 1;\n\t\t\t\tLastSwiftUpdateCheck = 1510;\n\t\t\t\tLastUpgradeCheck = 1510;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t0DDD237B2B4DE34F00B2AE5C = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 15.1;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 0DDD23772B4DE34F00B2AE5C /* Build configuration list for PBXProject \"Translator\" */;\n\t\t\tcompatibilityVersion = \"Xcode 14.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 0DDD23732B4DE34F00B2AE5C;\n\t\t\tpackageReferences = (\n\t\t\t\t2CE7708B2C9B37A600EC6C74 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */,\n\t\t\t);\n\t\t\tproductRefGroup = 0DDD237D2B4DE34F00B2AE5C /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t0DDD237B2B4DE34F00B2AE5C /* Translator */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t0DDD237A2B4DE34F00B2AE5C /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t0DDD23872B4DE35000B2AE5C /* Preview Assets.xcassets in Resources */,\n\t\t\t\t0DDD23842B4DE35000B2AE5C /* Assets.xcassets in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t0DDD23782B4DE34F00B2AE5C /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t0DDD243C2B4DF06A00B2AE5C /* TopTranslateView.swift in Sources */,\n\t\t\t\t0DDD243F2B4DF06A00B2AE5C /* TranslateView.swift in Sources */,\n\t\t\t\t2CE770922C9B459F00EC6C74 /* TranslationDataLoader.swift in Sources */,\n\t\t\t\t0DDD23802B4DE34F00B2AE5C /* TranslatorApp.swift in Sources */,\n\t\t\t\t0DDD24432B4DF07600B2AE5C /* AppConstants.swift in Sources */,\n\t\t\t\t0DDD24482B4DF0DD00B2AE5C /* ButtonStyles.swift in Sources */,\n\t\t\t\t0DDD243D2B4DF06A00B2AE5C /* BottomTranslateView.swift in Sources */,\n\t\t\t\t0DDD24422B4DF07600B2AE5C /* AppLogger.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t0DDD23882B4DE35000B2AE5C /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.2;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"DEBUG $(inherited)\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t0DDD23892B4DE35000B2AE5C /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.2;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t0DDD238B2B4DE35000B2AE5C /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"Translator/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 9557YJ9D37;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.aiproxy.bootstrap.translator;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t0DDD238C2B4DE35000B2AE5C /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"Translator/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 9557YJ9D37;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.aiproxy.bootstrap.translator;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t0DDD23772B4DE34F00B2AE5C /* Build configuration list for PBXProject \"Translator\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t0DDD23882B4DE35000B2AE5C /* Debug */,\n\t\t\t\t0DDD23892B4DE35000B2AE5C /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t0DDD238A2B4DE35000B2AE5C /* Build configuration list for PBXNativeTarget \"Translator\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t0DDD238B2B4DE35000B2AE5C /* Debug */,\n\t\t\t\t0DDD238C2B4DE35000B2AE5C /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCRemoteSwiftPackageReference section */\n\t\t2CE7708B2C9B37A600EC6C74 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/lzell/AIProxySwift\";\n\t\t\trequirement = {\n\t\t\t\tbranch = main;\n\t\t\t\tkind = branch;\n\t\t\t};\n\t\t};\n/* End XCRemoteSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */\n\t\t2CE7708C2C9B37A600EC6C74 /* AIProxy */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 2CE7708B2C9B37A600EC6C74 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */;\n\t\t\tproductName = AIProxy;\n\t\t};\n/* End XCSwiftPackageProductDependency section */\n\t};\n\trootObject = 0DDD23742B4DE34F00B2AE5C /* Project object */;\n}\n"
  },
  {
    "path": "Demos/Trivia/Trivia/AppConstants.swift",
    "content": "//\n//  AppConstants.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport AIProxy\n\nenum AppConstants {\n    #error(\n        \"\"\"\n        Uncomment one of the methods below. To build and run on device you must follow the AIProxy integration guide.\n        Please see https://www.aiproxy.pro/docs/integration-guide.html\")\n        \"\"\"\n    )\n\n    /* Uncomment for BYOK use cases */\n    static let openAIService = AIProxy.openAIDirectService(\n        unprotectedAPIKey: \"your-openai-key\"\n    )\n\n    /* Uncomment for all other production use cases */\n//    let openAIService = AIProxy.openAIService(\n//        partialKey: \"partial-key-from-your-developer-dashboard\",\n//        serviceURL: \"service-url-from-your-developer-dashboard\"\n//    )\n}\n"
  },
  {
    "path": "Demos/Trivia/Trivia/AppLogger.swift",
    "content": "//\n//  AppLogger.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport OSLog\n\n/// Log levels available:\n///\n///     AppLogger.debug\n///     AppLogger.info\n///     AppLogger.warning\n///     AppLogger.error\n///     AppLogger.critical\n///\n/// Flip on metadata logging in Xcode's console to show which source line the log occurred from.\n///\n/// See my reddit post for a video instructions:\n/// https://www.reddit.com/r/SwiftUI/comments/15lsdtk/how_to_use_the_oslog_logger/\nlet AppLogger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"UnknownApp\",\n                       category: \"AIProxyBootstrapTrivia\")\n"
  },
  {
    "path": "Demos/Trivia/Trivia/Assets.xcassets/AccentColor.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/Trivia/Trivia/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"trivia.png\",\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/Trivia/Trivia/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/Trivia/Trivia/Preview Content/Preview Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Demos/Trivia/Trivia/TriviaAnswerPicker.swift",
    "content": "//\n//  TriviaAnswerPicker.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport SwiftUI\n\nstruct TriviaAnswerPicker: View {\n    /// Data model that holds the trivia question, potential answers, and correct answer index\n    let questionModel: TriviaQuestionModel\n\n    /// This question position in the stack of trivia cards\n    let questionNumber: Int\n\n    /// Number of questions in the stack of trivia cards\n    let questionOf: Int\n\n    /// The argument passed to this closure is the guessed answer index for comparison with `questionModel.correctAnswerIndex`\n    let didTapAnswer: (Int) -> Void\n\n\n    var body: some View {\n        VStack(alignment:.leading, spacing:36) {\n\n            VStack(alignment:.leading, spacing:16){\n                Text(\"Question \\(questionNumber) of \\(questionOf)\")\n                    .font(.system(size: 15, weight:.medium, design: .rounded))\n                    .foregroundColor(.secondary)\n\n                Text(questionModel.question)\n                    .font(.system(size: 20, weight:.medium, design: .rounded))\n                    .fixedSize(horizontal: false, vertical: true)\n            }\n            .frame(maxWidth: .infinity, alignment:.leading)\n\n            VStack(alignment:.leading, spacing:8){\n                ForEach(questionModel.labeledAnswers) { labeledAnswer in\n                    Text(labeledAnswer.text)\n                        .fixedSize(horizontal: false, vertical: true)\n                }\n            }\n            .font(.system(size: 17, weight:.medium, design: .rounded))\n            .frame(maxWidth: .infinity, alignment:.leading)\n\n            VStack{\n                HStack(spacing:8) {\n                    CardButton(systemImageName: \"a.circle.fill\", tint: .blue) {\n                        didTapAnswer(0)\n                    }\n\n                    CardButton(systemImageName: \"b.circle.fill\", tint: .mint) {\n                        didTapAnswer(1)\n                    }\n                }\n                HStack {\n                    CardButton(systemImageName: \"c.circle.fill\", tint: .green) {\n                        didTapAnswer(2)\n                    }\n\n                    CardButton(systemImageName: \"d.circle.fill\", tint: .indigo) {\n                        didTapAnswer(3)\n                    }\n                }\n            }\n            .buttonStyle(.bordered)\n            .font(.title)\n            .frame(maxWidth:.infinity, alignment:.leading)\n        }\n        .padding(16)\n    }\n}\n\nprivate struct CardButton: View {\n    let systemImageName: String\n    let tint: Color\n    let action: () -> Void\n\n    var body: some View {\n        Button(action: action) {\n            Image(systemName: systemImageName)\n                .frame(maxWidth: .infinity)\n        }\n        .tint(tint)\n        .controlSize(.large)\n    }\n}\n"
  },
  {
    "path": "Demos/Trivia/Trivia/TriviaApp.swift",
    "content": "//\n//  TriviaApp.swift\n//  Trivia\n//\n//  Created by Lou Zell\n//\n\nimport SwiftUI\n\n@main\nstruct TriviaApp: App {\n    var body: some Scene {\n        WindowGroup {\n            TriviaView()\n        }\n    }\n}\n"
  },
  {
    "path": "Demos/Trivia/Trivia/TriviaCardData.swift",
    "content": "//\n//  TriviaQuestion.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport SwiftUI\n\n@MainActor\n@Observable\n/// UI model for TriviaCardView\nfinal class TriviaCardData: Identifiable {\n\n    /// Position of the card, with 0 meaning that the card is on top and 1 meaning directly below the top card, etc.\n    let position: Int\n\n    /// Data model for the card contents\n    var triviaQuestionModel: TriviaQuestionModel?\n\n    /// Networker to load card contents from OpenAI\n    private let triviaFetcher: TriviaDataLoader\n\n    /// Creates a UI model for TriviaCardView\n    /// - Parameters:\n    ///   - triviaFetcher: Loads card contents from OpenAI\n    ///   - position: Position of the card, with 0 being the top of the stack\n    init(triviaFetcher: TriviaDataLoader, position: Int) {\n        self.triviaFetcher = triviaFetcher\n        self.position = position\n    }\n\n    /// Loads the trivia question's data model asynchronously\n    func load() async {\n        self.triviaQuestionModel = try! await self.triviaFetcher.getNextQuestion()\n    }\n}\n"
  },
  {
    "path": "Demos/Trivia/Trivia/TriviaCardView.swift",
    "content": "//\n//  QuizView.swift\n//  AIProxyBootstrap\n//\n//  Created by Todd Hamilton\n//\n\nimport Foundation\nimport SwiftUI\n\n@MainActor\nstruct TriviaCardView: View {\n\n    let triviaCardData: TriviaCardData\n    @Binding var triviaManager: TriviaManager?\n    @State var attempts: Int = 0\n    @State var isCorrect = false\n\n    private var questionNumber: Int {\n        triviaCardData.position + 1\n    }\n\n    private var totalQuestions: Int {\n        triviaManager?.triviaCards.count ?? 0\n    }\n\n    var body: some View{\n        ZStack {\n            if let model = triviaCardData.triviaQuestionModel {\n                ZStack {\n                    TriviaAnswerPicker(\n                        questionModel: model,\n                        questionNumber: questionNumber,\n                        questionOf: totalQuestions\n                    ) { guessIndex in\n                        checkAnswer(forQuestion: model, withGuessedIndex: guessIndex)\n                    }\n\n                    if self.isCorrect {\n                        Rectangle()\n                            .fill(.black.opacity(0.4))\n                            .frame(width: .infinity, height: .infinity)\n                            .transition(.opacity)\n                        Image(systemName: \"checkmark.circle.fill\")\n                            .font(.system(size: 64))\n                            .foregroundColor(.green)\n                            .background(.white)\n                            .clipShape(Circle())\n                            .transition(.scale(0.5).combined(with: .opacity))\n                    }\n                }\n            } else {\n                VStack(spacing:16) {\n                    ProgressView()\n                    Text(\"Generating questions\")\n                        .font(.system(size: 15, weight:.regular, design:.rounded))\n                        .foregroundColor(.secondary)\n                }\n                .frame(maxHeight:.infinity)\n            }\n        }\n        .frame(maxWidth: .infinity, maxHeight:480, alignment:.top)\n        .background(Color(.systemBackground))\n        .cornerRadius(14)\n        .shadow(color: .black.opacity(0.14), radius: 1, x: 0, y: 1)\n        .modifier(Shake(animatableData: CGFloat(attempts)))\n    }\n\n\n    private func checkAnswer(forQuestion question: TriviaQuestionModel, withGuessedIndex guessedIndex: Int) {\n        triviaManager?.trackGuess(ofQuestion: question)\n        if (question.correctAnswerIndex == guessedIndex) {\n            withAnimation(.bouncy){\n                isCorrect = true\n            }\n            Task {\n                try await Task.sleep(for: .seconds(1))\n                withAnimation(.bouncy) {\n                    triviaManager?.progress()\n                }\n            }\n        } else {\n            withAnimation(.default) {\n                attempts += 1\n            }\n        }\n    }\n}\n\n\nprivate struct Shake: GeometryEffect {\n    var amount: CGFloat = 10\n    var shakesPerUnit = 3\n    var animatableData: CGFloat\n\n    func effectValue(size: CGSize) -> ProjectionTransform {\n        ProjectionTransform(CGAffineTransform(translationX:\n            amount * sin(animatableData * .pi * CGFloat(shakesPerUnit)),\n            y: 0))\n    }\n}\n"
  },
  {
    "path": "Demos/Trivia/Trivia/TriviaDataLoader.swift",
    "content": "//\n//  TriviaFetcher.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport AIProxy\n\n// It's important to add the 'produce JSON' instruction to the system prompt.\n// See the note at https://platform.openai.com/docs/api-reference/chat/create#chat-create-response_format\nprivate let prompt = \"\"\"\nYou are a trivia bot that produces JSON. You ask hard questions with four possible answers. Specifying the index of the correct answer in the key `correct_answer_index`. Example response:\n{ question: \"xyz\", answers: [\"a\", \"b\", \"c\", \"d\"], correct_answer_index: 2 }\n\"\"\"\n\n/// Loads trivia data from openai\nfinal actor TriviaDataLoader {\n    /// The topic of trivia\n    let topic: String\n\n    /// Create the TriviaDataLoader responsible for fetching trivia data from OpenAI\n    /// - Parameter topic: The topic of trivia\n    init(topic: String) {\n        self.topic = topic\n    }\n\n    /// We store past questions, and send them back to openai on subsequent requests.\n    /// This prevents chat from asking the same questions\n    private var pastQuestions = [String]()\n\n    deinit {\n        AppLogger.debug(\"TriviaFetcher is being freed\")\n    }\n\n\n    /// Fetches the next trivia question from OpenAI over the network\n    /// - Returns: A TriviaQuestionModel containing one question and multiple choice answers\n    func getNextQuestion() async throws -> TriviaQuestionModel {\n        var messages = prompt\n        if self.pastQuestions.count > 0 {\n            let pastQuestionsList = self.pastQuestions.joined(separator: \"\\n\\n\")\n            messages += \"\\nDo not repeat any of these questions: \\(pastQuestionsList)\"\n        }\n\n        let requestBody = OpenAIChatCompletionRequestBody(\n            model: \"gpt-4o\",\n            messages: [\n                .system(content: .text(\"Ask me a question about: \\(topic)\")),\n                .user(content: .text(messages))\n            ],\n            responseFormat: .jsonObject\n        )\n        let response = try await AppConstants.openAIService.chatCompletionRequest(body: requestBody)\n\n        guard let text = response.choices.first?.message.content else {\n            throw TriviaFetcherError.couldNotFetchQuestion\n        }\n\n        let decoder = JSONDecoder()\n        decoder.keyDecodingStrategy = .convertFromSnakeCase\n\n        AppLogger.info(\"Received from openai: \\(text)\")\n        let model = try decoder.decode(TriviaQuestionModel.self, from: text.data(using: .utf8)!)\n        self.pastQuestions.append(model.question)\n        return model\n    }\n}\n\nenum TriviaFetcherError: Error {\n    case couldNotFetchQuestion\n}\n\nstruct TriviaQuestionModel: Decodable, Hashable {\n\n    struct LabeledAnswer: Identifiable {\n        let id = UUID()\n        let text: String\n    }\n\n    let question: String\n    let answers: [String]\n    let correctAnswerIndex: Int\n\n    var labeledAnswers: [LabeledAnswer] {\n        return zip([\"A\", \"B\", \"C\", \"D\"], self.answers).map {\n            LabeledAnswer(text: \"\\($0). \\($1)\")\n        }\n    }\n}\n"
  },
  {
    "path": "Demos/Trivia/Trivia/TriviaFormView.swift",
    "content": "//\n//  TriviaFormView.swift\n//  AIProxyBootstrap\n//\n//  Created by Todd Hamilton\n//\n\nimport SwiftUI\n\nstruct TriviaFormView:View{\n\n    enum FocusedField {\n        case topic\n    }\n\n    /// Topic entered by the user in a SwiftUI text field\n    @State private var topic = \"\"\n    @Binding var triviaManager: TriviaManager?\n    @FocusState private var focusedField: FocusedField?\n\n    var body: some View{\n\n        VStack(spacing:24){\n            VStack{\n                ZStack{\n                    Image(systemName: \"doc.questionmark.fill\")\n                        .foregroundColor(.blue)\n                        .rotationEffect(.degrees(-15))\n                    Image(systemName: \"doc.questionmark.fill\")\n                        .foregroundColor(.teal)\n                        .rotationEffect(.degrees(10))\n                    Image(systemName: \"doc.questionmark\")\n                        .foregroundColor(.white)\n                    Image(systemName: \"doc.questionmark.fill\")\n                        .overlay {\n                            LinearGradient(\n                                colors: [.orange, .red, .purple],\n                                startPoint: .topLeading,\n                                endPoint: .bottomTrailing\n                            )\n                            .mask(\n                                Image(systemName: \"doc.questionmark.fill\")\n                                    .font(.system(size: 72))\n                            )\n                        }\n                }\n                .font(.system(size: 72))\n                .padding(.vertical, 8)\n\n                Text(\"Trivia Generator\")\n                    .font(.system(size: 36, weight:.bold, design: .rounded))\n                    .multilineTextAlignment(.center)\n                Text(\"Type a trivia theme below\")\n                    .font(.system(size: 17, weight:.medium, design: .rounded))\n                    .foregroundColor(.secondary)\n            }\n\n            VStack{\n                TextField(\"Ex. 80's movies...\", text: $topic, axis: .vertical)\n                    .focused($focusedField, equals: .topic)\n                    .font(.system(size: 17, weight:.medium, design: .rounded))\n                    .lineLimit(...3)\n                    .textFieldStyle(.plain)\n                    .padding()\n                    .background(.white)\n                    .cornerRadius(8)\n                    .overlay(\n                        RoundedRectangle(cornerRadius: 8)\n                            .fill(.clear)\n                            .stroke(.separator)\n                    )\n                    .onAppear {\n                        focusedField = .topic\n                    }\n                Button{\n                    withAnimation(){\n                        triviaManager = TriviaManager(topic: topic, numCards: 5)\n                    }\n                }label:{\n                    Label(\"Generate\", systemImage: \"sparkles\")\n                        .frame(maxWidth:.infinity)\n                        .font(.system(size: 17, weight:.bold, design: .rounded))\n                        .fontWeight(.bold)\n                }\n                .buttonStyle(.borderedProminent)\n                .controlSize(.large)\n            }\n        }\n        .padding()\n    }\n}\n"
  },
  {
    "path": "Demos/Trivia/Trivia/TriviaManager.swift",
    "content": "//\n//  TriviaManager.swift\n//  AIProxyBootstrap\n//\n//  Created by Lou Zell\n//\n\nimport Foundation\nimport SwiftUI\n\n@MainActor\n@Observable\nfinal class TriviaManager {\n\n    /// The topic of trivia\n    let topic: String\n\n    /// The number of cards for the user to solve\n    let numCards: Int\n\n    /// All trivia cards\n    let triviaCards: [TriviaCardData]\n\n    /// Observable of remaining cards that the user hasn't yet solved\n    var remainingCards: [TriviaCardData] {\n        return Array(self.triviaCards.suffix(from: self.currentCardIndex))\n    }\n\n    /// Number of questions that were answered correctly on the first guess\n    var numCorrectOnFirstGuess: Int {\n        return self.guessTracker.filter { $0.value == 1 }.count\n    }\n\n    private var currentCardIndex: Int\n    private let triviaDataLoader: TriviaDataLoader\n\n    /// Tracks number of guesses before the right answer was reached.\n    /// The key is the the question, the value is the number of guesses\n    private var guessTracker = [TriviaQuestionModel: Int]()\n\n    /// Creates a UI model for the TriviaView view\n    /// - Parameters:\n    ///   - topic: The topic of trivia\n    ///   - numCards: The number of cards to display in the UI\n    init(topic: String, numCards: Int) {\n        let triviaFetcher = TriviaDataLoader(topic: topic)\n        self.topic = topic\n        self.numCards = numCards\n        self.currentCardIndex = 0\n        self.triviaDataLoader = triviaFetcher\n        self.triviaCards = (0..<numCards).map { i in TriviaCardData(triviaFetcher: triviaFetcher, position: i) }\n        Task {\n            await self.triviaCards[0].load()\n        }\n        self.loadNext()\n    }\n\n    /// Progress to the next trivia card\n    func progress() {\n        self.currentCardIndex += 1\n        self.loadNext()\n    }\n\n    /// Increments the number of guesses for the question passed as argument\n    func trackGuess(ofQuestion question: TriviaQuestionModel) {\n        self.guessTracker[question, default: 0] += 1\n    }\n\n    private func loadNext() {\n        if (self.currentCardIndex < self.numCards - 1) {\n            Task {\n                await self.triviaCards[self.currentCardIndex + 1].load()\n            }\n        }\n    }\n\n    deinit {\n        AppLogger.debug(\"TriviaData is being freed\")\n    }\n}\n"
  },
  {
    "path": "Demos/Trivia/Trivia/TriviaView.swift",
    "content": "//\n//  QuizView.swift\n//  AIProxyBootstrap\n//\n//  Created by Todd Hamilton\n//\n\nimport SwiftUI\n\nstruct TriviaView: View {\n\n    @State private var triviaManager: TriviaManager?\n\n    var body: some View {\n        ZStack{\n\n            Rectangle()\n                .fill(Color(.secondarySystemBackground))\n                .ignoresSafeArea()\n\n            if let triviaManager = self.triviaManager {\n                ZStack{\n\n                    if triviaManager.remainingCards.count == 0 {\n                        VStack{\n                            Text(\"You answered\")\n                                .font(.system(size: 15, weight:.bold, design: .rounded))\n                                .foregroundColor(.secondary)\n                            Text(\"\\(triviaManager.numCorrectOnFirstGuess) out \\(triviaManager.numCards) correctly.\")\n                                .font(.system(size: 24, weight:.semibold, design: .rounded))\n                                .multilineTextAlignment(.center)\n                            Button(\"Play again\") {\n                                self.triviaManager = nil\n                            }\n                            .fontDesign(.rounded)\n                            .fontWeight(.bold)\n                            .controlSize(.large)\n                            .buttonStyle(.borderedProminent)\n                            .padding(.top, 8)\n                        }\n                    }\n\n\n                    VStack(spacing:24){\n                        Text(triviaManager.topic)\n                            .font(.system(size: 24, weight:.bold, design: .rounded))\n                            .fontWeight(.bold)\n                        ZStack{\n                            ForEach(triviaManager.remainingCards) { triviaCard in\n                                let cardPosition = triviaCard.position - (triviaManager.remainingCards.first?.position ?? 0)\n                                TriviaCardView(triviaCardData: triviaCard, triviaManager: $triviaManager)\n                                    .zIndex(1 - Double(cardPosition))\n                                    .offset(y: CGFloat(cardPosition) * 25)\n                                    .scaleEffect(1.0 - (CGFloat(cardPosition) * 0.05))\n                            }\n                        }\n                        Spacer()\n                    }\n                    .padding()\n                }\n\n            } else {\n                TriviaFormView(triviaManager: $triviaManager)\n            }\n        }\n    }\n}\n\n#Preview {\n    TriviaView()\n}\n\n\n\n"
  },
  {
    "path": "Demos/Trivia/Trivia.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 56;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t0DDD23CE2B4DE38700B2AE5C /* TriviaApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD23CD2B4DE38700B2AE5C /* TriviaApp.swift */; };\n\t\t0DDD23D22B4DE38800B2AE5C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0DDD23D12B4DE38800B2AE5C /* Assets.xcassets */; };\n\t\t0DDD23D52B4DE38800B2AE5C /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0DDD23D42B4DE38800B2AE5C /* Preview Assets.xcassets */; };\n\t\t0DDD24502B4DF12400B2AE5C /* TriviaManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD24492B4DF12400B2AE5C /* TriviaManager.swift */; };\n\t\t0DDD24512B4DF12400B2AE5C /* TriviaCardData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD244A2B4DF12400B2AE5C /* TriviaCardData.swift */; };\n\t\t0DDD24522B4DF12400B2AE5C /* TriviaAnswerPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD244B2B4DF12400B2AE5C /* TriviaAnswerPicker.swift */; };\n\t\t0DDD24532B4DF12400B2AE5C /* TriviaFormView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD244C2B4DF12400B2AE5C /* TriviaFormView.swift */; };\n\t\t0DDD24542B4DF12400B2AE5C /* TriviaDataLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD244D2B4DF12400B2AE5C /* TriviaDataLoader.swift */; };\n\t\t0DDD24552B4DF12400B2AE5C /* TriviaCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD244E2B4DF12400B2AE5C /* TriviaCardView.swift */; };\n\t\t0DDD24562B4DF12400B2AE5C /* TriviaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD244F2B4DF12400B2AE5C /* TriviaView.swift */; };\n\t\t0DDD24592B4DF12A00B2AE5C /* AppLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD24572B4DF12A00B2AE5C /* AppLogger.swift */; };\n\t\t0DDD245A2B4DF12A00B2AE5C /* AppConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDD24582B4DF12A00B2AE5C /* AppConstants.swift */; };\n\t\t2CE770952C9B515A00EC6C74 /* AIProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 2CE770942C9B515A00EC6C74 /* AIProxy */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t0DDD23CA2B4DE38700B2AE5C /* Trivia.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Trivia.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t0DDD23CD2B4DE38700B2AE5C /* TriviaApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TriviaApp.swift; sourceTree = \"<group>\"; };\n\t\t0DDD23D12B4DE38800B2AE5C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t0DDD23D42B4DE38800B2AE5C /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = \"Preview Assets.xcassets\"; sourceTree = \"<group>\"; };\n\t\t0DDD24492B4DF12400B2AE5C /* TriviaManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TriviaManager.swift; sourceTree = \"<group>\"; };\n\t\t0DDD244A2B4DF12400B2AE5C /* TriviaCardData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TriviaCardData.swift; sourceTree = \"<group>\"; };\n\t\t0DDD244B2B4DF12400B2AE5C /* TriviaAnswerPicker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TriviaAnswerPicker.swift; sourceTree = \"<group>\"; };\n\t\t0DDD244C2B4DF12400B2AE5C /* TriviaFormView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TriviaFormView.swift; sourceTree = \"<group>\"; };\n\t\t0DDD244D2B4DF12400B2AE5C /* TriviaDataLoader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TriviaDataLoader.swift; sourceTree = \"<group>\"; };\n\t\t0DDD244E2B4DF12400B2AE5C /* TriviaCardView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TriviaCardView.swift; sourceTree = \"<group>\"; };\n\t\t0DDD244F2B4DF12400B2AE5C /* TriviaView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TriviaView.swift; sourceTree = \"<group>\"; };\n\t\t0DDD24572B4DF12A00B2AE5C /* AppLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppLogger.swift; sourceTree = \"<group>\"; };\n\t\t0DDD24582B4DF12A00B2AE5C /* AppConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppConstants.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t0DDD23C72B4DE38700B2AE5C /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2CE770952C9B515A00EC6C74 /* AIProxy in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t0DDD23C12B4DE38700B2AE5C = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0DDD23CC2B4DE38700B2AE5C /* Trivia */,\n\t\t\t\t0DDD23CB2B4DE38700B2AE5C /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0DDD23CB2B4DE38700B2AE5C /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0DDD23CA2B4DE38700B2AE5C /* Trivia.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0DDD23CC2B4DE38700B2AE5C /* Trivia */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0DDD24582B4DF12A00B2AE5C /* AppConstants.swift */,\n\t\t\t\t0DDD24572B4DF12A00B2AE5C /* AppLogger.swift */,\n\t\t\t\t0DDD244B2B4DF12400B2AE5C /* TriviaAnswerPicker.swift */,\n\t\t\t\t0DDD23CD2B4DE38700B2AE5C /* TriviaApp.swift */,\n\t\t\t\t0DDD244A2B4DF12400B2AE5C /* TriviaCardData.swift */,\n\t\t\t\t0DDD244E2B4DF12400B2AE5C /* TriviaCardView.swift */,\n\t\t\t\t0DDD244D2B4DF12400B2AE5C /* TriviaDataLoader.swift */,\n\t\t\t\t0DDD244C2B4DF12400B2AE5C /* TriviaFormView.swift */,\n\t\t\t\t0DDD24492B4DF12400B2AE5C /* TriviaManager.swift */,\n\t\t\t\t0DDD244F2B4DF12400B2AE5C /* TriviaView.swift */,\n\t\t\t\t0DDD23D12B4DE38800B2AE5C /* Assets.xcassets */,\n\t\t\t\t0DDD23D32B4DE38800B2AE5C /* Preview Content */,\n\t\t\t);\n\t\t\tpath = Trivia;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0DDD23D32B4DE38800B2AE5C /* Preview Content */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0DDD23D42B4DE38800B2AE5C /* Preview Assets.xcassets */,\n\t\t\t);\n\t\t\tpath = \"Preview Content\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t0DDD23C92B4DE38700B2AE5C /* Trivia */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 0DDD23D82B4DE38800B2AE5C /* Build configuration list for PBXNativeTarget \"Trivia\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t0DDD23C62B4DE38700B2AE5C /* Sources */,\n\t\t\t\t0DDD23C72B4DE38700B2AE5C /* Frameworks */,\n\t\t\t\t0DDD23C82B4DE38700B2AE5C /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = Trivia;\n\t\t\tpackageProductDependencies = (\n\t\t\t\t2CE770942C9B515A00EC6C74 /* AIProxy */,\n\t\t\t);\n\t\t\tproductName = Trivia;\n\t\t\tproductReference = 0DDD23CA2B4DE38700B2AE5C /* Trivia.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t0DDD23C22B4DE38700B2AE5C /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = 1;\n\t\t\t\tLastSwiftUpdateCheck = 1510;\n\t\t\t\tLastUpgradeCheck = 1510;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t0DDD23C92B4DE38700B2AE5C = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 15.1;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 0DDD23C52B4DE38700B2AE5C /* Build configuration list for PBXProject \"Trivia\" */;\n\t\t\tcompatibilityVersion = \"Xcode 14.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 0DDD23C12B4DE38700B2AE5C;\n\t\t\tpackageReferences = (\n\t\t\t\t2CE770932C9B515A00EC6C74 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */,\n\t\t\t);\n\t\t\tproductRefGroup = 0DDD23CB2B4DE38700B2AE5C /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t0DDD23C92B4DE38700B2AE5C /* Trivia */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t0DDD23C82B4DE38700B2AE5C /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t0DDD23D52B4DE38800B2AE5C /* Preview Assets.xcassets in Resources */,\n\t\t\t\t0DDD23D22B4DE38800B2AE5C /* Assets.xcassets in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t0DDD23C62B4DE38700B2AE5C /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t0DDD24522B4DF12400B2AE5C /* TriviaAnswerPicker.swift in Sources */,\n\t\t\t\t0DDD24542B4DF12400B2AE5C /* TriviaDataLoader.swift in Sources */,\n\t\t\t\t0DDD24502B4DF12400B2AE5C /* TriviaManager.swift in Sources */,\n\t\t\t\t0DDD23CE2B4DE38700B2AE5C /* TriviaApp.swift in Sources */,\n\t\t\t\t0DDD24512B4DF12400B2AE5C /* TriviaCardData.swift in Sources */,\n\t\t\t\t0DDD24562B4DF12400B2AE5C /* TriviaView.swift in Sources */,\n\t\t\t\t0DDD24592B4DF12A00B2AE5C /* AppLogger.swift in Sources */,\n\t\t\t\t0DDD24552B4DF12400B2AE5C /* TriviaCardView.swift in Sources */,\n\t\t\t\t0DDD24532B4DF12400B2AE5C /* TriviaFormView.swift in Sources */,\n\t\t\t\t0DDD245A2B4DF12A00B2AE5C /* AppConstants.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t0DDD23D62B4DE38800B2AE5C /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.2;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"DEBUG $(inherited)\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t0DDD23D72B4DE38800B2AE5C /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.2;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t0DDD23D92B4DE38800B2AE5C /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"Trivia/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 9557YJ9D37;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.aiproxy.bootstrap.trivia;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t0DDD23DA2B4DE38800B2AE5C /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"Trivia/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = 9557YJ9D37;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.aiproxy.bootstrap.trivia;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t0DDD23C52B4DE38700B2AE5C /* Build configuration list for PBXProject \"Trivia\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t0DDD23D62B4DE38800B2AE5C /* Debug */,\n\t\t\t\t0DDD23D72B4DE38800B2AE5C /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t0DDD23D82B4DE38800B2AE5C /* Build configuration list for PBXNativeTarget \"Trivia\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t0DDD23D92B4DE38800B2AE5C /* Debug */,\n\t\t\t\t0DDD23DA2B4DE38800B2AE5C /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCRemoteSwiftPackageReference section */\n\t\t2CE770932C9B515A00EC6C74 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/lzell/AIProxySwift\";\n\t\t\trequirement = {\n\t\t\t\tbranch = main;\n\t\t\t\tkind = branch;\n\t\t\t};\n\t\t};\n/* End XCRemoteSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */\n\t\t2CE770942C9B515A00EC6C74 /* AIProxy */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 2CE770932C9B515A00EC6C74 /* XCRemoteSwiftPackageReference \"AIProxySwift\" */;\n\t\t\tproductName = AIProxy;\n\t\t};\n/* End XCSwiftPackageProductDependency section */\n\t};\n\trootObject = 0DDD23C22B4DE38700B2AE5C /* Project object */;\n}\n"
  },
  {
    "path": "README.md",
    "content": "# Starter apps for AIProxy\n\nUse these apps as a jumping off point to build your own experiences using AIProxy. Sample apps are organized by services (for ex. OpenAI, Anthropic etc.). Each sample app has a placeholder to add your AIProxy constants (see AppConstants.swift). The apps all use [AIProxySwift](https://github.com/lzell/AIProxySwift) to implement API calls.\n\n### Instructions to build and run\n\n1. Watch [the AIProxy bootstrap walkthrough video](https://www.youtube.com/watch?v=ohsN9awCzw4)\n2. Replace the constants in `AppConstants.swift` files with the snippet you receive from the AIProxy dashboard in step 1\n3. Change the bundler identifier of the sample app to match the App ID you created in step 1\n4. Add an AIPROXY_DEVICE_CHECK_BYPASS env variable to Xcode. This is necessary for the iOS simulator to communicate with the AIProxy backend. Type **cmd-shift-comma** to open up the \"Edit Schemes\" menu. Select Run in the sidebar, then select Arguments from the top nav. Add to the \"Environment Variables\" section an env variable with name AIPROXY_DEVICE_CHECK_BYPASS and value displayed on the key details screen.\n\n### Quickstart apps\n\n- **AIProxyAnthropic** - An Anthropic app that generates a message.\n- **AIProxyDeepL** - A DeepL app that translates input text to Spanish.\n- **AIProxyOpenAI** - An OpenAI app with chat, DALLE, and vision.\n- **AIProxyReplicate** - A Replicate app with Stable Diffusion XL.\n- **AIProxyGroq** - A Groq app with chat completion and streaming chat completion examples.\n- **AIProxyStability** - A Stability AI app that generates an image.\n- **AIProxyTogetherAI** - A Together AI app with examples for chat, streaming chat, and JSON response.\n\n### Playground apps\n\n- **FilmFinder** - A movie recommendation app that uses Groq and TMDB (requires Xcode 16).\n- **PuLIDDemo** - An image generator app that uses PuLID on Replicate (requires Xcode 16).\n- **AIColorPalette** - An OpenAI color palette generator that uses an image as input (requires Xcode 16).\n- **Chat** - A basic chat application and interface with OpenAI. Includes streaming responses and ability to stop stream.\n- **Image Classifier** - An OpenAI image classification app that identifies plants and provides a link to Wikipedia.\n- **Transriber** - An OpenAI app that transcribes audio recorded using the device microphone.\n- **Translator** - A simple English to Spanish translation app with text to speech using OpenAI.\n- **Trivia Game** - A trivia game that uses GPT to generate multiple choice questions from a JSON response.\n- **Stickers** - An OpenAI app that turns a prompt into a kawaii style sticker and extracts the foreground/background using Vision.\n- **EmojiPuzzleMaker** - Generate emoji puzzles using Anthropic's Claude 3.5 Sonnet API.\n"
  }
]