├── .gitignore ├── LICENSE ├── README.md ├── SwiftChat.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcuserdata │ └── pedro.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── SwiftChat ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── swift-chat copy.png │ │ ├── swift-chat-1024.png │ │ ├── swift-chat-128.png │ │ ├── swift-chat-16.png │ │ ├── swift-chat-256.png │ │ ├── swift-chat-32.png │ │ ├── swift-chat-512.png │ │ └── swift-chat-64.png │ └── Contents.json ├── ContentView.swift ├── ControlView.swift ├── ModelLoader.swift ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json ├── StatusView.swift ├── SwiftChat.entitlements └── SwiftChatApp.swift ├── SwiftChatTests └── SwiftChatTests.swift └── SwiftChatUITests ├── SwiftChatUITests.swift └── SwiftChatUITestsLaunchTests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | xcshareddata/ 2 | pedro.xcuserdatad/ 3 | .DS_Store 4 | xcuserdata 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2022 Hugging Face SAS. 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Swift Chat and Language Model Tester 2 | 3 | This is a small app that shows how to integrate [`swift-transformers`](https://github.com/huggingface/swift-transformers) in a Swift app. 4 | 5 | ![Swift Chat UI](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/swift-transformers/swift-chat-ui.png) 6 | 7 | ## Features and Roadmap 8 | 9 | Please, refer to the [`swift-transformers` repo](https://github.com/huggingface/swift-transformers). 10 | 11 | ## License 12 | 13 | [Apache 2](LICENSE). 14 | -------------------------------------------------------------------------------- /SwiftChat.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 56; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | EB2E91A72A06A45A00FA3ACE /* Transformers in Frameworks */ = {isa = PBXBuildFile; productRef = EB2E91A62A06A45A00FA3ACE /* Transformers */; }; 11 | EB545ED82A0AC32A00C8A5BD /* StatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB545ED72A0AC32A00C8A5BD /* StatusView.swift */; }; 12 | EB57105F2A05962F00BA569B /* Path in Frameworks */ = {isa = PBXBuildFile; productRef = EB57105E2A05962F00BA569B /* Path */; }; 13 | EB90085D2A02C53100B321C4 /* ControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB90085C2A02C53100B321C4 /* ControlView.swift */; }; 14 | EB9008602A02C5D500B321C4 /* CompactSlider in Frameworks */ = {isa = PBXBuildFile; productRef = EB90085F2A02C5D500B321C4 /* CompactSlider */; }; 15 | EB9008692A0578C300B321C4 /* ModelLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB9008682A0578C300B321C4 /* ModelLoader.swift */; }; 16 | EBE1152F2A02AECC000A0CF4 /* SwiftChatApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBE1152E2A02AECC000A0CF4 /* SwiftChatApp.swift */; }; 17 | EBE115312A02AECC000A0CF4 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBE115302A02AECC000A0CF4 /* ContentView.swift */; }; 18 | EBE115332A02AECD000A0CF4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EBE115322A02AECD000A0CF4 /* Assets.xcassets */; }; 19 | EBE115372A02AECD000A0CF4 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EBE115362A02AECD000A0CF4 /* Preview Assets.xcassets */; }; 20 | EBE115412A02AECE000A0CF4 /* SwiftChatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBE115402A02AECE000A0CF4 /* SwiftChatTests.swift */; }; 21 | EBE1154B2A02AECE000A0CF4 /* SwiftChatUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBE1154A2A02AECE000A0CF4 /* SwiftChatUITests.swift */; }; 22 | EBE1154D2A02AECE000A0CF4 /* SwiftChatUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBE1154C2A02AECE000A0CF4 /* SwiftChatUITestsLaunchTests.swift */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXContainerItemProxy section */ 26 | EBE1153D2A02AECE000A0CF4 /* PBXContainerItemProxy */ = { 27 | isa = PBXContainerItemProxy; 28 | containerPortal = EBE115232A02AECC000A0CF4 /* Project object */; 29 | proxyType = 1; 30 | remoteGlobalIDString = EBE1152A2A02AECC000A0CF4; 31 | remoteInfo = SwiftChat; 32 | }; 33 | EBE115472A02AECE000A0CF4 /* PBXContainerItemProxy */ = { 34 | isa = PBXContainerItemProxy; 35 | containerPortal = EBE115232A02AECC000A0CF4 /* Project object */; 36 | proxyType = 1; 37 | remoteGlobalIDString = EBE1152A2A02AECC000A0CF4; 38 | remoteInfo = SwiftChat; 39 | }; 40 | /* End PBXContainerItemProxy section */ 41 | 42 | /* Begin PBXFileReference section */ 43 | EB545ED72A0AC32A00C8A5BD /* StatusView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusView.swift; sourceTree = ""; }; 44 | EB90085C2A02C53100B321C4 /* ControlView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ControlView.swift; sourceTree = ""; }; 45 | EB9008682A0578C300B321C4 /* ModelLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelLoader.swift; sourceTree = ""; }; 46 | EBE1152B2A02AECC000A0CF4 /* SwiftChat.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftChat.app; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | EBE1152E2A02AECC000A0CF4 /* SwiftChatApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftChatApp.swift; sourceTree = ""; }; 48 | EBE115302A02AECC000A0CF4 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 49 | EBE115322A02AECD000A0CF4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 50 | EBE115342A02AECD000A0CF4 /* SwiftChat.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SwiftChat.entitlements; sourceTree = ""; }; 51 | EBE115362A02AECD000A0CF4 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 52 | EBE1153C2A02AECE000A0CF4 /* SwiftChatTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftChatTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 53 | EBE115402A02AECE000A0CF4 /* SwiftChatTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftChatTests.swift; sourceTree = ""; }; 54 | EBE115462A02AECE000A0CF4 /* SwiftChatUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftChatUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 55 | EBE1154A2A02AECE000A0CF4 /* SwiftChatUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftChatUITests.swift; sourceTree = ""; }; 56 | EBE1154C2A02AECE000A0CF4 /* SwiftChatUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftChatUITestsLaunchTests.swift; sourceTree = ""; }; 57 | /* End PBXFileReference section */ 58 | 59 | /* Begin PBXFrameworksBuildPhase section */ 60 | EBE115282A02AECC000A0CF4 /* Frameworks */ = { 61 | isa = PBXFrameworksBuildPhase; 62 | buildActionMask = 2147483647; 63 | files = ( 64 | EB2E91A72A06A45A00FA3ACE /* Transformers in Frameworks */, 65 | EB9008602A02C5D500B321C4 /* CompactSlider in Frameworks */, 66 | EB57105F2A05962F00BA569B /* Path in Frameworks */, 67 | ); 68 | runOnlyForDeploymentPostprocessing = 0; 69 | }; 70 | EBE115392A02AECE000A0CF4 /* Frameworks */ = { 71 | isa = PBXFrameworksBuildPhase; 72 | buildActionMask = 2147483647; 73 | files = ( 74 | ); 75 | runOnlyForDeploymentPostprocessing = 0; 76 | }; 77 | EBE115432A02AECE000A0CF4 /* Frameworks */ = { 78 | isa = PBXFrameworksBuildPhase; 79 | buildActionMask = 2147483647; 80 | files = ( 81 | ); 82 | runOnlyForDeploymentPostprocessing = 0; 83 | }; 84 | /* End PBXFrameworksBuildPhase section */ 85 | 86 | /* Begin PBXGroup section */ 87 | EBE115222A02AECC000A0CF4 = { 88 | isa = PBXGroup; 89 | children = ( 90 | EBE1152D2A02AECC000A0CF4 /* SwiftChat */, 91 | EBE1153F2A02AECE000A0CF4 /* SwiftChatTests */, 92 | EBE115492A02AECE000A0CF4 /* SwiftChatUITests */, 93 | EBE1152C2A02AECC000A0CF4 /* Products */, 94 | ); 95 | sourceTree = ""; 96 | }; 97 | EBE1152C2A02AECC000A0CF4 /* Products */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | EBE1152B2A02AECC000A0CF4 /* SwiftChat.app */, 101 | EBE1153C2A02AECE000A0CF4 /* SwiftChatTests.xctest */, 102 | EBE115462A02AECE000A0CF4 /* SwiftChatUITests.xctest */, 103 | ); 104 | name = Products; 105 | sourceTree = ""; 106 | }; 107 | EBE1152D2A02AECC000A0CF4 /* SwiftChat */ = { 108 | isa = PBXGroup; 109 | children = ( 110 | EBE1152E2A02AECC000A0CF4 /* SwiftChatApp.swift */, 111 | EB90085C2A02C53100B321C4 /* ControlView.swift */, 112 | EBE115302A02AECC000A0CF4 /* ContentView.swift */, 113 | EB545ED72A0AC32A00C8A5BD /* StatusView.swift */, 114 | EBE115322A02AECD000A0CF4 /* Assets.xcassets */, 115 | EBE115342A02AECD000A0CF4 /* SwiftChat.entitlements */, 116 | EBE115352A02AECD000A0CF4 /* Preview Content */, 117 | EB9008682A0578C300B321C4 /* ModelLoader.swift */, 118 | ); 119 | path = SwiftChat; 120 | sourceTree = ""; 121 | }; 122 | EBE115352A02AECD000A0CF4 /* Preview Content */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | EBE115362A02AECD000A0CF4 /* Preview Assets.xcassets */, 126 | ); 127 | path = "Preview Content"; 128 | sourceTree = ""; 129 | }; 130 | EBE1153F2A02AECE000A0CF4 /* SwiftChatTests */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | EBE115402A02AECE000A0CF4 /* SwiftChatTests.swift */, 134 | ); 135 | path = SwiftChatTests; 136 | sourceTree = ""; 137 | }; 138 | EBE115492A02AECE000A0CF4 /* SwiftChatUITests */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | EBE1154A2A02AECE000A0CF4 /* SwiftChatUITests.swift */, 142 | EBE1154C2A02AECE000A0CF4 /* SwiftChatUITestsLaunchTests.swift */, 143 | ); 144 | path = SwiftChatUITests; 145 | sourceTree = ""; 146 | }; 147 | /* End PBXGroup section */ 148 | 149 | /* Begin PBXNativeTarget section */ 150 | EBE1152A2A02AECC000A0CF4 /* SwiftChat */ = { 151 | isa = PBXNativeTarget; 152 | buildConfigurationList = EBE115502A02AECE000A0CF4 /* Build configuration list for PBXNativeTarget "SwiftChat" */; 153 | buildPhases = ( 154 | EBE115272A02AECC000A0CF4 /* Sources */, 155 | EBE115282A02AECC000A0CF4 /* Frameworks */, 156 | EBE115292A02AECC000A0CF4 /* Resources */, 157 | ); 158 | buildRules = ( 159 | ); 160 | dependencies = ( 161 | ); 162 | name = SwiftChat; 163 | packageProductDependencies = ( 164 | EB90085F2A02C5D500B321C4 /* CompactSlider */, 165 | EB57105E2A05962F00BA569B /* Path */, 166 | EB2E91A62A06A45A00FA3ACE /* Transformers */, 167 | ); 168 | productName = SwiftChat; 169 | productReference = EBE1152B2A02AECC000A0CF4 /* SwiftChat.app */; 170 | productType = "com.apple.product-type.application"; 171 | }; 172 | EBE1153B2A02AECE000A0CF4 /* SwiftChatTests */ = { 173 | isa = PBXNativeTarget; 174 | buildConfigurationList = EBE115532A02AECE000A0CF4 /* Build configuration list for PBXNativeTarget "SwiftChatTests" */; 175 | buildPhases = ( 176 | EBE115382A02AECE000A0CF4 /* Sources */, 177 | EBE115392A02AECE000A0CF4 /* Frameworks */, 178 | EBE1153A2A02AECE000A0CF4 /* Resources */, 179 | ); 180 | buildRules = ( 181 | ); 182 | dependencies = ( 183 | EBE1153E2A02AECE000A0CF4 /* PBXTargetDependency */, 184 | ); 185 | name = SwiftChatTests; 186 | productName = SwiftChatTests; 187 | productReference = EBE1153C2A02AECE000A0CF4 /* SwiftChatTests.xctest */; 188 | productType = "com.apple.product-type.bundle.unit-test"; 189 | }; 190 | EBE115452A02AECE000A0CF4 /* SwiftChatUITests */ = { 191 | isa = PBXNativeTarget; 192 | buildConfigurationList = EBE115562A02AECE000A0CF4 /* Build configuration list for PBXNativeTarget "SwiftChatUITests" */; 193 | buildPhases = ( 194 | EBE115422A02AECE000A0CF4 /* Sources */, 195 | EBE115432A02AECE000A0CF4 /* Frameworks */, 196 | EBE115442A02AECE000A0CF4 /* Resources */, 197 | ); 198 | buildRules = ( 199 | ); 200 | dependencies = ( 201 | EBE115482A02AECE000A0CF4 /* PBXTargetDependency */, 202 | ); 203 | name = SwiftChatUITests; 204 | productName = SwiftChatUITests; 205 | productReference = EBE115462A02AECE000A0CF4 /* SwiftChatUITests.xctest */; 206 | productType = "com.apple.product-type.bundle.ui-testing"; 207 | }; 208 | /* End PBXNativeTarget section */ 209 | 210 | /* Begin PBXProject section */ 211 | EBE115232A02AECC000A0CF4 /* Project object */ = { 212 | isa = PBXProject; 213 | attributes = { 214 | BuildIndependentTargetsInParallel = 1; 215 | LastSwiftUpdateCheck = 1430; 216 | LastUpgradeCheck = 1500; 217 | TargetAttributes = { 218 | EBE1152A2A02AECC000A0CF4 = { 219 | CreatedOnToolsVersion = 14.3; 220 | }; 221 | EBE1153B2A02AECE000A0CF4 = { 222 | CreatedOnToolsVersion = 14.3; 223 | TestTargetID = EBE1152A2A02AECC000A0CF4; 224 | }; 225 | EBE115452A02AECE000A0CF4 = { 226 | CreatedOnToolsVersion = 14.3; 227 | TestTargetID = EBE1152A2A02AECC000A0CF4; 228 | }; 229 | }; 230 | }; 231 | buildConfigurationList = EBE115262A02AECC000A0CF4 /* Build configuration list for PBXProject "SwiftChat" */; 232 | compatibilityVersion = "Xcode 14.0"; 233 | developmentRegion = en; 234 | hasScannedForEncodings = 0; 235 | knownRegions = ( 236 | en, 237 | Base, 238 | ); 239 | mainGroup = EBE115222A02AECC000A0CF4; 240 | packageReferences = ( 241 | EB90085E2A02C5D500B321C4 /* XCRemoteSwiftPackageReference "CompactSlider" */, 242 | EB57105D2A05962F00BA569B /* XCRemoteSwiftPackageReference "Path.swift" */, 243 | EB2E91A52A06A45A00FA3ACE /* XCRemoteSwiftPackageReference "swift-transformers" */, 244 | ); 245 | productRefGroup = EBE1152C2A02AECC000A0CF4 /* Products */; 246 | projectDirPath = ""; 247 | projectRoot = ""; 248 | targets = ( 249 | EBE1152A2A02AECC000A0CF4 /* SwiftChat */, 250 | EBE1153B2A02AECE000A0CF4 /* SwiftChatTests */, 251 | EBE115452A02AECE000A0CF4 /* SwiftChatUITests */, 252 | ); 253 | }; 254 | /* End PBXProject section */ 255 | 256 | /* Begin PBXResourcesBuildPhase section */ 257 | EBE115292A02AECC000A0CF4 /* Resources */ = { 258 | isa = PBXResourcesBuildPhase; 259 | buildActionMask = 2147483647; 260 | files = ( 261 | EBE115372A02AECD000A0CF4 /* Preview Assets.xcassets in Resources */, 262 | EBE115332A02AECD000A0CF4 /* Assets.xcassets in Resources */, 263 | ); 264 | runOnlyForDeploymentPostprocessing = 0; 265 | }; 266 | EBE1153A2A02AECE000A0CF4 /* Resources */ = { 267 | isa = PBXResourcesBuildPhase; 268 | buildActionMask = 2147483647; 269 | files = ( 270 | ); 271 | runOnlyForDeploymentPostprocessing = 0; 272 | }; 273 | EBE115442A02AECE000A0CF4 /* Resources */ = { 274 | isa = PBXResourcesBuildPhase; 275 | buildActionMask = 2147483647; 276 | files = ( 277 | ); 278 | runOnlyForDeploymentPostprocessing = 0; 279 | }; 280 | /* End PBXResourcesBuildPhase section */ 281 | 282 | /* Begin PBXSourcesBuildPhase section */ 283 | EBE115272A02AECC000A0CF4 /* Sources */ = { 284 | isa = PBXSourcesBuildPhase; 285 | buildActionMask = 2147483647; 286 | files = ( 287 | EB9008692A0578C300B321C4 /* ModelLoader.swift in Sources */, 288 | EBE115312A02AECC000A0CF4 /* ContentView.swift in Sources */, 289 | EB90085D2A02C53100B321C4 /* ControlView.swift in Sources */, 290 | EBE1152F2A02AECC000A0CF4 /* SwiftChatApp.swift in Sources */, 291 | EB545ED82A0AC32A00C8A5BD /* StatusView.swift in Sources */, 292 | ); 293 | runOnlyForDeploymentPostprocessing = 0; 294 | }; 295 | EBE115382A02AECE000A0CF4 /* Sources */ = { 296 | isa = PBXSourcesBuildPhase; 297 | buildActionMask = 2147483647; 298 | files = ( 299 | EBE115412A02AECE000A0CF4 /* SwiftChatTests.swift in Sources */, 300 | ); 301 | runOnlyForDeploymentPostprocessing = 0; 302 | }; 303 | EBE115422A02AECE000A0CF4 /* Sources */ = { 304 | isa = PBXSourcesBuildPhase; 305 | buildActionMask = 2147483647; 306 | files = ( 307 | EBE1154D2A02AECE000A0CF4 /* SwiftChatUITestsLaunchTests.swift in Sources */, 308 | EBE1154B2A02AECE000A0CF4 /* SwiftChatUITests.swift in Sources */, 309 | ); 310 | runOnlyForDeploymentPostprocessing = 0; 311 | }; 312 | /* End PBXSourcesBuildPhase section */ 313 | 314 | /* Begin PBXTargetDependency section */ 315 | EBE1153E2A02AECE000A0CF4 /* PBXTargetDependency */ = { 316 | isa = PBXTargetDependency; 317 | target = EBE1152A2A02AECC000A0CF4 /* SwiftChat */; 318 | targetProxy = EBE1153D2A02AECE000A0CF4 /* PBXContainerItemProxy */; 319 | }; 320 | EBE115482A02AECE000A0CF4 /* PBXTargetDependency */ = { 321 | isa = PBXTargetDependency; 322 | target = EBE1152A2A02AECC000A0CF4 /* SwiftChat */; 323 | targetProxy = EBE115472A02AECE000A0CF4 /* PBXContainerItemProxy */; 324 | }; 325 | /* End PBXTargetDependency section */ 326 | 327 | /* Begin XCBuildConfiguration section */ 328 | EBE1154E2A02AECE000A0CF4 /* Debug */ = { 329 | isa = XCBuildConfiguration; 330 | buildSettings = { 331 | ALWAYS_SEARCH_USER_PATHS = NO; 332 | CLANG_ANALYZER_NONNULL = YES; 333 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 334 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 335 | CLANG_ENABLE_MODULES = YES; 336 | CLANG_ENABLE_OBJC_ARC = YES; 337 | CLANG_ENABLE_OBJC_WEAK = YES; 338 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 339 | CLANG_WARN_BOOL_CONVERSION = YES; 340 | CLANG_WARN_COMMA = YES; 341 | CLANG_WARN_CONSTANT_CONVERSION = YES; 342 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 343 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 344 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 345 | CLANG_WARN_EMPTY_BODY = YES; 346 | CLANG_WARN_ENUM_CONVERSION = YES; 347 | CLANG_WARN_INFINITE_RECURSION = YES; 348 | CLANG_WARN_INT_CONVERSION = YES; 349 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 350 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 351 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 352 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 353 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 354 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 355 | CLANG_WARN_STRICT_PROTOTYPES = YES; 356 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 357 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 358 | CLANG_WARN_UNREACHABLE_CODE = YES; 359 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 360 | COPY_PHASE_STRIP = NO; 361 | DEAD_CODE_STRIPPING = YES; 362 | DEBUG_INFORMATION_FORMAT = dwarf; 363 | ENABLE_STRICT_OBJC_MSGSEND = YES; 364 | ENABLE_TESTABILITY = YES; 365 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 366 | GCC_C_LANGUAGE_STANDARD = gnu11; 367 | GCC_DYNAMIC_NO_PIC = NO; 368 | GCC_NO_COMMON_BLOCKS = YES; 369 | GCC_OPTIMIZATION_LEVEL = 0; 370 | GCC_PREPROCESSOR_DEFINITIONS = ( 371 | "DEBUG=1", 372 | "$(inherited)", 373 | ); 374 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 375 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 376 | GCC_WARN_UNDECLARED_SELECTOR = YES; 377 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 378 | GCC_WARN_UNUSED_FUNCTION = YES; 379 | GCC_WARN_UNUSED_VARIABLE = YES; 380 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 381 | MTL_FAST_MATH = YES; 382 | ONLY_ACTIVE_ARCH = YES; 383 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 384 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 385 | }; 386 | name = Debug; 387 | }; 388 | EBE1154F2A02AECE000A0CF4 /* Release */ = { 389 | isa = XCBuildConfiguration; 390 | buildSettings = { 391 | ALWAYS_SEARCH_USER_PATHS = NO; 392 | CLANG_ANALYZER_NONNULL = YES; 393 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 394 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 395 | CLANG_ENABLE_MODULES = YES; 396 | CLANG_ENABLE_OBJC_ARC = YES; 397 | CLANG_ENABLE_OBJC_WEAK = YES; 398 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 399 | CLANG_WARN_BOOL_CONVERSION = YES; 400 | CLANG_WARN_COMMA = YES; 401 | CLANG_WARN_CONSTANT_CONVERSION = YES; 402 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 403 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 404 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 405 | CLANG_WARN_EMPTY_BODY = YES; 406 | CLANG_WARN_ENUM_CONVERSION = YES; 407 | CLANG_WARN_INFINITE_RECURSION = YES; 408 | CLANG_WARN_INT_CONVERSION = YES; 409 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 410 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 411 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 412 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 413 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 414 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 415 | CLANG_WARN_STRICT_PROTOTYPES = YES; 416 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 417 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 418 | CLANG_WARN_UNREACHABLE_CODE = YES; 419 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 420 | COPY_PHASE_STRIP = NO; 421 | DEAD_CODE_STRIPPING = YES; 422 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 423 | ENABLE_NS_ASSERTIONS = NO; 424 | ENABLE_STRICT_OBJC_MSGSEND = YES; 425 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 426 | GCC_C_LANGUAGE_STANDARD = gnu11; 427 | GCC_NO_COMMON_BLOCKS = YES; 428 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 429 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 430 | GCC_WARN_UNDECLARED_SELECTOR = YES; 431 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 432 | GCC_WARN_UNUSED_FUNCTION = YES; 433 | GCC_WARN_UNUSED_VARIABLE = YES; 434 | MTL_ENABLE_DEBUG_INFO = NO; 435 | MTL_FAST_MATH = YES; 436 | SWIFT_COMPILATION_MODE = wholemodule; 437 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 438 | }; 439 | name = Release; 440 | }; 441 | EBE115512A02AECE000A0CF4 /* Debug */ = { 442 | isa = XCBuildConfiguration; 443 | buildSettings = { 444 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 445 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 446 | CODE_SIGN_ENTITLEMENTS = SwiftChat/SwiftChat.entitlements; 447 | CODE_SIGN_STYLE = Automatic; 448 | CURRENT_PROJECT_VERSION = 1; 449 | DEAD_CODE_STRIPPING = YES; 450 | DEVELOPMENT_ASSET_PATHS = "\"SwiftChat/Preview Content\""; 451 | DEVELOPMENT_TEAM = 2EADP68M95; 452 | ENABLE_HARDENED_RUNTIME = YES; 453 | ENABLE_PREVIEWS = YES; 454 | GENERATE_INFOPLIST_FILE = YES; 455 | "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; 456 | "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; 457 | "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES; 458 | "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES; 459 | "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES; 460 | "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES; 461 | "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault; 462 | "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault; 463 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 464 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 465 | LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; 466 | "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; 467 | MARKETING_VERSION = 1.0; 468 | PRODUCT_BUNDLE_IDENTIFIER = com.huggingface.SwiftChat; 469 | PRODUCT_NAME = "$(TARGET_NAME)"; 470 | SDKROOT = auto; 471 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; 472 | SWIFT_EMIT_LOC_STRINGS = YES; 473 | SWIFT_VERSION = 5.0; 474 | TARGETED_DEVICE_FAMILY = "1,2"; 475 | }; 476 | name = Debug; 477 | }; 478 | EBE115522A02AECE000A0CF4 /* Release */ = { 479 | isa = XCBuildConfiguration; 480 | buildSettings = { 481 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 482 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 483 | CODE_SIGN_ENTITLEMENTS = SwiftChat/SwiftChat.entitlements; 484 | CODE_SIGN_STYLE = Automatic; 485 | CURRENT_PROJECT_VERSION = 1; 486 | DEAD_CODE_STRIPPING = YES; 487 | DEVELOPMENT_ASSET_PATHS = "\"SwiftChat/Preview Content\""; 488 | DEVELOPMENT_TEAM = 2EADP68M95; 489 | ENABLE_HARDENED_RUNTIME = YES; 490 | ENABLE_PREVIEWS = YES; 491 | GENERATE_INFOPLIST_FILE = YES; 492 | "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; 493 | "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; 494 | "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES; 495 | "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES; 496 | "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES; 497 | "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES; 498 | "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault; 499 | "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault; 500 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 501 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 502 | LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; 503 | "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; 504 | MARKETING_VERSION = 1.0; 505 | PRODUCT_BUNDLE_IDENTIFIER = com.huggingface.SwiftChat; 506 | PRODUCT_NAME = "$(TARGET_NAME)"; 507 | SDKROOT = auto; 508 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; 509 | SWIFT_EMIT_LOC_STRINGS = YES; 510 | SWIFT_VERSION = 5.0; 511 | TARGETED_DEVICE_FAMILY = "1,2"; 512 | }; 513 | name = Release; 514 | }; 515 | EBE115542A02AECE000A0CF4 /* Debug */ = { 516 | isa = XCBuildConfiguration; 517 | buildSettings = { 518 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 519 | BUNDLE_LOADER = "$(TEST_HOST)"; 520 | CODE_SIGN_STYLE = Automatic; 521 | CURRENT_PROJECT_VERSION = 1; 522 | DEAD_CODE_STRIPPING = YES; 523 | DEVELOPMENT_TEAM = ZWDJQ796RU; 524 | GENERATE_INFOPLIST_FILE = YES; 525 | IPHONEOS_DEPLOYMENT_TARGET = 16.4; 526 | MACOSX_DEPLOYMENT_TARGET = 13.3; 527 | MARKETING_VERSION = 1.0; 528 | PRODUCT_BUNDLE_IDENTIFIER = com.latenitesoft.SwiftChatTests; 529 | PRODUCT_NAME = "$(TARGET_NAME)"; 530 | SDKROOT = auto; 531 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; 532 | SWIFT_EMIT_LOC_STRINGS = NO; 533 | SWIFT_VERSION = 5.0; 534 | TARGETED_DEVICE_FAMILY = "1,2"; 535 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftChat.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/SwiftChat"; 536 | }; 537 | name = Debug; 538 | }; 539 | EBE115552A02AECE000A0CF4 /* Release */ = { 540 | isa = XCBuildConfiguration; 541 | buildSettings = { 542 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 543 | BUNDLE_LOADER = "$(TEST_HOST)"; 544 | CODE_SIGN_STYLE = Automatic; 545 | CURRENT_PROJECT_VERSION = 1; 546 | DEAD_CODE_STRIPPING = YES; 547 | DEVELOPMENT_TEAM = ZWDJQ796RU; 548 | GENERATE_INFOPLIST_FILE = YES; 549 | IPHONEOS_DEPLOYMENT_TARGET = 16.4; 550 | MACOSX_DEPLOYMENT_TARGET = 13.3; 551 | MARKETING_VERSION = 1.0; 552 | PRODUCT_BUNDLE_IDENTIFIER = com.latenitesoft.SwiftChatTests; 553 | PRODUCT_NAME = "$(TARGET_NAME)"; 554 | SDKROOT = auto; 555 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; 556 | SWIFT_EMIT_LOC_STRINGS = NO; 557 | SWIFT_VERSION = 5.0; 558 | TARGETED_DEVICE_FAMILY = "1,2"; 559 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftChat.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/SwiftChat"; 560 | }; 561 | name = Release; 562 | }; 563 | EBE115572A02AECE000A0CF4 /* Debug */ = { 564 | isa = XCBuildConfiguration; 565 | buildSettings = { 566 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 567 | CODE_SIGN_STYLE = Automatic; 568 | CURRENT_PROJECT_VERSION = 1; 569 | DEAD_CODE_STRIPPING = YES; 570 | DEVELOPMENT_TEAM = ZWDJQ796RU; 571 | GENERATE_INFOPLIST_FILE = YES; 572 | IPHONEOS_DEPLOYMENT_TARGET = 16.4; 573 | MACOSX_DEPLOYMENT_TARGET = 13.3; 574 | MARKETING_VERSION = 1.0; 575 | PRODUCT_BUNDLE_IDENTIFIER = com.latenitesoft.SwiftChatUITests; 576 | PRODUCT_NAME = "$(TARGET_NAME)"; 577 | SDKROOT = auto; 578 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; 579 | SWIFT_EMIT_LOC_STRINGS = NO; 580 | SWIFT_VERSION = 5.0; 581 | TARGETED_DEVICE_FAMILY = "1,2"; 582 | TEST_TARGET_NAME = SwiftChat; 583 | }; 584 | name = Debug; 585 | }; 586 | EBE115582A02AECE000A0CF4 /* Release */ = { 587 | isa = XCBuildConfiguration; 588 | buildSettings = { 589 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 590 | CODE_SIGN_STYLE = Automatic; 591 | CURRENT_PROJECT_VERSION = 1; 592 | DEAD_CODE_STRIPPING = YES; 593 | DEVELOPMENT_TEAM = ZWDJQ796RU; 594 | GENERATE_INFOPLIST_FILE = YES; 595 | IPHONEOS_DEPLOYMENT_TARGET = 16.4; 596 | MACOSX_DEPLOYMENT_TARGET = 13.3; 597 | MARKETING_VERSION = 1.0; 598 | PRODUCT_BUNDLE_IDENTIFIER = com.latenitesoft.SwiftChatUITests; 599 | PRODUCT_NAME = "$(TARGET_NAME)"; 600 | SDKROOT = auto; 601 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; 602 | SWIFT_EMIT_LOC_STRINGS = NO; 603 | SWIFT_VERSION = 5.0; 604 | TARGETED_DEVICE_FAMILY = "1,2"; 605 | TEST_TARGET_NAME = SwiftChat; 606 | }; 607 | name = Release; 608 | }; 609 | /* End XCBuildConfiguration section */ 610 | 611 | /* Begin XCConfigurationList section */ 612 | EBE115262A02AECC000A0CF4 /* Build configuration list for PBXProject "SwiftChat" */ = { 613 | isa = XCConfigurationList; 614 | buildConfigurations = ( 615 | EBE1154E2A02AECE000A0CF4 /* Debug */, 616 | EBE1154F2A02AECE000A0CF4 /* Release */, 617 | ); 618 | defaultConfigurationIsVisible = 0; 619 | defaultConfigurationName = Release; 620 | }; 621 | EBE115502A02AECE000A0CF4 /* Build configuration list for PBXNativeTarget "SwiftChat" */ = { 622 | isa = XCConfigurationList; 623 | buildConfigurations = ( 624 | EBE115512A02AECE000A0CF4 /* Debug */, 625 | EBE115522A02AECE000A0CF4 /* Release */, 626 | ); 627 | defaultConfigurationIsVisible = 0; 628 | defaultConfigurationName = Release; 629 | }; 630 | EBE115532A02AECE000A0CF4 /* Build configuration list for PBXNativeTarget "SwiftChatTests" */ = { 631 | isa = XCConfigurationList; 632 | buildConfigurations = ( 633 | EBE115542A02AECE000A0CF4 /* Debug */, 634 | EBE115552A02AECE000A0CF4 /* Release */, 635 | ); 636 | defaultConfigurationIsVisible = 0; 637 | defaultConfigurationName = Release; 638 | }; 639 | EBE115562A02AECE000A0CF4 /* Build configuration list for PBXNativeTarget "SwiftChatUITests" */ = { 640 | isa = XCConfigurationList; 641 | buildConfigurations = ( 642 | EBE115572A02AECE000A0CF4 /* Debug */, 643 | EBE115582A02AECE000A0CF4 /* Release */, 644 | ); 645 | defaultConfigurationIsVisible = 0; 646 | defaultConfigurationName = Release; 647 | }; 648 | /* End XCConfigurationList section */ 649 | 650 | /* Begin XCRemoteSwiftPackageReference section */ 651 | EB2E91A52A06A45A00FA3ACE /* XCRemoteSwiftPackageReference "swift-transformers" */ = { 652 | isa = XCRemoteSwiftPackageReference; 653 | repositoryURL = "https://github.com/huggingface/swift-transformers.git"; 654 | requirement = { 655 | branch = main; 656 | kind = branch; 657 | }; 658 | }; 659 | EB57105D2A05962F00BA569B /* XCRemoteSwiftPackageReference "Path.swift" */ = { 660 | isa = XCRemoteSwiftPackageReference; 661 | repositoryURL = "https://github.com/mxcl/Path.swift.git"; 662 | requirement = { 663 | kind = upToNextMajorVersion; 664 | minimumVersion = 1.0.0; 665 | }; 666 | }; 667 | EB90085E2A02C5D500B321C4 /* XCRemoteSwiftPackageReference "CompactSlider" */ = { 668 | isa = XCRemoteSwiftPackageReference; 669 | repositoryURL = "https://github.com/buh/CompactSlider.git"; 670 | requirement = { 671 | kind = upToNextMajorVersion; 672 | minimumVersion = 1.0.0; 673 | }; 674 | }; 675 | /* End XCRemoteSwiftPackageReference section */ 676 | 677 | /* Begin XCSwiftPackageProductDependency section */ 678 | EB2E91A62A06A45A00FA3ACE /* Transformers */ = { 679 | isa = XCSwiftPackageProductDependency; 680 | package = EB2E91A52A06A45A00FA3ACE /* XCRemoteSwiftPackageReference "swift-transformers" */; 681 | productName = Transformers; 682 | }; 683 | EB57105E2A05962F00BA569B /* Path */ = { 684 | isa = XCSwiftPackageProductDependency; 685 | package = EB57105D2A05962F00BA569B /* XCRemoteSwiftPackageReference "Path.swift" */; 686 | productName = Path; 687 | }; 688 | EB90085F2A02C5D500B321C4 /* CompactSlider */ = { 689 | isa = XCSwiftPackageProductDependency; 690 | package = EB90085E2A02C5D500B321C4 /* XCRemoteSwiftPackageReference "CompactSlider" */; 691 | productName = CompactSlider; 692 | }; 693 | /* End XCSwiftPackageProductDependency section */ 694 | }; 695 | rootObject = EBE115232A02AECC000A0CF4 /* Project object */; 696 | } 697 | -------------------------------------------------------------------------------- /SwiftChat.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SwiftChat.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SwiftChat.xcodeproj/xcuserdata/pedro.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SwiftChat.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /SwiftChat/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 | -------------------------------------------------------------------------------- /SwiftChat/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "swift-chat copy.png", 5 | "idiom" : "universal", 6 | "platform" : "ios", 7 | "size" : "1024x1024" 8 | }, 9 | { 10 | "filename" : "swift-chat-16.png", 11 | "idiom" : "mac", 12 | "scale" : "1x", 13 | "size" : "16x16" 14 | }, 15 | { 16 | "filename" : "swift-chat-32.png", 17 | "idiom" : "mac", 18 | "scale" : "2x", 19 | "size" : "16x16" 20 | }, 21 | { 22 | "filename" : "swift-chat-32.png", 23 | "idiom" : "mac", 24 | "scale" : "1x", 25 | "size" : "32x32" 26 | }, 27 | { 28 | "filename" : "swift-chat-64.png", 29 | "idiom" : "mac", 30 | "scale" : "2x", 31 | "size" : "32x32" 32 | }, 33 | { 34 | "filename" : "swift-chat-128.png", 35 | "idiom" : "mac", 36 | "scale" : "1x", 37 | "size" : "128x128" 38 | }, 39 | { 40 | "filename" : "swift-chat-256.png", 41 | "idiom" : "mac", 42 | "scale" : "2x", 43 | "size" : "128x128" 44 | }, 45 | { 46 | "filename" : "swift-chat-256.png", 47 | "idiom" : "mac", 48 | "scale" : "1x", 49 | "size" : "256x256" 50 | }, 51 | { 52 | "filename" : "swift-chat-512.png", 53 | "idiom" : "mac", 54 | "scale" : "2x", 55 | "size" : "256x256" 56 | }, 57 | { 58 | "filename" : "swift-chat-512.png", 59 | "idiom" : "mac", 60 | "scale" : "1x", 61 | "size" : "512x512" 62 | }, 63 | { 64 | "filename" : "swift-chat-1024.png", 65 | "idiom" : "mac", 66 | "scale" : "2x", 67 | "size" : "512x512" 68 | } 69 | ], 70 | "info" : { 71 | "author" : "xcode", 72 | "version" : 1 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /SwiftChat/Assets.xcassets/AppIcon.appiconset/swift-chat copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huggingface/swift-chat/7e9c33255f9801e8d59cf5ebbb5793a23c9d136e/SwiftChat/Assets.xcassets/AppIcon.appiconset/swift-chat copy.png -------------------------------------------------------------------------------- /SwiftChat/Assets.xcassets/AppIcon.appiconset/swift-chat-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huggingface/swift-chat/7e9c33255f9801e8d59cf5ebbb5793a23c9d136e/SwiftChat/Assets.xcassets/AppIcon.appiconset/swift-chat-1024.png -------------------------------------------------------------------------------- /SwiftChat/Assets.xcassets/AppIcon.appiconset/swift-chat-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huggingface/swift-chat/7e9c33255f9801e8d59cf5ebbb5793a23c9d136e/SwiftChat/Assets.xcassets/AppIcon.appiconset/swift-chat-128.png -------------------------------------------------------------------------------- /SwiftChat/Assets.xcassets/AppIcon.appiconset/swift-chat-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huggingface/swift-chat/7e9c33255f9801e8d59cf5ebbb5793a23c9d136e/SwiftChat/Assets.xcassets/AppIcon.appiconset/swift-chat-16.png -------------------------------------------------------------------------------- /SwiftChat/Assets.xcassets/AppIcon.appiconset/swift-chat-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huggingface/swift-chat/7e9c33255f9801e8d59cf5ebbb5793a23c9d136e/SwiftChat/Assets.xcassets/AppIcon.appiconset/swift-chat-256.png -------------------------------------------------------------------------------- /SwiftChat/Assets.xcassets/AppIcon.appiconset/swift-chat-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huggingface/swift-chat/7e9c33255f9801e8d59cf5ebbb5793a23c9d136e/SwiftChat/Assets.xcassets/AppIcon.appiconset/swift-chat-32.png -------------------------------------------------------------------------------- /SwiftChat/Assets.xcassets/AppIcon.appiconset/swift-chat-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huggingface/swift-chat/7e9c33255f9801e8d59cf5ebbb5793a23c9d136e/SwiftChat/Assets.xcassets/AppIcon.appiconset/swift-chat-512.png -------------------------------------------------------------------------------- /SwiftChat/Assets.xcassets/AppIcon.appiconset/swift-chat-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huggingface/swift-chat/7e9c33255f9801e8d59cf5ebbb5793a23c9d136e/SwiftChat/Assets.xcassets/AppIcon.appiconset/swift-chat-64.png -------------------------------------------------------------------------------- /SwiftChat/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /SwiftChat/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // SwiftChat 4 | // 5 | // Created by Pedro Cuenca on April 2023 6 | // Based on code by Cyril Zakka from https://github.com/cyrilzakka/pen 7 | // 8 | 9 | import SwiftUI 10 | import Generation 11 | import Models 12 | 13 | enum ModelState: Equatable { 14 | case noModel 15 | case loading 16 | case ready(Double?) 17 | case generating(Double) 18 | case failed(String) 19 | } 20 | 21 | struct ContentView: View { 22 | 23 | @Environment(\.horizontalSizeClass) private var horizontalSizeClass 24 | @Environment(\.verticalSizeClass) private var verticalSizeClass 25 | 26 | @State private var config = GenerationConfig(maxNewTokens: 20) 27 | @State private var prompt = "Write a poem about Valencia\n" 28 | @State private var modelURL: URL? = nil 29 | @State private var languageModel: LanguageModel? = nil 30 | 31 | @State private var isSettingsPresented = false 32 | @State private var isFirstLaunch = true 33 | 34 | @State private var status: ModelState = .noModel 35 | @State private var outputText: AttributedString = "" 36 | 37 | @Binding var clearTriggered: Bool 38 | 39 | func modelDidChange() { 40 | guard status != .loading else { return } 41 | 42 | status = .loading 43 | Task.init { 44 | do { 45 | languageModel = try await ModelLoader.load(url: modelURL) 46 | if let config = languageModel?.defaultGenerationConfig { 47 | let maxNewTokens = self.config.maxNewTokens 48 | self.config = config 49 | Task.init { 50 | // Refresh after slider limits have been updated 51 | self.config.maxNewTokens = min(maxNewTokens, languageModel?.maxContextLength ?? 20) 52 | } 53 | } 54 | status = .ready(nil) 55 | isSettingsPresented = false 56 | } catch { 57 | print("No model could be loaded: \(error)") 58 | status = .noModel 59 | } 60 | 61 | } 62 | } 63 | 64 | func clear() { 65 | outputText = "" 66 | } 67 | 68 | func run() { 69 | guard let languageModel = languageModel else { return } 70 | 71 | @Sendable func showOutput(currentGeneration: String, progress: Double, completedTokensPerSecond: Double? = nil) { 72 | Task { @MainActor in 73 | // Temporary hack to remove start token returned by llama tokenizers 74 | var response = currentGeneration.deletingPrefix(" ") 75 | 76 | // Strip prompt 77 | guard response.count > prompt.count else { return } 78 | response = response[prompt.endIndex...].replacingOccurrences(of: "\\n", with: "\n") 79 | 80 | // Format prompt + response with different colors 81 | var styledPrompt = AttributedString(prompt) 82 | styledPrompt.foregroundColor = .black 83 | 84 | var styledOutput = AttributedString(response) 85 | styledOutput.foregroundColor = .accentColor 86 | 87 | outputText = styledPrompt + styledOutput 88 | if let tps = completedTokensPerSecond { 89 | status = .ready(tps) 90 | } else { 91 | status = .generating(progress) 92 | } 93 | } 94 | } 95 | 96 | Task.init { 97 | status = .generating(0) 98 | var tokensReceived = 0 99 | let begin = Date() 100 | do { 101 | let output = try await languageModel.generate(config: config, prompt: prompt) { inProgressGeneration in 102 | tokensReceived += 1 103 | showOutput(currentGeneration: inProgressGeneration, progress: Double(tokensReceived)/Double(config.maxNewTokens)) 104 | } 105 | let completionTime = Date().timeIntervalSince(begin) 106 | let tokensPerSecond = Double(tokensReceived) / completionTime 107 | showOutput(currentGeneration: output, progress: 1, completedTokensPerSecond: tokensPerSecond) 108 | print("Took \(completionTime)") 109 | } catch { 110 | print("Error \(error)") 111 | Task { @MainActor in 112 | status = .failed("\(error)") 113 | } 114 | } 115 | } 116 | } 117 | 118 | @ViewBuilder 119 | var runButton: some View { 120 | switch status { 121 | case .noModel: 122 | EmptyView() 123 | case .loading: 124 | ProgressView().controlSize(.small).padding(.trailing, 6) 125 | case .ready, .failed: 126 | Button(action: run) { Label("Run", systemImage: "play.fill") } 127 | .keyboardShortcut("R") 128 | case .generating(let progress): 129 | ProgressView(value: progress).controlSize(.small).progressViewStyle(.circular).padding(.trailing, 6) 130 | } 131 | } 132 | 133 | var chatView: some View { 134 | GeometryReader { geometry in 135 | VStack { 136 | VStack(alignment: .leading, spacing: 4) { 137 | Text("Your input (use format appropriate for the model you are using)") 138 | .font(.caption) 139 | .foregroundColor(.gray) 140 | 141 | TextEditor(text: $prompt) 142 | .font(.body) 143 | .fontDesign(.rounded) 144 | .scrollContentBackground(.hidden) 145 | .multilineTextAlignment(.leading) 146 | .padding(.all, 4) 147 | .overlay( 148 | RoundedRectangle(cornerRadius: 8) 149 | .stroke(Color.gray.opacity(0.5), lineWidth: 1) 150 | ) 151 | } 152 | .frame(height: 100) 153 | .padding(.bottom, 16) 154 | 155 | VStack(alignment: .leading, spacing: 4) { 156 | Text("Language Model Output") 157 | .font(.caption) 158 | .foregroundColor(.gray) 159 | 160 | Text(outputText) 161 | .font(.system(size: 14)) 162 | .foregroundColor(.blue) 163 | .multilineTextAlignment(.leading) 164 | .lineLimit(nil) 165 | .frame(minWidth: geometry.size.width - 44, minHeight: 200, alignment: Alignment(horizontal: .leading, vertical: .top)) 166 | .padding(.all, 4) 167 | .overlay( 168 | RoundedRectangle(cornerRadius: 8) 169 | .stroke(Color.gray.opacity(0.5), lineWidth: 1) 170 | ) 171 | .onChange(of: clearTriggered) { _, _ in 172 | clear() 173 | } 174 | } 175 | } 176 | .padding() 177 | .toolbar { 178 | ToolbarItem(placement: .primaryAction) { 179 | runButton 180 | } 181 | } 182 | } 183 | .navigationTitle("Language Model Tester") 184 | } 185 | 186 | var regularView: some View { 187 | NavigationSplitView { 188 | VStack { 189 | ControlView(prompt: prompt, config: $config, model: $languageModel, modelURL: $modelURL) 190 | StatusView(status: $status) 191 | } 192 | .navigationSplitViewColumnWidth(min: 250, ideal: 300) 193 | } detail: { 194 | chatView 195 | } 196 | } 197 | 198 | #if os(iOS) 199 | var compactView: some View { 200 | NavigationView { 201 | VStack { 202 | chatView 203 | StatusView(status: $status) 204 | } 205 | .navigationBarTitleDisplayMode(.inline) 206 | .toolbar { 207 | ToolbarItem(placement: .topBarLeading) { 208 | Button("Settings", systemImage: "gear") { 209 | isSettingsPresented = true 210 | } 211 | } 212 | } 213 | } 214 | .onAppear { 215 | if isFirstLaunch { 216 | isSettingsPresented = true 217 | isFirstLaunch = false 218 | } 219 | } 220 | .sheet(isPresented: $isSettingsPresented) { 221 | NavigationView { 222 | VStack { 223 | ControlView(prompt: prompt, config: $config, model: $languageModel, modelURL: $modelURL) 224 | StatusView(status: $status) 225 | } 226 | .navigationTitle("Settings") 227 | .navigationBarTitleDisplayMode(.inline) 228 | .toolbar { 229 | ToolbarItem(placement: .confirmationAction) { 230 | Button("Done") { 231 | isSettingsPresented = false 232 | } 233 | } 234 | } 235 | } 236 | } 237 | } 238 | #endif 239 | 240 | var body: some View { 241 | Group { 242 | #if os(iOS) 243 | if horizontalSizeClass == .compact && (verticalSizeClass == .compact || verticalSizeClass == .regular) { 244 | compactView 245 | } else { 246 | regularView 247 | } 248 | #else 249 | regularView 250 | #endif 251 | } 252 | .onAppear { 253 | modelDidChange() 254 | } 255 | .onChange(of: modelURL) { 256 | modelDidChange() 257 | } 258 | } 259 | } 260 | 261 | struct ContentView_Previews: PreviewProvider { 262 | static var previews: some View { 263 | ContentView(clearTriggered: .constant(false)) 264 | } 265 | } 266 | 267 | extension String { 268 | func deletingPrefix(_ prefix: String) -> String { 269 | guard hasPrefix(prefix) else { return self } 270 | return String(dropFirst(prefix.count)) 271 | } 272 | } 273 | -------------------------------------------------------------------------------- /SwiftChat/ControlView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ControlView.swift 3 | // SwiftChat 4 | // 5 | // Created by Cyril Zakka on 4/3/23. 6 | // 7 | 8 | import SwiftUI 9 | import CompactSlider 10 | import Models 11 | import Generation 12 | import UniformTypeIdentifiers 13 | 14 | struct ControlView: View { 15 | var prompt: String = "" 16 | @Binding var config: GenerationConfig 17 | @Binding var model: LanguageModel? 18 | @Binding var modelURL: URL? 19 | 20 | @State var discloseParams = true 21 | 22 | @State var discloseAdvanced = true 23 | @State private var topK = 40.0 24 | @State private var freqPenalty = 2.0 25 | @State private var presPenalty = 0.9 26 | 27 | @State var disclosedModel = true 28 | @State private var showFilePicker = false 29 | 30 | 31 | var body: some View { 32 | VStack(alignment: .leading) { 33 | ScrollView { 34 | Group { 35 | DisclosureGroup(isExpanded: $discloseParams) { 36 | Spacer() 37 | CompactSlider(value: $config.temperature, in: 0...2, direction: .center) { 38 | Text("Temperature") 39 | Spacer() 40 | Text("\(config.temperature, specifier: "%.2f")") 41 | }.compactSliderStyle( 42 | .prominent( 43 | lowerColor: .blue, 44 | upperColor: .red, 45 | useGradientBackground: true 46 | ) 47 | ) 48 | .compactSliderSecondaryColor(config.temperature <= 0.5 ? .blue : .red) 49 | .disabled(!config.doSample) 50 | .help("Controls randomness: Lowering results in less random completions. As the temperature approaches zero, the model will become deterministic and repetitive.") 51 | 52 | CompactSlider(value: Binding { 53 | CFloat(config.topK) 54 | } set: { 55 | config.topK = Int($0) 56 | }, in: 1...50, step: 1) { 57 | Text("Top K") 58 | Spacer() 59 | Text("\(config.topK)") 60 | } 61 | .compactSliderSecondaryColor(.blue) 62 | .disabled(!config.doSample) 63 | .help("Sort predicted tokens by probability and discards those below the k-th one. A top-k value of 1 is equivalent to greedy search (select the most probable token)") 64 | 65 | CompactSlider(value: Binding { 66 | CFloat(config.maxNewTokens) 67 | } set: { 68 | config.maxNewTokens = Int($0) 69 | }, in: CFloat(1)...CFloat(model?.maxContextLength ?? 128), step: 1) { 70 | Text("Maximum Length") 71 | Spacer() 72 | Text("\(Int(config.maxNewTokens))") 73 | } 74 | .compactSliderSecondaryColor(.blue) 75 | .disabled(model == nil) 76 | .help("The maximum number of tokens to generate. Requests can use up to 2,048 tokens shared between prompt and completion. The exact limit varies by model. (One token is roughly 4 characters for normal English text)") 77 | } label: { 78 | HStack { 79 | Label("Parameters", systemImage: "slider.horizontal.3").foregroundColor(.secondary) 80 | Spacer() 81 | } 82 | } 83 | } 84 | 85 | HStack { 86 | Toggle(isOn: $config.doSample) { Text("Sample") } 87 | Spacer() 88 | } 89 | 90 | Divider() 91 | 92 | // Group { 93 | // DisclosureGroup(isExpanded: $discloseAdvanced) { 94 | // Spacer() 95 | // CompactSlider(value: $config.topP) { 96 | // Text("Top P") 97 | // Spacer() 98 | // Text("\(config.topP, specifier: "%.2f")") 99 | // } 100 | // .help("Controls diversity via nucleus sampling: 0.5 means half of all likelihood-weighted options are considered.") 101 | // CompactSlider(value: Binding { 102 | // Darwin.sqrt(CGFloat(config.repetitionPenalty)) 103 | // } set: { 104 | // config.repetitionPenalty = Darwin.pow($0, 2) 105 | // }, in: 1...sqrt(CGFloat(10))) { 106 | // Text("Frequency Penalty") 107 | // Spacer() 108 | // Text("\(config.repetitionPenalty, specifier: "%.1f")") 109 | // }.help("How much to penalize new tokens based on their existing frequency in the text so far. Decreases the model's likelihood to repeat the same line verbatim.") 110 | // } label: { 111 | // HStack { 112 | // Label("Advanced", systemImage: "wrench.adjustable").foregroundColor(.secondary) 113 | // Spacer() 114 | // } 115 | // } 116 | // .compactSliderSecondaryColor(.blue) 117 | // } 118 | // 119 | // Divider() 120 | 121 | Group { 122 | DisclosureGroup(isExpanded: $disclosedModel) { 123 | Spacer() 124 | Button(action: { 125 | showFilePicker.toggle() 126 | }, label: { 127 | 128 | Text(model?.description ?? "Select model...") 129 | .frame(maxWidth: .infinity) 130 | .padding(.vertical, 7) 131 | .overlay( 132 | RoundedRectangle(cornerRadius: 5) 133 | .stroke(Color.secondary, lineWidth: 2) 134 | ) 135 | }) 136 | .buttonStyle(.borderless) 137 | .controlSize(.large) 138 | .frame(maxWidth: .infinity) 139 | .cornerRadius(5) 140 | .fileImporter(isPresented: $showFilePicker, allowedContentTypes: [.mlpackage, .mlmodelc], allowsMultipleSelection: false) { result in 141 | switch result { 142 | case .success(let urls): 143 | modelURL = urls.first 144 | case .failure(let error): 145 | print("Import failed: \(error.localizedDescription)") 146 | } 147 | } 148 | 149 | } label: { 150 | HStack { 151 | Label("Models", systemImage: "cpu").foregroundColor(.secondary) 152 | Spacer() 153 | } 154 | } 155 | } 156 | 157 | } 158 | } 159 | .padding() 160 | } 161 | } 162 | 163 | private extension UTType { 164 | static let mlpackage = UTType(filenameExtension: "mlpackage", conformingTo: .item)! 165 | static let mlmodelc = UTType(filenameExtension: "mlmodelc", conformingTo: .item)! 166 | } 167 | -------------------------------------------------------------------------------- /SwiftChat/ModelLoader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ModelLoader.swift 3 | // SwiftChat 4 | // 5 | // Created by Pedro Cuenca on 5/5/23. 6 | // 7 | 8 | import CoreML 9 | import Path 10 | import Models 11 | 12 | class ModelLoader { 13 | static let models = Path.applicationSupport / "hf-compiled-transformers" 14 | static let lastCompiledModel = models / "last-model.mlmodelc" 15 | 16 | static func load(url: URL?) async throws -> LanguageModel { 17 | func clearModels() throws { 18 | try models.delete() 19 | try ModelLoader.models.mkdir(.p) 20 | } 21 | 22 | if let url = url, url.startAccessingSecurityScopedResource() { 23 | defer { 24 | url.stopAccessingSecurityScopedResource() 25 | } 26 | let compiledPath = models / url.deletingPathExtension().appendingPathExtension("mlmodelc").lastPathComponent 27 | if url.pathExtension == "mlmodelc" { 28 | // _copy_ to the models folder 29 | try clearModels() 30 | try Path(url: url)?.copy(to: compiledPath, overwrite: true) 31 | } else { 32 | // Compile and _move_ 33 | print("Compiling model \(url)") 34 | let compiledURL = try await MLModel.compileModel(at: url) 35 | try clearModels() 36 | try Path(url: compiledURL)?.move(to: compiledPath, overwrite: true) 37 | } 38 | 39 | // Create symlink (alternative: store name in UserDefaults) 40 | try compiledPath.symlink(as: lastCompiledModel) 41 | } 42 | 43 | // Load last model used (or the one we just compiled) 44 | let lastURL = try lastCompiledModel.readlink().url 45 | return try LanguageModel.loadCompiled(url: lastURL, computeUnits: .cpuAndGPU) 46 | } 47 | } 48 | 49 | import Combine 50 | 51 | extension LanguageModel: ObservableObject {} 52 | -------------------------------------------------------------------------------- /SwiftChat/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /SwiftChat/StatusView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StatusView.swift 3 | // 4 | // Initially created by Cyril Zakka on 1/12/23. 5 | // 6 | 7 | import SwiftUI 8 | 9 | struct StatusView: View { 10 | @Binding var status: ModelState 11 | 12 | @State private var showErrorPopover = false 13 | 14 | func errorWithDetails(_ message: String, error: Error) -> any View { 15 | HStack { 16 | Text(message) 17 | Spacer() 18 | Button { 19 | showErrorPopover.toggle() 20 | } label: { 21 | Image(systemName: "info.circle") 22 | }.buttonStyle(.plain) 23 | .popover(isPresented: $showErrorPopover) { 24 | VStack { 25 | Text(verbatim: "\(error)") 26 | .lineLimit(nil) 27 | .padding(.all, 5) 28 | Button { 29 | showErrorPopover.toggle() 30 | } label: { 31 | Text("Dismiss").frame(maxWidth: 200) 32 | } 33 | .padding(.bottom) 34 | } 35 | .frame(minWidth: 400, idealWidth: 400, maxWidth: 400) 36 | .fixedSize() 37 | } 38 | } 39 | } 40 | 41 | var body: some View { 42 | switch status { 43 | case .noModel: Text("Please, select a model").frame(height: 50) 44 | case .loading: Text("Loading model…").frame(height: 50) 45 | case .generating(let progress): 46 | let label = progress > 0 ? "Generating…" : "Preparing…" 47 | ProgressView(label, value: progress, total: 1).padding().frame(height: 50) 48 | .progressViewStyle(LinearProgressViewStyle(tint: Color.gray)) 49 | case .ready(let tps): 50 | if let tps = tps { 51 | HStack { 52 | Spacer() 53 | Text("Ready") 54 | Spacer() 55 | Text("\(tps, specifier: "%.2f") tokens/s").padding(.trailing) 56 | }.frame(height: 50) 57 | } else { 58 | Text("Ready").frame(height: 50) 59 | } 60 | case .failed(let errorMessage): 61 | Text("Error: \(errorMessage)").frame(height: 50) 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /SwiftChat/SwiftChat.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.kernel.increased-memory-limit 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SwiftChat/SwiftChatApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftChatApp.swift 3 | // SwiftChat 4 | // 5 | // Created by Pedro Cuenca on 3/5/23. 6 | // 7 | 8 | import SwiftUI 9 | 10 | @main 11 | struct SwiftChatApp: App { 12 | @State private var clearTriggered = false 13 | 14 | var body: some Scene { 15 | WindowGroup { 16 | ContentView(clearTriggered: $clearTriggered) 17 | } 18 | .commands { 19 | CommandGroup(after: .pasteboard) { 20 | Button(action: { 21 | print("clear") 22 | self.clearTriggered.toggle() 23 | }) { 24 | Text("Clear Output") 25 | } 26 | .keyboardShortcut(.delete, modifiers: [.command]) 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /SwiftChatTests/SwiftChatTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftChatTests.swift 3 | // SwiftChatTests 4 | // 5 | // Created by Pedro Cuenca on 3/5/23. 6 | // 7 | 8 | import XCTest 9 | 10 | final class SwiftChatTests: XCTestCase { 11 | 12 | override func setUpWithError() throws { 13 | // Put setup code here. This method is called before the invocation of each test method in the class. 14 | } 15 | 16 | override func tearDownWithError() throws { 17 | // Put teardown code here. This method is called after the invocation of each test method in the class. 18 | } 19 | 20 | func testExample() throws { 21 | // This is an example of a functional test case. 22 | // Use XCTAssert and related functions to verify your tests produce the correct results. 23 | // Any test you write for XCTest can be annotated as throws and async. 24 | // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. 25 | // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. 26 | } 27 | 28 | func testPerformanceExample() throws { 29 | // This is an example of a performance test case. 30 | measure { 31 | // Put the code you want to measure the time of here. 32 | } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /SwiftChatUITests/SwiftChatUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftChatUITests.swift 3 | // SwiftChatUITests 4 | // 5 | // Created by Pedro Cuenca on 3/5/23. 6 | // 7 | 8 | import XCTest 9 | 10 | final class SwiftChatUITests: XCTestCase { 11 | 12 | override func setUpWithError() throws { 13 | // Put setup code here. This method is called before the invocation of each test method in the class. 14 | 15 | // In UI tests it is usually best to stop immediately when a failure occurs. 16 | continueAfterFailure = false 17 | 18 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 19 | } 20 | 21 | override func tearDownWithError() throws { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | } 24 | 25 | func testExample() throws { 26 | // UI tests must launch the application that they test. 27 | let app = XCUIApplication() 28 | app.launch() 29 | 30 | // Use XCTAssert and related functions to verify your tests produce the correct results. 31 | } 32 | 33 | func testLaunchPerformance() throws { 34 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) { 35 | // This measures how long it takes to launch your application. 36 | measure(metrics: [XCTApplicationLaunchMetric()]) { 37 | XCUIApplication().launch() 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /SwiftChatUITests/SwiftChatUITestsLaunchTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftChatUITestsLaunchTests.swift 3 | // SwiftChatUITests 4 | // 5 | // Created by Pedro Cuenca on 3/5/23. 6 | // 7 | 8 | import XCTest 9 | 10 | final class SwiftChatUITestsLaunchTests: XCTestCase { 11 | 12 | override class var runsForEachTargetApplicationUIConfiguration: Bool { 13 | true 14 | } 15 | 16 | override func setUpWithError() throws { 17 | continueAfterFailure = false 18 | } 19 | 20 | func testLaunch() throws { 21 | let app = XCUIApplication() 22 | app.launch() 23 | 24 | // Insert steps here to perform after app launch but before taking a screenshot, 25 | // such as logging into a test account or navigating somewhere in the app 26 | 27 | let attachment = XCTAttachment(screenshot: app.screenshot()) 28 | attachment.name = "Launch Screen" 29 | attachment.lifetime = .keepAlways 30 | add(attachment) 31 | } 32 | } 33 | --------------------------------------------------------------------------------