├── ContextCoreMLDemo ├── Assets.xcassets │ ├── Contents.json │ ├── AccentColor.colorset │ │ └── Contents.json │ └── AppIcon.appiconset │ │ └── Contents.json ├── MyFirstCustomModel.mlmodel ├── Info.plist ├── AppDelegate.swift ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── ViewController.swift ├── SceneDelegate.swift └── ModelDownloadManager.swift ├── docs ├── latest_model_details.json └── models │ ├── 40a2-82d1-bcf8-4ab5-9d35-d7f257c4c31e.mlmodel │ └── 80a2-82d1-bcf8-4ab5-9d35-d7f257c4c31e.mlmodel ├── ContextCoreMLDemo.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── project.pbxproj ├── README.md ├── .gitignore └── model_training.ipynb /ContextCoreMLDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ContextCoreMLDemo/MyFirstCustomModel.mlmodel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KrauseFx/CoreMLDemo/HEAD/ContextCoreMLDemo/MyFirstCustomModel.mlmodel -------------------------------------------------------------------------------- /docs/latest_model_details.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://krausefx.github.io/CoreMLDemo/models/80a2-82d1-bcf8-4ab5-9d35-d7f257c4c31e.mlmodel" 3 | } 4 | -------------------------------------------------------------------------------- /docs/models/40a2-82d1-bcf8-4ab5-9d35-d7f257c4c31e.mlmodel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KrauseFx/CoreMLDemo/HEAD/docs/models/40a2-82d1-bcf8-4ab5-9d35-d7f257c4c31e.mlmodel -------------------------------------------------------------------------------- /docs/models/80a2-82d1-bcf8-4ab5-9d35-d7f257c4c31e.mlmodel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KrauseFx/CoreMLDemo/HEAD/docs/models/80a2-82d1-bcf8-4ab5-9d35-d7f257c4c31e.mlmodel -------------------------------------------------------------------------------- /ContextCoreMLDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ContextCoreMLDemo/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is the demo app for distributing CoreML Machine Learning files over-the-air. For more context, check out [this post](https://contextsdk.com/blog/safely-distribute-new-machine-learning-models-to-millions-of-iphones-over-the-air) 2 | -------------------------------------------------------------------------------- /ContextCoreMLDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "platform" : "ios", 6 | "size" : "1024x1024" 7 | } 8 | ], 9 | "info" : { 10 | "author" : "xcode", 11 | "version" : 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ContextCoreMLDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ContextCoreMLDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIApplicationSceneManifest 6 | 7 | UIApplicationSupportsMultipleScenes 8 | 9 | UISceneConfigurations 10 | 11 | UIWindowSceneSessionRoleApplication 12 | 13 | 14 | UISceneConfigurationName 15 | Default Configuration 16 | UISceneDelegateClassName 17 | $(PRODUCT_MODULE_NAME).SceneDelegate 18 | UISceneStoryboardFile 19 | Main 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /ContextCoreMLDemo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // ContextCoreMLDemo 4 | // 5 | // Created by Felix Krause on 16.05.24. 6 | // 7 | 8 | import UIKit 9 | 10 | @main 11 | class AppDelegate: UIResponder, UIApplicationDelegate { 12 | 13 | 14 | 15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 16 | // Override point for customization after application launch. 17 | return true 18 | } 19 | 20 | // MARK: UISceneSession Lifecycle 21 | 22 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 23 | // Called when a new scene session is being created. 24 | // Use this method to select a configuration to create the new scene with. 25 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 26 | } 27 | 28 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 29 | // Called when the user discards a scene session. 30 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 31 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 32 | } 33 | 34 | 35 | } 36 | 37 | -------------------------------------------------------------------------------- /ContextCoreMLDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /ContextCoreMLDemo/ViewController.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import CoreML 3 | 4 | class ViewController: UIViewController { 5 | let modelDownloadManager = ModelDownloadManager() 6 | 7 | override func viewDidLoad() { 8 | super.viewDidLoad() 9 | } 10 | 11 | @IBAction func runLatestLocalModel() { 12 | let batteryLevel = UIDevice.current.batteryLevel 13 | let batteryCharging = UIDevice.current.batteryState == .charging || UIDevice.current.batteryState == .full 14 | do { 15 | let modelInput = MyFirstCustomModelInput(input: [ 16 | Double(batteryLevel), 17 | Double(batteryCharging ? 1.0 : 0.0) 18 | ]) 19 | if let currentModel = modelDownloadManager.latestModel(), 20 | let modelMetadata = currentModel.model.modelDescription.metadata[.description] { 21 | let result = try currentModel.prediction(input: modelInput) 22 | let classProbabilities = result.featureValue(for: "classProbability")?.dictionaryValue 23 | let upsellProbability = classProbabilities?["Purchased"]?.doubleValue ?? -1 24 | 25 | showAlertDialog(message:("Chances of Upsell: \(upsellProbability), executed through model \(String(describing: modelMetadata))")) 26 | } else { 27 | showAlertDialog(message:("Could not run CoreML model")) 28 | } 29 | } catch { 30 | showAlertDialog(message:("Error running CoreML file: \(error)")) 31 | } 32 | } 33 | 34 | @IBAction func downloadLatestModel() { 35 | Task { 36 | do { 37 | try await modelDownloadManager.checkForModelUpdates() 38 | showAlertDialog(message:("Model update completed successfully.")) 39 | } catch { 40 | // Handle possible errors here 41 | showAlertDialog(message:("Failed to update model: \(error.localizedDescription)")) 42 | } 43 | } 44 | } 45 | 46 | internal func showAlertDialog(message: String) { 47 | let alert = UIAlertController(title: "Alert", message: message, preferredStyle: .alert) 48 | alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) 49 | self.present(alert, animated: true, completion: nil) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /ContextCoreMLDemo/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // ContextCoreMLDemo 4 | // 5 | // Created by Felix Krause on 16.05.24. 6 | // 7 | 8 | import UIKit 9 | 10 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 11 | 12 | var window: UIWindow? 13 | 14 | 15 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 16 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 17 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 18 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 19 | guard let _ = (scene as? UIWindowScene) else { return } 20 | } 21 | 22 | func sceneDidDisconnect(_ scene: UIScene) { 23 | // Called as the scene is being released by the system. 24 | // This occurs shortly after the scene enters the background, or when its session is discarded. 25 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 26 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). 27 | } 28 | 29 | func sceneDidBecomeActive(_ scene: UIScene) { 30 | // Called when the scene has moved from an inactive state to an active state. 31 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 32 | } 33 | 34 | func sceneWillResignActive(_ scene: UIScene) { 35 | // Called when the scene will move from an active state to an inactive state. 36 | // This may occur due to temporary interruptions (ex. an incoming phone call). 37 | } 38 | 39 | func sceneWillEnterForeground(_ scene: UIScene) { 40 | // Called as the scene transitions from the background to the foreground. 41 | // Use this method to undo the changes made on entering the background. 42 | } 43 | 44 | func sceneDidEnterBackground(_ scene: UIScene) { 45 | // Called as the scene transitions from the foreground to the background. 46 | // Use this method to save data, release shared resources, and store enough scene-specific state information 47 | // to restore the scene back to its current state. 48 | } 49 | 50 | 51 | } 52 | 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_STORE 2 | 3 | # Xcode 4 | # 5 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 6 | 7 | ## User settings 8 | xcuserdata/ 9 | 10 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 11 | *.xcscmblueprint 12 | *.xccheckout 13 | 14 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 15 | build/ 16 | DerivedData/ 17 | *.moved-aside 18 | *.pbxuser 19 | !default.pbxuser 20 | *.mode1v3 21 | !default.mode1v3 22 | *.mode2v3 23 | !default.mode2v3 24 | *.perspectivev3 25 | !default.perspectivev3 26 | 27 | ## Obj-C/Swift specific 28 | *.hmap 29 | 30 | ## App packaging 31 | *.ipa 32 | *.dSYM.zip 33 | *.dSYM 34 | 35 | ## Playgrounds 36 | timeline.xctimeline 37 | playground.xcworkspace 38 | 39 | # Swift Package Manager 40 | # 41 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 42 | # Packages/ 43 | # Package.pins 44 | # Package.resolved 45 | # *.xcodeproj 46 | # 47 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 48 | # hence it is not needed unless you have added a package configuration file to your project 49 | # .swiftpm 50 | 51 | .build/ 52 | 53 | # CocoaPods 54 | # 55 | # We recommend against adding the Pods directory to your .gitignore. However 56 | # you should judge for yourself, the pros and cons are mentioned at: 57 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 58 | # 59 | # Pods/ 60 | # 61 | # Add this line if you want to avoid checking in source code from the Xcode workspace 62 | # *.xcworkspace 63 | 64 | # Carthage 65 | # 66 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 67 | # Carthage/Checkouts 68 | 69 | Carthage/Build/ 70 | 71 | # Accio dependency management 72 | Dependencies/ 73 | .accio/ 74 | 75 | # fastlane 76 | # 77 | # It is recommended to not store the screenshots in the git repo. 78 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 79 | # For more information about the recommended setup visit: 80 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 81 | 82 | fastlane/report.xml 83 | fastlane/Preview.html 84 | fastlane/screenshots/**/*.png 85 | fastlane/test_output 86 | 87 | # Code Injection 88 | # 89 | # After new code Injection tools there's a generated folder /iOSInjectionProject 90 | # https://github.com/johnno1962/injectionforxcode 91 | 92 | iOSInjectionProject/ 93 | 94 | -------------------------------------------------------------------------------- /ContextCoreMLDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 28 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /ContextCoreMLDemo/ModelDownloadManager.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import CoreML 3 | 4 | class ModelDownloadManager { 5 | private let fileManager: FileManager 6 | private let modelsFolder: URL 7 | private let modelUpdateCheckURL = "https://krausefx.github.io/CoreMLDemo/latest_model_details.json" 8 | 9 | init(fileManager: FileManager = .default) { 10 | self.fileManager = fileManager 11 | if let folder = fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask).first?.appendingPathComponent("context_sdk_models") { 12 | self.modelsFolder = folder 13 | try? fileManager.createDirectory(at: folder, withIntermediateDirectories: true) 14 | } else { 15 | fatalError("Unable to find or create models folder.") // Handle this more gracefully 16 | } 17 | } 18 | 19 | internal func latestModel() -> MyFirstCustomModel? { 20 | let fileManagerContents = (try? fileManager.contentsOfDirectory(at: modelsFolder, includingPropertiesForKeys: nil)) ?? [] 21 | 22 | // Try to find the latest model file based on modification date 23 | if let latestFileURL = fileManagerContents.sorted(by: { $0.lastPathComponent > $1.lastPathComponent }).first, 24 | let otaModel = try? MyFirstCustomModel(contentsOf: latestFileURL) { 25 | return otaModel 26 | } else if let bundledModel = try? MyFirstCustomModel(configuration: MLModelConfiguration()) { 27 | return bundledModel // Fallback to the bundled model if no downloaded model exists 28 | } 29 | return nil 30 | } 31 | 32 | internal func checkForModelUpdates() async throws { 33 | guard let url = URL(string: modelUpdateCheckURL) else { 34 | throw URLError(.badURL) 35 | } 36 | let (data, _) = try await URLSession.shared.data(from: url) 37 | guard let jsonObject = try JSONSerialization.jsonObject(with: data) as? [String: Any], 38 | let modelDownloadURLString = jsonObject["url"] as? String, 39 | let modelDownloadURL = URL(string: modelDownloadURLString) else { 40 | throw URLError(.cannotParseResponse) 41 | } 42 | 43 | try await downloadIfNeeded(from: modelDownloadURL) 44 | } 45 | 46 | private func downloadIfNeeded(from url: URL) async throws { 47 | let lastPathComponent = url.lastPathComponent 48 | 49 | // Check if the model file already exists (for this sample project we use the unique file name as identifier) 50 | if let localFiles = try? fileManager.contentsOfDirectory(at: modelsFolder, includingPropertiesForKeys: nil), 51 | localFiles.contains(where: { $0.lastPathComponent == lastPathComponent }) { 52 | // File exists, you could add a version check here if versions are part of the file name or metadata 53 | print("Model already exists locally. No need to download.") 54 | } else { 55 | let downloadedURL = try await downloadCoreMLFile(from: url) // File does not exist, download it 56 | let compiledURL = try compileCoreMLFile(at: downloadedURL) 57 | try deleteAllOutdatedModels(keeping: compiledURL.lastPathComponent) 58 | print("Model downloaded, compiled, and old models cleaned up successfully.") 59 | } 60 | } 61 | 62 | // It's important to immediately move the downloaded CoreML file into a permanent location 63 | private func downloadCoreMLFile(from url: URL) async throws -> URL { 64 | let (tempLocalURL, _) = try await URLSession.shared.download(for: URLRequest(url: url)) 65 | let destinationURL = modelsFolder.appendingPathComponent(tempLocalURL.lastPathComponent) 66 | try fileManager.moveItem(at: tempLocalURL, to: destinationURL) 67 | return destinationURL 68 | } 69 | 70 | private func compileCoreMLFile(at localFilePath: URL) throws -> URL { 71 | let compiledModelURL = try MLModel.compileModel(at: localFilePath) 72 | let destinationCompiledURL = modelsFolder.appendingPathComponent(compiledModelURL.lastPathComponent) 73 | try fileManager.moveItem(at: compiledModelURL, to: destinationCompiledURL) 74 | try fileManager.removeItem(at: localFilePath) 75 | return destinationCompiledURL 76 | } 77 | 78 | private func deleteAllOutdatedModels(keeping recentModelFileName: String) throws { 79 | let urlContent = try fileManager.contentsOfDirectory(at: modelsFolder, includingPropertiesForKeys: nil, options: .skipsHiddenFiles) 80 | for fileURL in urlContent where fileURL.lastPathComponent != recentModelFileName { 81 | try fileManager.removeItem(at: fileURL) 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /model_training.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 8, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "name": "stdout", 10 | "output_type": "stream", 11 | "text": [ 12 | " Outcome Battery Level Phone Charging?\n", 13 | "0 Dismissed 0.90 False\n", 14 | "1 Dismissed 0.10 False\n", 15 | "2 Purchased 0.24 True\n", 16 | "3 Dismissed 0.13 True\n", 17 | "4 Purchased 0.94 True\n" 18 | ] 19 | } 20 | ], 21 | "source": [ 22 | "import pandas as pd\n", 23 | "\n", 24 | "rows = [\n", 25 | " ['Dismissed', 0.90, False],\n", 26 | " ['Dismissed', 0.10, False],\n", 27 | " ['Purchased', 0.24, True],\n", 28 | " ['Dismissed', 0.13, True],\n", 29 | " ['Purchased', 0.94, True],\n", 30 | " ['Dismissed', 0.11, False],\n", 31 | " ['Purchased', 0.89, True],\n", 32 | " ['Dismissed', 0.06, False],\n", 33 | " ['Purchased', 0.76, True],\n", 34 | " ['Dismissed', 0.22, False],\n", 35 | " ['Purchased', 0.91, True],\n", 36 | " ['Dismissed', 0.05, False],\n", 37 | " ['Purchased', 0.83, True],\n", 38 | " ['Dismissed', 0.14, False],\n", 39 | " ['Purchased', 0.92, True],\n", 40 | " ['Dismissed', 0.08, False],\n", 41 | " ['Purchased', 0.88, True],\n", 42 | " ['Dismissed', 0.18, False],\n", 43 | " ['Purchased', 0.93, True],\n", 44 | " ['Dismissed', 0.07, False],\n", 45 | " ['Purchased', 0.85, True],\n", 46 | " ['Dismissed', 0.13, False],\n", 47 | " ['Purchased', 0.90, True],\n", 48 | " ['Dismissed', 0.10, False],\n", 49 | " ['Purchased', 0.84, True],\n", 50 | " ['Dismissed', 0.16, False],\n", 51 | " ['Purchased', 0.91, True],\n", 52 | " ['Dismissed', 0.09, False],\n", 53 | " ['Purchased', 0.86, True],\n", 54 | " ['Dismissed', 0.14, False],\n", 55 | " ['Purchased', 0.95, True],\n", 56 | " ['Dismissed', 0.05, False],\n", 57 | " ['Purchased', 0.82, True],\n", 58 | " ['Dismissed', 0.18, False],\n", 59 | " ['Purchased', 0.93, True],\n", 60 | " ['Dismissed', 0.07, False],\n", 61 | " ['Purchased', 0.87, True],\n", 62 | " ['Dismissed', 0.13, False],\n", 63 | " ['Purchased', 0.90, True],\n", 64 | " ['Dismissed', 0.10, False],\n", 65 | " ['Purchased', 0.84, True],\n", 66 | " ['Dismissed', 0.16, False],\n", 67 | " ['Purchased', 0.92, True],\n", 68 | " ['Dismissed', 0.08, False],\n", 69 | " ['Purchased', 0.88, True],\n", 70 | " ['Dismissed', 0.12, False],\n", 71 | " ['Purchased', 0.91, True],\n", 72 | " ['Dismissed', 0.09, False],\n", 73 | " ['Purchased', 0.86, True],\n", 74 | " ['Dismissed', 0.14, False],\n", 75 | " ['Purchased', 0.94, True],\n", 76 | " ['Dismissed', 0.06, False]\n", 77 | "]\n", 78 | "data = pd.DataFrame(rows, columns=['Outcome', 'Battery Level', 'Phone Charging?'])\n", 79 | "print(data.head(5))" 80 | ] 81 | }, 82 | { 83 | "cell_type": "code", 84 | "execution_count": 9, 85 | "metadata": {}, 86 | "outputs": [], 87 | "source": [ 88 | "from sklearn.model_selection import train_test_split\n", 89 | "\n", 90 | "X = data.drop(\"Outcome\", axis=1)\n", 91 | "Y = data[\"Outcome\"]\n", 92 | "\n", 93 | "X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.2, shuffle=True)\n" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": 10, 99 | "metadata": {}, 100 | "outputs": [ 101 | { 102 | "name": "stdout", 103 | "output_type": "stream", 104 | "text": [ 105 | " precision recall f1-score support\n", 106 | "\n", 107 | " Dismissed 1.00 1.00 1.00 5\n", 108 | " Purchased 1.00 1.00 1.00 6\n", 109 | "\n", 110 | " accuracy 1.00 11\n", 111 | " macro avg 1.00 1.00 1.00 11\n", 112 | "weighted avg 1.00 1.00 1.00 11\n", 113 | "\n" 114 | ] 115 | } 116 | ], 117 | "source": [ 118 | "from sklearn.ensemble import RandomForestClassifier\n", 119 | "from sklearn.metrics import classification_report\n", 120 | "\n", 121 | "classifier = RandomForestClassifier()\n", 122 | "classifier.fit(X_train, Y_train)\n", 123 | "Y_pred = classifier.predict(X_test)\n", 124 | "print(classification_report(Y_test, Y_pred, zero_division=1))" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": 11, 130 | "metadata": {}, 131 | "outputs": [ 132 | { 133 | "name": "stderr", 134 | "output_type": "stream", 135 | "text": [ 136 | "/Users/krausefx/Library/Python/3.9/lib/python/site-packages/sklearn/utils/deprecation.py:103: FutureWarning: Attribute `n_features_` was deprecated in version 1.0 and will be removed in 1.2. Use `n_features_in_` instead.\n", 137 | " warnings.warn(msg, category=FutureWarning)\n" 138 | ] 139 | } 140 | ], 141 | "source": [ 142 | "import coremltools\n", 143 | "\n", 144 | "coreml_model = coremltools.converters.sklearn.convert(classifier, input_features=\"input\")\n", 145 | "coreml_model.short_description = \"My first model\"\n", 146 | "coreml_model.save(\"ContextCoreMLDemo/MyFirstCustomModel.mlmodel\")" 147 | ] 148 | } 149 | ], 150 | "metadata": { 151 | "kernelspec": { 152 | "display_name": "Python 3", 153 | "language": "python", 154 | "name": "python3" 155 | }, 156 | "language_info": { 157 | "codemirror_mode": { 158 | "name": "ipython", 159 | "version": 3 160 | }, 161 | "file_extension": ".py", 162 | "mimetype": "text/x-python", 163 | "name": "python", 164 | "nbconvert_exporter": "python", 165 | "pygments_lexer": "ipython3", 166 | "version": "3.9.6" 167 | } 168 | }, 169 | "nbformat": 4, 170 | "nbformat_minor": 2 171 | } 172 | -------------------------------------------------------------------------------- /ContextCoreMLDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 56; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | F20732362BF5ECD3002F3A39 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F20732352BF5ECD3002F3A39 /* AppDelegate.swift */; }; 11 | F20732382BF5ECD3002F3A39 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F20732372BF5ECD3002F3A39 /* SceneDelegate.swift */; }; 12 | F207323A2BF5ECD3002F3A39 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F20732392BF5ECD3002F3A39 /* ViewController.swift */; }; 13 | F207323D2BF5ECD4002F3A39 /* Base in Resources */ = {isa = PBXBuildFile; fileRef = F207323C2BF5ECD4002F3A39 /* Base */; }; 14 | F207323F2BF5ECD5002F3A39 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F207323E2BF5ECD5002F3A39 /* Assets.xcassets */; }; 15 | F20732422BF5ECD5002F3A39 /* Base in Resources */ = {isa = PBXBuildFile; fileRef = F20732412BF5ECD5002F3A39 /* Base */; }; 16 | F207324C2BF5EFFF002F3A39 /* MyFirstCustomModel.mlmodel in Sources */ = {isa = PBXBuildFile; fileRef = F207324B2BF5EFFF002F3A39 /* MyFirstCustomModel.mlmodel */; }; 17 | F207324E2BF61B73002F3A39 /* ModelDownloadManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F207324D2BF61B73002F3A39 /* ModelDownloadManager.swift */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXFileReference section */ 21 | F20732322BF5ECD3002F3A39 /* ContextCoreMLDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ContextCoreMLDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 22 | F20732352BF5ECD3002F3A39 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 23 | F20732372BF5ECD3002F3A39 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 24 | F20732392BF5ECD3002F3A39 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 25 | F207323C2BF5ECD4002F3A39 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 26 | F207323E2BF5ECD5002F3A39 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 27 | F20732412BF5ECD5002F3A39 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 28 | F20732432BF5ECD5002F3A39 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 29 | F207324B2BF5EFFF002F3A39 /* MyFirstCustomModel.mlmodel */ = {isa = PBXFileReference; lastKnownFileType = file.mlmodel; path = MyFirstCustomModel.mlmodel; sourceTree = ""; }; 30 | F207324D2BF61B73002F3A39 /* ModelDownloadManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelDownloadManager.swift; sourceTree = ""; }; 31 | /* End PBXFileReference section */ 32 | 33 | /* Begin PBXFrameworksBuildPhase section */ 34 | F207322F2BF5ECD3002F3A39 /* Frameworks */ = { 35 | isa = PBXFrameworksBuildPhase; 36 | buildActionMask = 2147483647; 37 | files = ( 38 | ); 39 | runOnlyForDeploymentPostprocessing = 0; 40 | }; 41 | /* End PBXFrameworksBuildPhase section */ 42 | 43 | /* Begin PBXGroup section */ 44 | F20732292BF5ECD3002F3A39 = { 45 | isa = PBXGroup; 46 | children = ( 47 | F20732342BF5ECD3002F3A39 /* ContextCoreMLDemo */, 48 | F20732332BF5ECD3002F3A39 /* Products */, 49 | ); 50 | sourceTree = ""; 51 | }; 52 | F20732332BF5ECD3002F3A39 /* Products */ = { 53 | isa = PBXGroup; 54 | children = ( 55 | F20732322BF5ECD3002F3A39 /* ContextCoreMLDemo.app */, 56 | ); 57 | name = Products; 58 | sourceTree = ""; 59 | }; 60 | F20732342BF5ECD3002F3A39 /* ContextCoreMLDemo */ = { 61 | isa = PBXGroup; 62 | children = ( 63 | F20732352BF5ECD3002F3A39 /* AppDelegate.swift */, 64 | F20732372BF5ECD3002F3A39 /* SceneDelegate.swift */, 65 | F20732392BF5ECD3002F3A39 /* ViewController.swift */, 66 | F207323B2BF5ECD4002F3A39 /* Main.storyboard */, 67 | F207323E2BF5ECD5002F3A39 /* Assets.xcassets */, 68 | F20732402BF5ECD5002F3A39 /* LaunchScreen.storyboard */, 69 | F20732432BF5ECD5002F3A39 /* Info.plist */, 70 | F207324B2BF5EFFF002F3A39 /* MyFirstCustomModel.mlmodel */, 71 | F207324D2BF61B73002F3A39 /* ModelDownloadManager.swift */, 72 | ); 73 | path = ContextCoreMLDemo; 74 | sourceTree = ""; 75 | }; 76 | /* End PBXGroup section */ 77 | 78 | /* Begin PBXNativeTarget section */ 79 | F20732312BF5ECD3002F3A39 /* ContextCoreMLDemo */ = { 80 | isa = PBXNativeTarget; 81 | buildConfigurationList = F20732462BF5ECD5002F3A39 /* Build configuration list for PBXNativeTarget "ContextCoreMLDemo" */; 82 | buildPhases = ( 83 | F207322E2BF5ECD3002F3A39 /* Sources */, 84 | F207322F2BF5ECD3002F3A39 /* Frameworks */, 85 | F20732302BF5ECD3002F3A39 /* Resources */, 86 | ); 87 | buildRules = ( 88 | ); 89 | dependencies = ( 90 | ); 91 | name = ContextCoreMLDemo; 92 | productName = ContextCoreMLDemo; 93 | productReference = F20732322BF5ECD3002F3A39 /* ContextCoreMLDemo.app */; 94 | productType = "com.apple.product-type.application"; 95 | }; 96 | /* End PBXNativeTarget section */ 97 | 98 | /* Begin PBXProject section */ 99 | F207322A2BF5ECD3002F3A39 /* Project object */ = { 100 | isa = PBXProject; 101 | attributes = { 102 | BuildIndependentTargetsInParallel = 1; 103 | LastSwiftUpdateCheck = 1540; 104 | LastUpgradeCheck = 1540; 105 | TargetAttributes = { 106 | F20732312BF5ECD3002F3A39 = { 107 | CreatedOnToolsVersion = 15.4; 108 | }; 109 | }; 110 | }; 111 | buildConfigurationList = F207322D2BF5ECD3002F3A39 /* Build configuration list for PBXProject "ContextCoreMLDemo" */; 112 | compatibilityVersion = "Xcode 14.0"; 113 | developmentRegion = en; 114 | hasScannedForEncodings = 0; 115 | knownRegions = ( 116 | en, 117 | Base, 118 | ); 119 | mainGroup = F20732292BF5ECD3002F3A39; 120 | productRefGroup = F20732332BF5ECD3002F3A39 /* Products */; 121 | projectDirPath = ""; 122 | projectRoot = ""; 123 | targets = ( 124 | F20732312BF5ECD3002F3A39 /* ContextCoreMLDemo */, 125 | ); 126 | }; 127 | /* End PBXProject section */ 128 | 129 | /* Begin PBXResourcesBuildPhase section */ 130 | F20732302BF5ECD3002F3A39 /* Resources */ = { 131 | isa = PBXResourcesBuildPhase; 132 | buildActionMask = 2147483647; 133 | files = ( 134 | F207323F2BF5ECD5002F3A39 /* Assets.xcassets in Resources */, 135 | F20732422BF5ECD5002F3A39 /* Base in Resources */, 136 | F207323D2BF5ECD4002F3A39 /* Base in Resources */, 137 | ); 138 | runOnlyForDeploymentPostprocessing = 0; 139 | }; 140 | /* End PBXResourcesBuildPhase section */ 141 | 142 | /* Begin PBXSourcesBuildPhase section */ 143 | F207322E2BF5ECD3002F3A39 /* Sources */ = { 144 | isa = PBXSourcesBuildPhase; 145 | buildActionMask = 2147483647; 146 | files = ( 147 | F207324C2BF5EFFF002F3A39 /* MyFirstCustomModel.mlmodel in Sources */, 148 | F207324E2BF61B73002F3A39 /* ModelDownloadManager.swift in Sources */, 149 | F207323A2BF5ECD3002F3A39 /* ViewController.swift in Sources */, 150 | F20732362BF5ECD3002F3A39 /* AppDelegate.swift in Sources */, 151 | F20732382BF5ECD3002F3A39 /* SceneDelegate.swift in Sources */, 152 | ); 153 | runOnlyForDeploymentPostprocessing = 0; 154 | }; 155 | /* End PBXSourcesBuildPhase section */ 156 | 157 | /* Begin PBXVariantGroup section */ 158 | F207323B2BF5ECD4002F3A39 /* Main.storyboard */ = { 159 | isa = PBXVariantGroup; 160 | children = ( 161 | F207323C2BF5ECD4002F3A39 /* Base */, 162 | ); 163 | name = Main.storyboard; 164 | sourceTree = ""; 165 | }; 166 | F20732402BF5ECD5002F3A39 /* LaunchScreen.storyboard */ = { 167 | isa = PBXVariantGroup; 168 | children = ( 169 | F20732412BF5ECD5002F3A39 /* Base */, 170 | ); 171 | name = LaunchScreen.storyboard; 172 | sourceTree = ""; 173 | }; 174 | /* End PBXVariantGroup section */ 175 | 176 | /* Begin XCBuildConfiguration section */ 177 | F20732442BF5ECD5002F3A39 /* Debug */ = { 178 | isa = XCBuildConfiguration; 179 | buildSettings = { 180 | ALWAYS_SEARCH_USER_PATHS = NO; 181 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 182 | CLANG_ANALYZER_NONNULL = YES; 183 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 184 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 185 | CLANG_ENABLE_MODULES = YES; 186 | CLANG_ENABLE_OBJC_ARC = YES; 187 | CLANG_ENABLE_OBJC_WEAK = YES; 188 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 189 | CLANG_WARN_BOOL_CONVERSION = YES; 190 | CLANG_WARN_COMMA = YES; 191 | CLANG_WARN_CONSTANT_CONVERSION = YES; 192 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 193 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 194 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 195 | CLANG_WARN_EMPTY_BODY = YES; 196 | CLANG_WARN_ENUM_CONVERSION = YES; 197 | CLANG_WARN_INFINITE_RECURSION = YES; 198 | CLANG_WARN_INT_CONVERSION = YES; 199 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 200 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 201 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 202 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 203 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 204 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 205 | CLANG_WARN_STRICT_PROTOTYPES = YES; 206 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 207 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 208 | CLANG_WARN_UNREACHABLE_CODE = YES; 209 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 210 | COPY_PHASE_STRIP = NO; 211 | DEBUG_INFORMATION_FORMAT = dwarf; 212 | ENABLE_STRICT_OBJC_MSGSEND = YES; 213 | ENABLE_TESTABILITY = YES; 214 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 215 | GCC_C_LANGUAGE_STANDARD = gnu17; 216 | GCC_DYNAMIC_NO_PIC = NO; 217 | GCC_NO_COMMON_BLOCKS = YES; 218 | GCC_OPTIMIZATION_LEVEL = 0; 219 | GCC_PREPROCESSOR_DEFINITIONS = ( 220 | "DEBUG=1", 221 | "$(inherited)", 222 | ); 223 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 224 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 225 | GCC_WARN_UNDECLARED_SELECTOR = YES; 226 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 227 | GCC_WARN_UNUSED_FUNCTION = YES; 228 | GCC_WARN_UNUSED_VARIABLE = YES; 229 | IPHONEOS_DEPLOYMENT_TARGET = 17.5; 230 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES; 231 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 232 | MTL_FAST_MATH = YES; 233 | ONLY_ACTIVE_ARCH = YES; 234 | SDKROOT = iphoneos; 235 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; 236 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 237 | }; 238 | name = Debug; 239 | }; 240 | F20732452BF5ECD5002F3A39 /* Release */ = { 241 | isa = XCBuildConfiguration; 242 | buildSettings = { 243 | ALWAYS_SEARCH_USER_PATHS = NO; 244 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 245 | CLANG_ANALYZER_NONNULL = YES; 246 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 247 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 248 | CLANG_ENABLE_MODULES = YES; 249 | CLANG_ENABLE_OBJC_ARC = YES; 250 | CLANG_ENABLE_OBJC_WEAK = YES; 251 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 252 | CLANG_WARN_BOOL_CONVERSION = YES; 253 | CLANG_WARN_COMMA = YES; 254 | CLANG_WARN_CONSTANT_CONVERSION = YES; 255 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 256 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 257 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 258 | CLANG_WARN_EMPTY_BODY = YES; 259 | CLANG_WARN_ENUM_CONVERSION = YES; 260 | CLANG_WARN_INFINITE_RECURSION = YES; 261 | CLANG_WARN_INT_CONVERSION = YES; 262 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 263 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 264 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 265 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 266 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 267 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 268 | CLANG_WARN_STRICT_PROTOTYPES = YES; 269 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 270 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 271 | CLANG_WARN_UNREACHABLE_CODE = YES; 272 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 273 | COPY_PHASE_STRIP = NO; 274 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 275 | ENABLE_NS_ASSERTIONS = NO; 276 | ENABLE_STRICT_OBJC_MSGSEND = YES; 277 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 278 | GCC_C_LANGUAGE_STANDARD = gnu17; 279 | GCC_NO_COMMON_BLOCKS = YES; 280 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 281 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 282 | GCC_WARN_UNDECLARED_SELECTOR = YES; 283 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 284 | GCC_WARN_UNUSED_FUNCTION = YES; 285 | GCC_WARN_UNUSED_VARIABLE = YES; 286 | IPHONEOS_DEPLOYMENT_TARGET = 17.5; 287 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES; 288 | MTL_ENABLE_DEBUG_INFO = NO; 289 | MTL_FAST_MATH = YES; 290 | SDKROOT = iphoneos; 291 | SWIFT_COMPILATION_MODE = wholemodule; 292 | VALIDATE_PRODUCT = YES; 293 | }; 294 | name = Release; 295 | }; 296 | F20732472BF5ECD5002F3A39 /* Debug */ = { 297 | isa = XCBuildConfiguration; 298 | buildSettings = { 299 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 300 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 301 | CODE_SIGN_STYLE = Automatic; 302 | CURRENT_PROJECT_VERSION = 1; 303 | DEVELOPMENT_TEAM = 35BGN5XEU6; 304 | GENERATE_INFOPLIST_FILE = YES; 305 | INFOPLIST_FILE = ContextCoreMLDemo/Info.plist; 306 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 307 | INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; 308 | INFOPLIST_KEY_UIMainStoryboardFile = Main; 309 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 310 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 311 | LD_RUNPATH_SEARCH_PATHS = ( 312 | "$(inherited)", 313 | "@executable_path/Frameworks", 314 | ); 315 | MARKETING_VERSION = 1.0; 316 | PRODUCT_BUNDLE_IDENTIFIER = com.contextsdk.ContextCoreMLDemo; 317 | PRODUCT_NAME = "$(TARGET_NAME)"; 318 | SWIFT_EMIT_LOC_STRINGS = YES; 319 | SWIFT_VERSION = 5.0; 320 | TARGETED_DEVICE_FAMILY = "1,2"; 321 | }; 322 | name = Debug; 323 | }; 324 | F20732482BF5ECD5002F3A39 /* Release */ = { 325 | isa = XCBuildConfiguration; 326 | buildSettings = { 327 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 328 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 329 | CODE_SIGN_STYLE = Automatic; 330 | CURRENT_PROJECT_VERSION = 1; 331 | DEVELOPMENT_TEAM = 35BGN5XEU6; 332 | GENERATE_INFOPLIST_FILE = YES; 333 | INFOPLIST_FILE = ContextCoreMLDemo/Info.plist; 334 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 335 | INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; 336 | INFOPLIST_KEY_UIMainStoryboardFile = Main; 337 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 338 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 339 | LD_RUNPATH_SEARCH_PATHS = ( 340 | "$(inherited)", 341 | "@executable_path/Frameworks", 342 | ); 343 | MARKETING_VERSION = 1.0; 344 | PRODUCT_BUNDLE_IDENTIFIER = com.contextsdk.ContextCoreMLDemo; 345 | PRODUCT_NAME = "$(TARGET_NAME)"; 346 | SWIFT_EMIT_LOC_STRINGS = YES; 347 | SWIFT_VERSION = 5.0; 348 | TARGETED_DEVICE_FAMILY = "1,2"; 349 | }; 350 | name = Release; 351 | }; 352 | /* End XCBuildConfiguration section */ 353 | 354 | /* Begin XCConfigurationList section */ 355 | F207322D2BF5ECD3002F3A39 /* Build configuration list for PBXProject "ContextCoreMLDemo" */ = { 356 | isa = XCConfigurationList; 357 | buildConfigurations = ( 358 | F20732442BF5ECD5002F3A39 /* Debug */, 359 | F20732452BF5ECD5002F3A39 /* Release */, 360 | ); 361 | defaultConfigurationIsVisible = 0; 362 | defaultConfigurationName = Release; 363 | }; 364 | F20732462BF5ECD5002F3A39 /* Build configuration list for PBXNativeTarget "ContextCoreMLDemo" */ = { 365 | isa = XCConfigurationList; 366 | buildConfigurations = ( 367 | F20732472BF5ECD5002F3A39 /* Debug */, 368 | F20732482BF5ECD5002F3A39 /* Release */, 369 | ); 370 | defaultConfigurationIsVisible = 0; 371 | defaultConfigurationName = Release; 372 | }; 373 | /* End XCConfigurationList section */ 374 | }; 375 | rootObject = F207322A2BF5ECD3002F3A39 /* Project object */; 376 | } 377 | --------------------------------------------------------------------------------