├── .gitignore
├── LICENSE
├── OllamaGUI
├── Assets.xcassets
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── ChainIcon.imageset
│ │ ├── Contents.json
│ │ └── chain.svg
│ ├── ChatColor.colorset
│ │ └── Contents.json
│ ├── ChatHoverColor.colorset
│ │ └── Contents.json
│ ├── Contents.json
│ ├── MicIcon.imageset
│ │ ├── Contents.json
│ │ └── mic.svg
│ ├── MopIcon.imageset
│ │ ├── Contents.json
│ │ └── mop.svg
│ ├── OllamaIcon.imageset
│ │ ├── Contents.json
│ │ └── ollama.png
│ ├── PinIcon.imageset
│ │ ├── Contents.json
│ │ └── pin.svg
│ ├── SettingIcon.imageset
│ │ ├── Contents.json
│ │ └── settings_FILL0_wght200_GRAD0_opsz24.svg
│ ├── SidebarColor.colorset
│ │ └── Contents.json
│ └── SidebarIconColor.colorset
│ │ └── Contents.json
├── Core
│ ├── Loadable.swift
│ └── NetworkError.swift
├── Data
│ ├── AppSettingEntity.swift
│ ├── ChatEntity.swift
│ ├── MessageEntity.swift
│ ├── RoomEntity.swift
│ ├── RoomOptionEntity.swift
│ └── chat.xcdatamodeld
│ │ └── chat.xcdatamodel
│ │ └── contents
├── Enum.swift
├── Enum
│ ├── RoleEnum.swift
│ └── RouterEnum.swift
├── Helper
│ ├── DateHelper.swift
│ ├── DescribableEnum.swift
│ ├── DictionaryEncoder.swift
│ ├── HtmlHelper.swift
│ ├── IntHelper.swift
│ ├── MarkdownTheme.swift
│ ├── NetworkHelper.swift
│ ├── RandomGenerator.swift
│ ├── StringHelper.swift
│ ├── ViewHelper.swift
│ └── WindowHelper.swift
├── Info.plist
├── Injected
│ ├── AppSetting.swift
│ ├── DIContainer.swift
│ ├── DataInteractor.swift
│ ├── Interactor.swift
│ └── UpdateTrigger.swift
├── LangChain
│ ├── DocumentLoader
│ │ ├── BaseLoader.swift
│ │ └── HTMLLoader.swift
│ ├── Error
│ │ └── LangchainError.swift
│ ├── Util
│ │ └── TextSplitter.swift
│ └── VectorStore
│ │ └── USearchUtil.swift
├── Model
│ ├── ChatModel.swift
│ ├── ChatRequestModel.swift
│ ├── MessageModel.swift
│ ├── ModelDeleteRequestModel.swift
│ ├── ModelInfoModel.swift
│ ├── ModelList.swift
│ ├── OllamaTagModel.swift
│ ├── OllmaModel.swift
│ ├── OptionModel.swift
│ ├── PullRequestModel.swift
│ └── PullResponseModel.swift
├── Preview Content
│ └── Preview Assets.xcassets
│ │ └── Contents.json
├── UI
│ ├── BubbleShape.swift
│ ├── ChatBubble.swift
│ ├── ChatHeader.swift
│ ├── ChatView.swift
│ ├── ChatViewModel.swift
│ ├── Commen
│ │ ├── ClearButton.swift
│ │ ├── CommonButton.swift
│ │ ├── Controller
│ │ │ └── KeyPressedController.swift
│ │ ├── EditorButton.swift
│ │ ├── FloatingWindow.swift
│ │ ├── SidebarButton.swift
│ │ └── XProgressView.swift
│ ├── Home
│ │ └── HomeView.swift
│ ├── LangchainSheet.swift
│ ├── Manager
│ │ ├── Components
│ │ │ ├── LibraryModelListView.swift
│ │ │ └── ModelListView.swift
│ │ └── ModelManagerView.swift
│ ├── MessageEditor.swift
│ ├── OverlayToast.swift
│ ├── Room
│ │ ├── Components
│ │ │ └── RoomItem.swift
│ │ └── RoomView.swift
│ ├── Setting
│ │ └── SettingView.swift
│ ├── SettingSheet.swift
│ ├── SettingSheetViewModel.swift
│ ├── SideBar
│ │ └── SideBar.swift
│ ├── StopButton.swift
│ └── Tags
│ │ ├── TagListItem.swift
│ │ └── TagsView.swift
├── V2
│ ├── Core.swift
│ ├── Core
│ │ ├── APICall.swift
│ │ └── SessionManager.swift
│ ├── Data
│ │ ├── Datasource
│ │ │ ├── OllamaDatasource.swift
│ │ │ └── WebDatasource.swift
│ │ ├── Dto
│ │ │ ├── EmbeddingDto.swift
│ │ │ └── EmbeddingResponseDto.swift
│ │ └── Repository
│ │ │ ├── CrawlingRepositoryImpl.swift
│ │ │ └── OllmaRepositoryImpl.swift
│ ├── Domain
│ │ ├── Repository
│ │ │ ├── CrawlingRepository.swift
│ │ │ └── OllamaRepository.swift
│ │ └── Usecase
│ │ │ ├── ChatUsecase.swift
│ │ │ └── LangchainUsecase.swift
│ └── UI_v2
│ │ ├── Chat
│ │ └── Bloc
│ │ │ ├── LangchainBloc.swift
│ │ │ └── LangchainEvent+State.swift
│ │ ├── Root
│ │ ├── RootView.swift
│ │ └── RootViewModel.swift
│ │ ├── SidebarV2
│ │ ├── SidebarV2.swift
│ │ └── SidebarV2ViewModel.swift
│ │ └── model
│ │ └── Embeddings.swift
├── ollamaGUI.entitlements
└── ollamaGUIApp.swift
├── OllamaGuiTest
├── Data
│ └── Datasource
│ │ ├── OllamaDatasource.swift
│ │ └── WebDatasource.swift
├── Domain
│ └── Usecase
│ │ ├── ChatUsecase.swift
│ │ ├── Langchain+ChatUsecase.swift
│ │ └── LangchainUsecase.swift
├── Info.plist
├── UI
│ └── Chat
│ │ └── Bloc
│ │ └── LangchainBloc.swift
└── ollamaGuiTest.swift
├── Podfile
├── Podfile.lock
├── Pods
├── Alamofire
│ ├── LICENSE
│ ├── README.md
│ └── Source
│ │ ├── AFError.swift
│ │ ├── Alamofire.swift
│ │ ├── AlamofireExtended.swift
│ │ ├── AuthenticationInterceptor.swift
│ │ ├── CachedResponseHandler.swift
│ │ ├── Combine.swift
│ │ ├── Concurrency.swift
│ │ ├── DispatchQueue+Alamofire.swift
│ │ ├── EventMonitor.swift
│ │ ├── HTTPHeaders.swift
│ │ ├── HTTPMethod.swift
│ │ ├── MultipartFormData.swift
│ │ ├── MultipartUpload.swift
│ │ ├── NetworkReachabilityManager.swift
│ │ ├── Notifications.swift
│ │ ├── OperationQueue+Alamofire.swift
│ │ ├── ParameterEncoder.swift
│ │ ├── ParameterEncoding.swift
│ │ ├── Protected.swift
│ │ ├── RedirectHandler.swift
│ │ ├── Request.swift
│ │ ├── RequestCompression.swift
│ │ ├── RequestInterceptor.swift
│ │ ├── RequestTaskMap.swift
│ │ ├── Response.swift
│ │ ├── ResponseSerialization.swift
│ │ ├── Result+Alamofire.swift
│ │ ├── RetryPolicy.swift
│ │ ├── ServerTrustEvaluation.swift
│ │ ├── Session.swift
│ │ ├── SessionDelegate.swift
│ │ ├── StringEncoding+Alamofire.swift
│ │ ├── URLConvertible+URLRequestConvertible.swift
│ │ ├── URLEncodedFormEncoder.swift
│ │ ├── URLRequest+Alamofire.swift
│ │ ├── URLSessionConfiguration+Alamofire.swift
│ │ └── Validation.swift
├── Manifest.lock
├── Pods.xcodeproj
│ ├── project.pbxproj
│ └── xcuserdata
│ │ └── baesanghwi.xcuserdatad
│ │ └── xcschemes
│ │ ├── Alamofire.xcscheme
│ │ ├── Pods-ollamaGUI.xcscheme
│ │ ├── SwiftUIIntrospect.xcscheme
│ │ └── xcschememanagement.plist
├── SwiftUIIntrospect
│ ├── LICENSE
│ ├── README.md
│ └── Sources
│ │ ├── Introspect.swift
│ │ ├── IntrospectableViewType.swift
│ │ ├── IntrospectionSelector.swift
│ │ ├── IntrospectionView.swift
│ │ ├── PlatformVersion.swift
│ │ ├── PlatformView.swift
│ │ ├── PlatformViewVersion.swift
│ │ ├── RuntimeWarnings.swift
│ │ ├── Utils.swift
│ │ ├── ViewTypes
│ │ ├── Button.swift
│ │ ├── ColorPicker.swift
│ │ ├── DatePicker.swift
│ │ ├── DatePickerWithCompactStyle.swift
│ │ ├── DatePickerWithFieldStyle.swift
│ │ ├── DatePickerWithGraphicalStyle.swift
│ │ ├── DatePickerWithStepperFieldStyle.swift
│ │ ├── DatePickerWithWheelStyle.swift
│ │ ├── Form.swift
│ │ ├── FormWithGroupedStyle.swift
│ │ ├── FullScreenCover.swift
│ │ ├── List.swift
│ │ ├── ListCell.swift
│ │ ├── ListWithBorderedStyle.swift
│ │ ├── ListWithGroupedStyle.swift
│ │ ├── ListWithInsetGroupedStyle.swift
│ │ ├── ListWithInsetStyle.swift
│ │ ├── ListWithSidebarStyle.swift
│ │ ├── Map.swift
│ │ ├── NavigationSplitView.swift
│ │ ├── NavigationStack.swift
│ │ ├── NavigationViewWithColumnsStyle.swift
│ │ ├── NavigationViewWithStackStyle.swift
│ │ ├── PageControl.swift
│ │ ├── PickerWithMenuStyle.swift
│ │ ├── PickerWithSegmentedStyle.swift
│ │ ├── PickerWithWheelStyle.swift
│ │ ├── Popover.swift
│ │ ├── ProgressViewWithCircularStyle.swift
│ │ ├── ProgressViewWithLinearStyle.swift
│ │ ├── ScrollView.swift
│ │ ├── SearchField.swift
│ │ ├── SecureField.swift
│ │ ├── Sheet.swift
│ │ ├── SignInWithAppleButton.swift
│ │ ├── Slider.swift
│ │ ├── Stepper.swift
│ │ ├── TabView.swift
│ │ ├── TabViewWithPageStyle.swift
│ │ ├── Table.swift
│ │ ├── TextEditor.swift
│ │ ├── TextField.swift
│ │ ├── TextFieldWithVerticalAxis.swift
│ │ ├── Toggle.swift
│ │ ├── ToggleWithButtonStyle.swift
│ │ ├── ToggleWithCheckboxStyle.swift
│ │ ├── ToggleWithSwitchStyle.swift
│ │ ├── VideoPlayer.swift
│ │ ├── View.swift
│ │ ├── ViewController.swift
│ │ └── Window.swift
│ │ └── Weak.swift
└── Target Support Files
│ ├── Alamofire
│ ├── Alamofire-Info.plist
│ ├── Alamofire-dummy.m
│ ├── Alamofire-prefix.pch
│ ├── Alamofire-umbrella.h
│ ├── Alamofire.debug.xcconfig
│ ├── Alamofire.modulemap
│ └── Alamofire.release.xcconfig
│ ├── Pods-ollamaGUI
│ ├── Pods-ollamaGUI-Info.plist
│ ├── Pods-ollamaGUI-acknowledgements.markdown
│ ├── Pods-ollamaGUI-acknowledgements.plist
│ ├── Pods-ollamaGUI-dummy.m
│ ├── Pods-ollamaGUI-frameworks-Debug-input-files.xcfilelist
│ ├── Pods-ollamaGUI-frameworks-Debug-output-files.xcfilelist
│ ├── Pods-ollamaGUI-frameworks-Release-input-files.xcfilelist
│ ├── Pods-ollamaGUI-frameworks-Release-output-files.xcfilelist
│ ├── Pods-ollamaGUI-frameworks.sh
│ ├── Pods-ollamaGUI-umbrella.h
│ ├── Pods-ollamaGUI.debug.xcconfig
│ ├── Pods-ollamaGUI.modulemap
│ └── Pods-ollamaGUI.release.xcconfig
│ └── SwiftUIIntrospect
│ ├── SwiftUIIntrospect-Info.plist
│ ├── SwiftUIIntrospect-dummy.m
│ ├── SwiftUIIntrospect-prefix.pch
│ ├── SwiftUIIntrospect-umbrella.h
│ ├── SwiftUIIntrospect.debug.xcconfig
│ ├── SwiftUIIntrospect.modulemap
│ └── SwiftUIIntrospect.release.xcconfig
├── README.md
├── image
├── 1.1v.png
├── gif.gif
├── langchain.png
├── png.png
├── png2.png
└── png3.png
├── ollamaGUI.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── xcshareddata
│ └── xcschemes
│ │ └── ollamaGUI.xcscheme
└── xcuserdata
│ └── baesanghwi.xcuserdatad
│ └── xcschemes
│ └── xcschememanagement.plist
├── ollamaGUI.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ ├── IDEWorkspaceChecks.plist
│ └── swiftpm
│ └── Package.resolved
└── ollamaGUI
└── V2
└── Core
├── Error
└── MuseError.swift
└── Protocol
└── BaseBloc.swift
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## User settings
6 | xcuserdata/
7 |
8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
9 | *.xcscmblueprintj
10 | *.xccheckout
11 | *.xcconfig
12 |
13 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
14 | build/
15 | DerivedData/
16 | *.moved-aside
17 | *.pbxuser
18 | !default.pbxuser
19 | *.mode1v3
20 | !default.mode1v3
21 | *.mode2v3
22 | !default.mode2v3
23 | *.perspectivev3
24 | !default.perspectivev3
25 |
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 | Pods/
95 | Podfile.lock
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 enoch1118
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/OllamaGUI/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 |
--------------------------------------------------------------------------------
/OllamaGUI/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "mac",
5 | "scale" : "1x",
6 | "size" : "16x16"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "scale" : "2x",
11 | "size" : "16x16"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "scale" : "1x",
16 | "size" : "32x32"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "scale" : "2x",
21 | "size" : "32x32"
22 | },
23 | {
24 | "idiom" : "mac",
25 | "scale" : "1x",
26 | "size" : "128x128"
27 | },
28 | {
29 | "idiom" : "mac",
30 | "scale" : "2x",
31 | "size" : "128x128"
32 | },
33 | {
34 | "idiom" : "mac",
35 | "scale" : "1x",
36 | "size" : "256x256"
37 | },
38 | {
39 | "idiom" : "mac",
40 | "scale" : "2x",
41 | "size" : "256x256"
42 | },
43 | {
44 | "idiom" : "mac",
45 | "scale" : "1x",
46 | "size" : "512x512"
47 | },
48 | {
49 | "idiom" : "mac",
50 | "scale" : "2x",
51 | "size" : "512x512"
52 | }
53 | ],
54 | "info" : {
55 | "author" : "xcode",
56 | "version" : 1
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/OllamaGUI/Assets.xcassets/ChainIcon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "chain.svg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | },
21 | "properties" : {
22 | "preserves-vector-representation" : true,
23 | "template-rendering-intent" : "template"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/OllamaGUI/Assets.xcassets/ChainIcon.imageset/chain.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/OllamaGUI/Assets.xcassets/ChatColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "38",
9 | "green" : "38",
10 | "red" : "38"
11 | }
12 | },
13 | "idiom" : "universal"
14 | },
15 | {
16 | "appearances" : [
17 | {
18 | "appearance" : "luminosity",
19 | "value" : "dark"
20 | }
21 | ],
22 | "color" : {
23 | "color-space" : "srgb",
24 | "components" : {
25 | "alpha" : "1.000",
26 | "blue" : "38",
27 | "green" : "38",
28 | "red" : "38"
29 | }
30 | },
31 | "idiom" : "universal"
32 | }
33 | ],
34 | "info" : {
35 | "author" : "xcode",
36 | "version" : 1
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/OllamaGUI/Assets.xcassets/ChatHoverColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "46",
9 | "green" : "46",
10 | "red" : "46"
11 | }
12 | },
13 | "idiom" : "universal"
14 | },
15 | {
16 | "appearances" : [
17 | {
18 | "appearance" : "luminosity",
19 | "value" : "dark"
20 | }
21 | ],
22 | "color" : {
23 | "color-space" : "srgb",
24 | "components" : {
25 | "alpha" : "1.000",
26 | "blue" : "64",
27 | "green" : "64",
28 | "red" : "64"
29 | }
30 | },
31 | "idiom" : "universal"
32 | }
33 | ],
34 | "info" : {
35 | "author" : "xcode",
36 | "version" : 1
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/OllamaGUI/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/OllamaGUI/Assets.xcassets/MicIcon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "mic.svg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | },
21 | "properties" : {
22 | "preserves-vector-representation" : true,
23 | "template-rendering-intent" : "template"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/OllamaGUI/Assets.xcassets/MicIcon.imageset/mic.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/OllamaGUI/Assets.xcassets/MopIcon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "mop.svg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | },
21 | "properties" : {
22 | "preserves-vector-representation" : true,
23 | "template-rendering-intent" : "template"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/OllamaGUI/Assets.xcassets/MopIcon.imageset/mop.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/OllamaGUI/Assets.xcassets/OllamaIcon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "ollama.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/OllamaGUI/Assets.xcassets/OllamaIcon.imageset/ollama.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enoch1118/ollamaGUI/b094a09cff130c60e9c14bf1dcbf0bff1e4020ca/OllamaGUI/Assets.xcassets/OllamaIcon.imageset/ollama.png
--------------------------------------------------------------------------------
/OllamaGUI/Assets.xcassets/PinIcon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "pin.svg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | },
21 | "properties" : {
22 | "preserves-vector-representation" : true,
23 | "template-rendering-intent" : "template"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/OllamaGUI/Assets.xcassets/PinIcon.imageset/pin.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/OllamaGUI/Assets.xcassets/SettingIcon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "settings_FILL0_wght200_GRAD0_opsz24.svg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | },
21 | "properties" : {
22 | "preserves-vector-representation" : true,
23 | "template-rendering-intent" : "template"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/OllamaGUI/Assets.xcassets/SettingIcon.imageset/settings_FILL0_wght200_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/OllamaGUI/Assets.xcassets/SidebarColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "64",
9 | "green" : "64",
10 | "red" : "64"
11 | }
12 | },
13 | "idiom" : "universal"
14 | },
15 | {
16 | "appearances" : [
17 | {
18 | "appearance" : "luminosity",
19 | "value" : "dark"
20 | }
21 | ],
22 | "color" : {
23 | "color-space" : "srgb",
24 | "components" : {
25 | "alpha" : "1.000",
26 | "blue" : "64",
27 | "green" : "64",
28 | "red" : "64"
29 | }
30 | },
31 | "idiom" : "universal"
32 | }
33 | ],
34 | "info" : {
35 | "author" : "xcode",
36 | "version" : 1
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/OllamaGUI/Assets.xcassets/SidebarIconColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "160",
9 | "green" : "160",
10 | "red" : "160"
11 | }
12 | },
13 | "idiom" : "universal"
14 | },
15 | {
16 | "appearances" : [
17 | {
18 | "appearance" : "luminosity",
19 | "value" : "dark"
20 | }
21 | ],
22 | "color" : {
23 | "color-space" : "srgb",
24 | "components" : {
25 | "alpha" : "1.000",
26 | "blue" : "160",
27 | "green" : "160",
28 | "red" : "160"
29 | }
30 | },
31 | "idiom" : "universal"
32 | }
33 | ],
34 | "info" : {
35 | "author" : "xcode",
36 | "version" : 1
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/OllamaGUI/Core/Loadable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Loadable.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/11/24.
6 | //
7 |
8 | import Foundation
9 |
10 | enum Loadable where E: Error {
11 | case initState
12 | case isLoading(last: U?)
13 | case loaded(U)
14 | case cancelled
15 | case finished
16 | case failed(E)
17 |
18 | var value: U? {
19 | switch self {
20 | case let .isLoading(last): return last
21 | case let .loaded(value): return value
22 | default: return nil
23 | }
24 | }
25 |
26 | var error: Error? {
27 | switch self {
28 | case let .failed(error): return error
29 | default: return nil
30 | }
31 | }
32 |
33 | var status: String? {
34 | switch self {
35 | case .initState: return NSLocalizedString("ready to loading",
36 | comment: "")
37 | case .isLoading: return NSLocalizedString("is loading",
38 | comment: "")
39 | case .finished: return NSLocalizedString("complete",
40 | comment: "")
41 | case .cancelled: return NSLocalizedString("user cancelled", comment: "")
42 | case .loaded: return NSLocalizedString("loaded", comment: "")
43 | case let .failed(error): return error.localizedDescription
44 | }
45 | }
46 | }
47 |
48 | extension Loadable: Equatable where U: Equatable {
49 | static func == (lhs: Loadable, rhs: Loadable) -> Bool {
50 | switch (lhs, rhs) {
51 | case (.initState, .initState): return true
52 | case let (.isLoading(lhsC), .isLoading(rhsC)):
53 | return lhsC == rhsC
54 | case let (.loaded(lhsV), .loaded(rhsV)): return lhsV == rhsV
55 | case let (.failed(lhsE), .failed(rhsE)):
56 | return lhsE.localizedDescription == rhsE.localizedDescription
57 | default: return false
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/OllamaGUI/Core/NetworkError.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NetworkError.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/11/24.
6 | //
7 |
8 | import Alamofire
9 | import Foundation
10 |
11 | enum NetworkError: Error {
12 | case disconnected
13 | case commonError(error: AFError)
14 | case badRequest(error: Error?)
15 | case inValidStatus(status: Int)
16 | case jsonEncodeError
17 | }
18 |
19 | extension NetworkError {
20 | var localizedDescription: String {
21 | switch self {
22 | case let .badRequest(error):
23 | return NSLocalizedString(
24 | "bad request \(error?.localizedDescription ?? "no data")",
25 | comment: ""
26 | )
27 | case let .inValidStatus(status):
28 | return NSLocalizedString(
29 | "invalid status code \(status)",
30 | comment: ""
31 | )
32 | case .disconnected:
33 | return NSLocalizedString("network error", comment: "")
34 | case let .commonError(error):
35 | return NSLocalizedString("error \(error)", comment: "")
36 | case .jsonEncodeError:
37 | return NSLocalizedString("error to encode json", comment: "")
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/OllamaGUI/Data/AppSettingEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppSettingEntity.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/18/24.
6 | //
7 |
8 | import Foundation
9 | import SwiftData
10 |
11 | @Model
12 | class AppSettingEntity {
13 | var baseUrl:String
14 | var selectedModel:String
15 |
16 | init(baseUrl: String, selectedModel: String) {
17 | self.baseUrl = baseUrl
18 | self.selectedModel = selectedModel
19 | }
20 | }
21 |
22 |
23 | extension AppSettingEntity {
24 | static var `default`:AppSettingEntity {
25 | AppSettingEntity(baseUrl: "http://localhost:11434", selectedModel: "llama2")
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/OllamaGUI/Data/ChatEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChatEntity.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/15/24.
6 | //
7 |
8 | import Foundation
9 | import SwiftData
10 |
11 | //
12 | // var message: MessageModel?
13 | // let stream: Bool?
14 | // let done: Bool?
15 | // let createdAt: Date?
16 | // let images: [String]?
17 | // let model: String?
18 | //
19 | @Model
20 | class ChatEntity {
21 | @Relationship(deleteRule: .cascade) var message: MessageEntity?
22 | var createdAt: Date
23 |
24 | init(message: MessageEntity? = nil, createdAt: Date) {
25 | self.message = message
26 | self.createdAt = createdAt
27 | }
28 | }
29 |
30 | #if DEBUG
31 | extension ChatEntity {
32 | static var randomChat: ChatEntity {
33 | return ChatEntity(message: nil,createdAt: RandomGenerator.randomDate())
34 | }
35 | }
36 | #endif
37 |
--------------------------------------------------------------------------------
/OllamaGUI/Data/MessageEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChatEntity.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/15/24.
6 | //
7 |
8 | import Foundation
9 | import SwiftData
10 |
11 | // var id: UUID
12 | // var role: RoleEnum
13 | // var content: String
14 | // var images: [String]?
15 | @Model
16 | class MessageEntity {
17 | var role: RoleEnum
18 | var content: String
19 | var images: [Data]?
20 |
21 | init(role: RoleEnum, content: String, images: [Data]? = nil) {
22 | self.role = role
23 | self.content = content
24 | self.images = images
25 | }
26 | }
27 |
28 | #if DEBUG
29 | extension MessageEntity {
30 | static var randomMessage: MessageEntity {
31 | let rols: [RoleEnum] = [.user, .assistant]
32 | return MessageEntity(
33 | role: rols.randomElement()!,
34 | content: RandomGenerator.randomNames.randomElement()!
35 | )
36 | }
37 | }
38 | #endif
39 |
--------------------------------------------------------------------------------
/OllamaGUI/Data/RoomEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RoomEntity.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/15/24.
6 | //
7 |
8 | import Foundation
9 | import SwiftData
10 |
11 | @Model
12 | class RoomEntity {
13 | var updatedAt: Date
14 | @Relationship(deleteRule: .cascade) var chats: [ChatEntity]
15 | var title: String?
16 | @Relationship(deleteRule: .cascade) var option: RoomOptionEntity?
17 |
18 |
19 | init(updatedAt: Date, chats: [ChatEntity], title: String? = nil) {
20 | self.updatedAt = updatedAt
21 | self.chats = chats
22 | self.title = title ?? "new chat"
23 | }
24 |
25 | init() {
26 | updatedAt = Date.now
27 | chats = []
28 | title = "new chat"
29 | }
30 |
31 | var getChatModel: [ChatModel] {
32 | chats.map { ChatModel(entity: $0) }
33 | }
34 |
35 | func clean() {
36 | chats.removeAll()
37 | }
38 | }
39 |
40 | extension [ChatModel] {
41 | var toEntity: [ChatEntity] {
42 | map { $0.toEntity }
43 | }
44 | }
45 |
46 | extension ChatModel {
47 | var toEntity: ChatEntity {
48 | ChatEntity(
49 | message: MessageEntity(role: message!.role,
50 | content: message!.content, images: []),
51 | createdAt: createdAt ?? Date.now
52 | )
53 | }
54 | }
55 |
56 | extension RoomEntity {
57 | static var randomRoom: RoomEntity {
58 | let room = RoomEntity()
59 | room.title = RandomGenerator.randomNames.randomElement()
60 | room.chats = [
61 | ]
62 |
63 | room.updatedAt = RandomGenerator.randomDate()
64 | return room
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/OllamaGUI/Data/RoomOptionEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RoomOption.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 3/5/24.
6 | //
7 |
8 | import Foundation
9 | import SwiftData
10 |
11 | @Model
12 | class RoomOptionEntity {
13 | var model: String?
14 | var system: String?
15 | var top_p: Float
16 | var top_k: Int
17 | var temperature: Float?
18 | init(model: String?,
19 | system: String?,
20 | top_p: Float = 0.9,
21 | top_k: Int = 40,
22 | temperature: Float = 0.8
23 | ) {
24 |
25 | self.model = model
26 | self.system = system
27 | self.top_p = top_p
28 | self.top_k = top_k
29 | self.temperature = temperature
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/OllamaGUI/Data/chat.xcdatamodeld/chat.xcdatamodel/contents:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/OllamaGUI/Enum.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Enum.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/10/24.
6 | //
7 |
8 | import Foundation
9 |
--------------------------------------------------------------------------------
/OllamaGUI/Enum/RoleEnum.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RoleEnum.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/10/24.
6 | //
7 |
8 | import Foundation
9 |
10 | enum RoleEnum:String,Codable{
11 | case user = "user"
12 | case assistant = "assistant"
13 | case system = "system"
14 | }
15 |
16 | extension RoleEnum {
17 | var value:String{
18 | String(describing: self)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/OllamaGUI/Enum/RouterEnum.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RouterEnum.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/11/24.
6 | //
7 |
8 | import Foundation
9 |
10 |
11 |
--------------------------------------------------------------------------------
/OllamaGUI/Helper/DateHelper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DateHelper.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/17/24.
6 | //
7 |
8 | import Foundation
9 |
10 | extension Date {
11 | func fullDistance(
12 | from date: Date,
13 | resultIn component: Calendar.Component,
14 | calendar: Calendar = .current
15 | ) -> Int? {
16 | calendar.dateComponents([component], from: self, to: date)
17 | .value(for: component)
18 | }
19 |
20 | func distance(
21 | from date: Date,
22 | only component: Calendar.Component,
23 | calendar: Calendar = .current
24 | ) -> Int {
25 | let days1 = calendar.component(component, from: self)
26 | let days2 = calendar.component(component, from: date)
27 | return days1 - days2
28 | }
29 |
30 | func hasSame(_ component: Calendar.Component, as date: Date) -> Bool {
31 | distance(from: date, only: component) == 0
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/OllamaGUI/Helper/DescribableEnum.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StringConvertableEnum.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/11/24.
6 | //
7 |
8 | import Foundation
9 |
10 | protocol DescribableEnum{
11 | var description:String? { get }
12 | }
13 |
--------------------------------------------------------------------------------
/OllamaGUI/Helper/DictionaryEncoder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DictionaryEncoder.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/12/24.
6 | //
7 |
8 | import Foundation
9 |
10 | class DictionaryEncoder {
11 | private let encoder = JSONEncoder()
12 |
13 | func encode(_ value: T) throws -> [String: Any] where T : Encodable {
14 | let data = try encoder.encode(value)
15 | return try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String: Any]
16 | }
17 | }
18 |
19 |
20 | extension Encodable{
21 | func getLeafDictionary() -> [String:Any]?{
22 | let data = try? JSONEncoder().encode(self)
23 | let dict = try? JSONSerialization.jsonObject(with: data!) as? [String: Any]
24 | return dict
25 | }
26 | }
27 |
28 | protocol DictionaryEncodable{
29 | func getDictionary()->[String:Any]?
30 | }
31 |
--------------------------------------------------------------------------------
/OllamaGUI/Helper/IntHelper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IntHelper.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/20/24.
6 | //
7 |
8 | import Foundation
9 |
10 |
11 | extension Int{
12 | var getSize:String{
13 | let div = 1024.0
14 | if self > Int(pow(div,3)){
15 | let val = pow(div,3)
16 | return "\((Double(self) / val).roundToDecimal(2))GB"
17 | }
18 | if self > Int(pow(div,2)){
19 | let val = pow(div,3)
20 | return "\((Double(self) / val).roundToDecimal(2))MB"
21 | }
22 | if self > Int(pow(div,1)){
23 | let val = pow(div,2)
24 | return "\((Double(self) / val).roundToDecimal(2))KB"
25 | }
26 | if self > Int(pow(div,0)){
27 | let val = pow(div,1)
28 | return "\((Double(self) / val).roundToDecimal(2))B"
29 | }
30 |
31 | return "cal error"
32 | }
33 | }
34 |
35 |
36 | extension Double {
37 | func roundToDecimal(_ fractionDigits: Int) -> Double {
38 | let multiplier = pow(10, Double(fractionDigits))
39 | return Darwin.round(self * multiplier) / multiplier
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/OllamaGUI/Helper/MarkdownTheme.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MarkdownTheme.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/15/24.
6 | //
7 |
8 | import Foundation
9 | import MarkdownUI
10 | import SwiftUI
11 |
12 | extension Theme {
13 | static let user = Theme()
14 | .code {
15 | FontFamilyVariant(.monospaced)
16 | FontSize(.em(0.85))
17 | }
18 | .link {
19 | ForegroundColor(.purple)
20 | }
21 | .paragraph { configuration in
22 | configuration.label
23 | .relativeLineSpacing(.em(0.25))
24 | .markdownMargin(top: 0, bottom: 16)
25 | }
26 | .listItem { configuration in
27 | configuration.label
28 | .markdownMargin(top: .em(0.25))
29 | }
30 | .text {
31 | BackgroundColor(.blue)
32 | }
33 |
34 | static let assistant = Theme()
35 | .code {
36 | FontFamilyVariant(.monospaced)
37 | FontSize(.em(0.85))
38 | }.codeBlock { conf in
39 | conf.label
40 | .padding(.horizontal, 16)
41 | .padding(.vertical, 20)
42 | .frame(maxWidth: .infinity,alignment: .leading)
43 | .padding(.top,14)
44 |
45 | .markdownTextStyle {
46 | ForegroundColor(.white)
47 | }
48 | .background(RoundedRectangle(cornerRadius: 8).fill(.black))
49 | .overlay(alignment: .topTrailing) {
50 | Button (action: {
51 | let pasteboard = NSPasteboard.general
52 | pasteboard.clearContents()
53 | pasteboard.setString(conf.content, forType: .string)
54 | print(conf.content)
55 | }) {
56 | Image(systemName: "doc.on.doc")
57 | }.padding()
58 | }
59 | }
60 | .link {
61 | ForegroundColor(.purple)
62 | }
63 | .paragraph { configuration in
64 | configuration.label
65 | .relativeLineSpacing(.em(0.25))
66 | .markdownMargin(top: 0, bottom: 16)
67 | }
68 | .listItem { configuration in
69 | configuration.label
70 | .markdownMargin(top: .em(0.25))
71 | }
72 | .text {
73 | BackgroundColor(.white)
74 | ForegroundColor(.black)
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/OllamaGUI/Helper/RandomGenerator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RandomGenerator.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/17/24.
6 | //
7 |
8 | import Foundation
9 |
10 | enum RandomGenerator {
11 | static var randomNames: [String] {
12 | [
13 | "Unboxing the Secrets of [Mysterious Subject]: A Journey of Discovery",
14 | "From Novice to Ninja: Mastering the Art of [Intriguing Skill]",
15 | "Beyond the Surface: A Deep Dive into the World of [Unfamiliar Topic]",
16 | "Confessions of a [Unexpected Profession]: The Untold Stories of [Intriguing Aspect]",
17 | "The Unexpected Twists and Turns of [Intriguing Event]: A Story You Won't Believe",
18 | "Cracking the Code: Unraveling the Mysteries of [Complex Phenomenon]",
19 | "From Zero to Hero: My Personal Quest to Conquering [Daunting Challenge]",
20 | "Inside the Minds of [Fascinating Group]: A Glimpse into Their [Unique Perspective]",
21 | "The Forgotten Tale of [Historical Event or Figure]: A Retelling for the Modern Age",
22 | "Navigating the Labyrinth: A Guide to Surviving [Challenging Situation]",
23 | ]
24 | }
25 |
26 | static func randomDate(in range: Range = (Date.now - 100000).. Date {
27 | Date(
28 | timeIntervalSinceNow: .random(
29 | in: range.lowerBound.timeIntervalSinceNow...range.upperBound.timeIntervalSinceNow
30 | )
31 | )
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/OllamaGUI/Helper/StringHelper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StringHelper.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/15/24.
6 | //
7 |
8 | import Foundation
9 | import SwiftUI
10 |
11 | extension String {
12 | var removeFirstBreakLine: String {
13 | if starts(with: "\n") {
14 | return replacing("\n", with: "", maxReplacements: 1)
15 | }
16 | return self
17 | }
18 |
19 | var verifyUrl: Bool {
20 | let urlPattern =
21 | "https?://[localhost|(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b]([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)"
22 | let urlRegex = try! NSRegularExpression(pattern: urlPattern)
23 | if urlRegex.firstMatch(
24 | in: self,
25 | options: [],
26 | range: NSRange(location: 0, length: utf16.count)
27 | ) != nil {
28 | return true
29 | } else {
30 | return false
31 | }
32 | }
33 |
34 | var base64Data: Data? {
35 | let utf8Data = data(using: .utf8)
36 | return utf8Data?.base64EncodedData()
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/OllamaGUI/Helper/ViewHelper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewHelper.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/9/24.
6 | //
7 |
8 | import Foundation
9 | import SwiftUI
10 |
11 | struct PlaceHolder: ViewModifier {
12 | var placeHolder: T
13 | var show: Bool
14 | func body(content: Content) -> some View {
15 | ZStack(alignment: .leading) {
16 | if show { VStack {
17 | placeHolder.padding(.leading,5)
18 | Spacer()
19 | } }
20 | content
21 | }
22 | }
23 | }
24 |
25 | extension View {
26 | func placeHolder(_ holder: T, show: Bool) -> some View {
27 | modifier(PlaceHolder(placeHolder: holder, show: show))
28 | }
29 |
30 | var textLeft:some View {
31 | self.frame(maxWidth: .infinity,alignment: .leading)
32 | }
33 |
34 | var flexTL:some View{
35 | self.frame(maxWidth: .infinity,maxHeight: .infinity,alignment: .topLeading)
36 | }
37 | var flexC:some View{
38 | self.frame(maxWidth: .infinity,maxHeight: .infinity,alignment: .center)
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/OllamaGUI/Helper/WindowHelper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WindowHelper.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/18/24.
6 | //
7 |
8 | import Foundation
9 | import SwiftUI
10 |
11 | struct WindowAccessor: NSViewRepresentable {
12 | @Binding var window: NSWindow?
13 |
14 | func makeNSView(context _: Context) -> NSView {
15 | let view = NSView()
16 | DispatchQueue.main.async {
17 | self.window = view.window
18 | }
19 | return view
20 | }
21 |
22 | func updateNSView(_: NSView, context _: Context) {}
23 | }
24 |
--------------------------------------------------------------------------------
/OllamaGUI/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSAppTransportSecurity
6 |
7 | NSExceptionDomains
8 |
9 | ollama.ai
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/OllamaGUI/Injected/AppSetting.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppSetting.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/15/24.
6 | //
7 |
8 | import Combine
9 | import Foundation
10 |
11 | class AppSetting {
12 | private var subject = CurrentValueSubject(nil)
13 | var ollamaDs: OllamaDatasource
14 |
15 | init(ollamaDs: OllamaDatasource) {
16 | self.ollamaDs = ollamaDs
17 | }
18 |
19 | private var entity: AppSettingEntity {
20 | subject.value!
21 | }
22 |
23 | func updateBaseUrl(_ url: String) {
24 | let entity = entity
25 | entity.baseUrl = url
26 | ollamaDs.baseUrl = url
27 | subject.send(entity)
28 | }
29 |
30 | func updateModel(_ model: String) {
31 | let entity = entity
32 | entity.selectedModel = model
33 | subject.send(entity)
34 | }
35 |
36 | func updateSetting(_ entity: AppSettingEntity) {
37 | print("setting setted")
38 | print(ollamaDs.baseUrl)
39 | ollamaDs.baseUrl = entity.baseUrl
40 | subject.send(entity)
41 | }
42 |
43 | var baseUrl: String {
44 | entity.baseUrl
45 | }
46 |
47 | var model: String {
48 | entity.selectedModel
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/OllamaGUI/Injected/DataInteractor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DataInteractor.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/15/24.
6 | //
7 |
8 | import Foundation
9 | import SwiftData
10 |
11 | protocol DataInteractor {
12 | func fetchRoom(context: ModelContext) -> [RoomEntity]
13 |
14 | func clearRoom(context: ModelContext, room: RoomEntity)
15 |
16 | func insertRoom(context: ModelContext) -> PersistentIdentifier
17 |
18 | func deleteRoom(context: ModelContext, room: RoomEntity)
19 |
20 | func fetchSetting(context: ModelContext) -> AppSettingEntity
21 | }
22 |
23 | struct RealDataInteractor: DataInteractor {
24 | func insertRoom(context: ModelContext) -> PersistentIdentifier {
25 | let room = RoomEntity()
26 | context.insert(room)
27 | return room.id
28 | }
29 | func fetchRoom(context: ModelContext) -> [RoomEntity] {
30 | let des = FetchDescriptor()
31 | var rooms = try? context.fetch(des)
32 | if rooms == nil || rooms!.isEmpty {
33 | context.insert(RoomEntity())
34 | rooms = try? context.fetch(des)
35 | }
36 | if rooms == nil || rooms!.isEmpty {
37 | fatalError()
38 | }
39 | return rooms!.sorted(by: { $0.updatedAt > $1.updatedAt })
40 | }
41 |
42 | func clearRoom(context: ModelContext, room: RoomEntity) {
43 | for message in room.chats {
44 | context.delete(message)
45 | }
46 | }
47 |
48 | func deleteRoom(context: ModelContext, room: RoomEntity) {
49 | context.delete(room)
50 | }
51 |
52 | func fetchSetting(context: ModelContext) -> AppSettingEntity {
53 | let des = FetchDescriptor()
54 | var setting = try? context.fetch(des)
55 | if setting?.first == nil {
56 | context.insert(AppSettingEntity.default)
57 | setting = try? context.fetch(des)
58 | }
59 | if setting?.first == nil {
60 | fatalError()
61 | }
62 | return setting!.first!
63 | }
64 |
65 | }
66 |
67 | struct StubDataInteractor: DataInteractor {
68 | func fetchRoom(context _: ModelContext) -> [RoomEntity] {
69 | [.randomRoom, .randomRoom, .randomRoom]
70 | }
71 |
72 | func clearRoom(context _: ModelContext, room _: RoomEntity) {}
73 |
74 | func insertRoom(context _: ModelContext) -> PersistentIdentifier {
75 | let room = RoomEntity()
76 | return room.id
77 | }
78 |
79 | func deleteRoom(context _: ModelContext, room _: RoomEntity) {}
80 |
81 | func fetchSetting(context: ModelContext) -> AppSettingEntity {
82 | .default
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/OllamaGUI/Injected/UpdateTrigger.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UpdateTrigger.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/18/24.
6 | //
7 |
8 | import Foundation
9 | import Combine
10 |
11 |
12 | struct UpdateTrigger {
13 | var subject = CurrentValueSubject(.init())
14 |
15 | var publisher: AnyPublisher {
16 | subject.eraseToAnyPublisher()
17 | }
18 |
19 | func triggerNewMessage() {
20 | var current = subject.value
21 | current.newMessage = true
22 | subject.send(current)
23 | }
24 |
25 | func newMessageHandled() {
26 | var current = subject.value
27 | current.newMessage = false
28 | subject.send(current)
29 | }
30 |
31 | func triggerNewModel(){
32 | var current = subject.value
33 | current.newModel = true
34 | subject.send(current)
35 | }
36 |
37 | func newModelHandled(){
38 | var current = subject.value
39 | current.newModel = false
40 | subject.send(current)
41 | }
42 |
43 | var hasNewMessage:Bool {
44 | subject.value.newMessage
45 | }
46 | var hasNewModel:Bool {
47 | subject.value.newModel
48 | }
49 |
50 | }
51 |
52 |
53 |
54 | struct TriggerModel{
55 | var newMessage = false
56 | var newModel = false
57 | }
58 |
59 |
60 | extension TriggerModel{
61 | static fileprivate var `default`:Self{
62 | Self.init()
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/OllamaGUI/LangChain/DocumentLoader/BaseLoader.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BaseLoader.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 3/7/24.
6 | //
7 | import Foundation
8 | struct Document: Equatable,Codable {
9 | public init(page_content: String, metadata: [String: String]) {
10 | self.page_content = page_content
11 | self.metadata = metadata
12 | }
13 |
14 | public let page_content: String
15 | public var metadata: [String: String]
16 | public static func == (lhs: Document, rhs: Document) -> Bool {
17 | return lhs.page_content == rhs.page_content
18 | }
19 |
20 |
21 | enum CodingKeys: CodingKey {
22 | case page_content
23 | case metadata
24 | }
25 |
26 | init(from decoder: any Decoder) throws {
27 | let container = try decoder.container(keyedBy: CodingKeys.self)
28 | self.page_content = try container.decode(String.self, forKey: .page_content)
29 | self.metadata = try container.decode([String : String].self, forKey: .metadata)
30 | }
31 |
32 | func encode(to encoder: any Encoder) throws {
33 | var container = encoder.container(keyedBy: CodingKeys.self)
34 | try container.encode(self.page_content, forKey: .page_content)
35 | try container.encode(self.metadata, forKey: .metadata)
36 | }
37 | }
38 |
39 | class BaseLoader {
40 | public func load() async -> [Document] {
41 | let type = type()
42 | do {
43 | let docs = try await _load()
44 | return docs
45 | } catch let LangchainError.loadError(message) {
46 | print("Catch langchain loader error \(type):\(message)")
47 | return []
48 | } catch {
49 | print("Catch other error \(type)")
50 | return []
51 | }
52 | }
53 |
54 | func _load() async throws -> [Document] {
55 | []
56 | }
57 |
58 | func type() -> String {
59 | "Base"
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/OllamaGUI/LangChain/DocumentLoader/HTMLLoader.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HTMLLoader.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 3/7/24.
6 | //
7 |
8 | import Foundation
9 | import SwiftSoup
10 |
11 | class HTMLLoader: BaseLoader {
12 | let html: String
13 | let url: String
14 |
15 | public init(html: String, url: String) {
16 | self.html = html
17 | self.url = url
18 | }
19 |
20 | override func _load() async throws -> [Document] {
21 | do {
22 | let doc: SwiftSoup.Document = try SwiftSoup.parse(html)
23 | let text = try doc.text()
24 | let metadata: [String: String] = ["url": url]
25 | return [Document(page_content: text, metadata: metadata)]
26 | } catch let Exception.Error(_, message) {
27 | throw LangchainError
28 | .loadError(message: "parse html fail with \(message)")
29 | } catch {
30 | throw LangchainError
31 | .loadError(message: "parse html fail with \(error)")
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/OllamaGUI/LangChain/Error/LangchainError.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LangchainError.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 3/7/24.
6 | //
7 |
8 | import Foundation
9 |
10 | enum LangchainError:Error {
11 | case loadError(message: String)
12 | }
13 |
--------------------------------------------------------------------------------
/OllamaGUI/Model/ChatRequestModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChatRequestModel.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/12/24.
6 | //
7 |
8 | import Foundation
9 |
10 | struct ChatRequestModel: Encodable, DictionaryEncodable {
11 | var model: String
12 | var messages: [MessageModel]
13 | var stream: Bool
14 | var format: String
15 | var options: OptionModel?
16 |
17 | init(model: String, messages: [MessageModel], stream: Bool) {
18 | self.model = model
19 | self.messages = messages
20 | self.stream = stream
21 | self.format = "json"
22 | }
23 |
24 | enum CodingKeys: CodingKey {
25 | case model
26 | case messages
27 | case stream
28 | case options
29 | }
30 |
31 | func encode(to encoder: Encoder) throws {
32 | var container = encoder.container(keyedBy: CodingKeys.self)
33 | try container.encode(model, forKey: .model)
34 | try container.encode(stream, forKey: .stream)
35 | try container.encode(messages, forKey: .messages)
36 | try container.encodeIfPresent(options, forKey: .options)
37 | }
38 |
39 | func getDictionary() -> [String: Any]? {
40 | let dict = getLeafDictionary()
41 | guard var d = dict else {
42 | return nil
43 | }
44 | var list: [[String: Any]] = []
45 | for m in messages {
46 | let val = m.getLeafDictionary()
47 | if val == nil {
48 | continue
49 | }
50 | list.append(val!)
51 | }
52 | d["messages"] = list
53 | d["options"] = options.getLeafDictionary()
54 | return d
55 | }
56 |
57 | init(of: MessageModel, stream: Bool = false) {
58 | model = "llama2"
59 | self.stream = stream
60 | messages = [of]
61 | options = nil
62 | format = "json"
63 | }
64 |
65 | init(ofList: [MessageModel], stream: Bool = false) {
66 | model = "llama2"
67 | self.stream = stream
68 | messages = ofList
69 | format = "json"
70 | }
71 |
72 |
73 | mutating func applyOption(option: RoomOptionEntity?) -> ChatRequestModel {
74 | guard let option = option else {
75 | return self
76 | }
77 | options = OptionModel(top_p: option.top_p,
78 | top_k: option.top_k,
79 | temperature: option.temperature)
80 |
81 | if let model = option.model {
82 | self.model = model
83 | }
84 | return self
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/OllamaGUI/Model/MessageModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MessageModel.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/12/24.
6 | //
7 |
8 | import Foundation
9 |
10 | struct MessageModel: Codable, Hashable {
11 | var id: UUID
12 | var role: RoleEnum
13 | var content: String
14 | var images: [String]?
15 |
16 | init(from decoder: Decoder) throws {
17 | let container = try decoder.container(keyedBy: CodingKeys.self)
18 | id = UUID()
19 | role = try container.decode(RoleEnum.self, forKey: .role)
20 | content = try container.decode(String.self, forKey: .content)
21 | images = try container.decodeIfPresent([String].self, forKey: .images)
22 | }
23 |
24 | enum CodingKeys: CodingKey {
25 | case role
26 | case content
27 | case images
28 | }
29 |
30 | func encode(to encoder: Encoder) throws {
31 | var container = encoder.container(keyedBy: CodingKeys.self)
32 | try container.encode(role, forKey: .role)
33 | try container.encode(content, forKey: .content)
34 | try container.encodeIfPresent(images, forKey: .images)
35 | }
36 |
37 | init(text: String, role: RoleEnum = .user, images: [String]? = nil) {
38 | id = UUID()
39 | content = text
40 | self.role = role
41 | self.images = images
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/OllamaGUI/Model/ModelDeleteRequestModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ModelDeleteRequestModel.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/22/24.
6 | //
7 |
8 | import Foundation
9 |
10 |
--------------------------------------------------------------------------------
/OllamaGUI/Model/ModelInfoModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ModelInfoModel.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/19/24.
6 | //
7 |
8 | import Foundation
9 |
10 | struct ModelInfoModel: Decodable, Hashable {
11 | var id: UUID
12 | var name: String
13 | var modifiedAt: Date
14 | var size: Int
15 |
16 | enum CodingKeys: String, CodingKey {
17 | case name
18 | case modifiedAt = "modified_at"
19 | case size
20 | }
21 |
22 | init(from decoder: Decoder) throws {
23 | let container = try decoder.container(keyedBy: CodingKeys.self)
24 | id = UUID()
25 | name = try container.decode(String.self, forKey: .name)
26 | modifiedAt = try container.decode(Date.self, forKey: .modifiedAt)
27 | size = try container.decode(Int.self, forKey: .size)
28 | }
29 |
30 | init(name: String, modifiedAt: Date, size: Int) {
31 | id = UUID()
32 | self.name = name
33 | self.modifiedAt = modifiedAt
34 | self.size = size
35 | }
36 | }
37 |
38 | #if DEBUG
39 | extension ModelInfoModel {
40 | static var preview: ModelInfoModel {
41 | Self(name: "testModel", modifiedAt: .now, size: 123_242_425)
42 | }
43 | }
44 |
45 | #endif
46 |
--------------------------------------------------------------------------------
/OllamaGUI/Model/ModelList.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ModelList.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/19/24.
6 | //
7 |
8 | import Foundation
9 |
10 | struct ModelList: Decodable{
11 | var models: [ModelInfoModel]
12 |
13 | enum CodingKeys: CodingKey {
14 | case models
15 | }
16 |
17 |
18 | init(from decoder: Decoder) throws {
19 | let container = try decoder.container(keyedBy: CodingKeys.self)
20 | self.models = try container.decode([ModelInfoModel].self, forKey: .models)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/OllamaGUI/Model/OllamaTagModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OllamaTagModel.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/20/24.
6 | //
7 |
8 | import Foundation
9 |
10 | struct OllamaTagModel {
11 | var id: UUID
12 | var title: String
13 | var size: String
14 | var parent: String
15 | var sha: String
16 | var updatedAt: String
17 |
18 | init(title: String, size: String, sha: String, updatedAt: String,parent:String) {
19 | self.id = UUID()
20 | self.title = title
21 | self.size = size
22 | self.sha = sha
23 | self.updatedAt = updatedAt
24 | self.parent = parent
25 | }
26 | }
27 |
28 | extension OllamaTagModel {
29 | init() {
30 | title = "tag"
31 | size = "9.999TB"
32 | sha = "12i391239i12j4i"
33 | updatedAt = "long long ago"
34 | parent = "llama2"
35 | id = UUID()
36 | }
37 |
38 | static func guardedInit(
39 | title: String?,
40 | size: String?,
41 | sha: String?,
42 | updatedAt: String?,
43 | parent:String
44 | ) -> OllamaTagModel? {
45 | if title != nil, size != nil, sha != nil, updatedAt != nil {
46 | return Self(
47 | title: title!,
48 | size: size!,
49 | sha: sha!,
50 | updatedAt: updatedAt!,
51 | parent: parent
52 | )
53 | }
54 | return nil
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/OllamaGUI/Model/OllmaModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OllmaModel.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/20/24.
6 | //
7 |
8 | import Foundation
9 |
10 | struct OllamaModel {
11 | var id:UUID = UUID()
12 | var title: String
13 | var desc: String
14 | var pulls: String
15 | var tagsCount: String
16 | var updatedAt: String
17 |
18 | init(
19 | title: String,
20 | desc: String,
21 | pulls: String,
22 | tagsCount: String,
23 | updatedAt: String
24 | ) {
25 | self.title = title
26 | self.desc = desc
27 | self.pulls = pulls
28 | self.tagsCount = tagsCount
29 | self.updatedAt = updatedAt
30 | }
31 | }
32 |
33 | extension OllamaModel {
34 | static func guardedInit(
35 | title: String?,
36 | desc: String?,
37 | pulls: String?,
38 | tagCount: String?,
39 | updatedAt: String?
40 | ) -> OllamaModel? {
41 | if title != nil, desc != nil, pulls != nil, tagCount != nil,
42 | updatedAt != nil
43 | {
44 | return Self(
45 | title: title!,
46 | desc: desc!,
47 | pulls: pulls!,
48 | tagsCount: tagCount!,
49 | updatedAt: updatedAt!
50 | )
51 | }
52 | return nil
53 | }
54 |
55 | init() {
56 | title = "ollmaa"
57 | desc = "awesome model"
58 | pulls = "many pulls"
59 | tagsCount = "many tags"
60 | updatedAt = "2 weeks ago"
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/OllamaGUI/Model/OptionModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OptionModel.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 3/5/24.
6 | //
7 |
8 | import Foundation
9 |
10 | struct OptionModel:Encodable,DictionaryEncodable {
11 | var top_p: Float
12 | var top_k: Int
13 | var temperature: Float?
14 |
15 | init(top_p: Float, top_k: Int,temperature:Float?) {
16 | self.top_p = top_p
17 | self.top_k = top_k
18 | self.temperature = temperature
19 | }
20 |
21 | enum CodingKeys: CodingKey {
22 | case top_p
23 | case top_k
24 | case temperature
25 | }
26 |
27 | func encode(to encoder: Encoder) throws {
28 | var container = encoder.container(keyedBy: CodingKeys.self)
29 | try container.encode(self.top_p, forKey: .top_p)
30 | try container.encode(self.top_k, forKey: .top_k)
31 | try container.encodeIfPresent(self.temperature, forKey: .temperature)
32 | }
33 |
34 |
35 | func getDictionary() -> [String : Any]? {
36 | let dict = getLeafDictionary()
37 | guard let d = dict else {
38 | return nil
39 | }
40 | return d
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/OllamaGUI/Model/PullRequestModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PullRequestModel.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/22/24.
6 | //
7 |
8 | import Foundation
9 |
10 | struct PullRequestModel: Encodable {
11 | var name: String
12 | var stream: Bool
13 |
14 | enum CodingKeys: CodingKey {
15 | case name
16 | }
17 |
18 | init(name: String) {
19 | self.name = name
20 | stream = true
21 | }
22 |
23 | func encode(to encoder: Encoder) throws {
24 | var container = encoder.container(keyedBy: CodingKeys.self)
25 | try container.encode(self.name, forKey: .name)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/OllamaGUI/Model/PullResponseModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PullResponseModel.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/22/24.
6 | //
7 |
8 | import Foundation
9 |
10 | struct PullResponseModel: Decodable {
11 | var status:String
12 | var digest:String?
13 | var total:Double?
14 | var completed:Double?
15 |
16 | init(status: String, digest: String? = nil, total: Double? = nil, completed: Double? = nil) {
17 | self.status = status
18 | self.digest = digest
19 | self.total = total
20 | self.completed = completed
21 | }
22 |
23 | enum CodingKeys: CodingKey {
24 | case status
25 | case digest
26 | case total
27 | case completed
28 | }
29 |
30 |
31 | init(from decoder: Decoder) throws {
32 | let container = try decoder.container(keyedBy: CodingKeys.self)
33 | self.status = try container.decode(String.self, forKey: .status)
34 | self.digest = try container.decodeIfPresent(String.self, forKey: .digest)
35 | self.total = try container.decodeIfPresent(Double.self, forKey: .total)
36 | self.completed = try container.decodeIfPresent(Double.self, forKey: .completed)
37 | }
38 | }
39 |
40 |
41 | extension PullResponseModel {
42 | var progress:Float? {
43 | if total == nil || completed == nil {
44 | return nil
45 | }
46 | return Float(completed!) / Float(total!)
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/OllamaGUI/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/OllamaGUI/UI/BubbleShape.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BubbleShape.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/10/24.
6 | //
7 |
8 | import Foundation
9 | import SwiftUI
10 |
11 | struct BubbleShape: Shape {
12 | let role: RoleEnum
13 |
14 | func path(in rect: CGRect) -> Path {
15 | return (role == .user) ? rightBubble(in: rect) : leftBubble(in: rect)
16 | }
17 |
18 | func rightBubble(in rect: CGRect) -> Path {
19 | let w = rect.width
20 | let h = rect.height
21 |
22 | let path = Path { p in
23 | p.move(to: CGPoint(x: 16, y: 16))
24 | p.addCurve(to: CGPoint(x: 32, y: 0),
25 | control1: CGPoint(x: 16, y: 8),
26 | control2: CGPoint(x: 24, y: 0))
27 | p.addLine(to: CGPoint(x: w - 8, y: 0))
28 | p.addLine(to: CGPoint(x: w - 16, y: 8))
29 | p.addLine(to: CGPoint(x: w - 16, y: h - 16))
30 |
31 | p.addCurve(to: CGPoint(x: w - 32, y: h),
32 | control1: CGPoint(x: w - 16, y: h - 8),
33 | control2: CGPoint(x: w - 24, y: h))
34 |
35 | p.addLine(to: CGPoint(x: 32, y: h))
36 | p.addCurve(to: CGPoint(x: 16, y: h - 16),
37 | control1: CGPoint(x: 24, y: h),
38 | control2: CGPoint(x: 16, y: h - 8))
39 |
40 | p.addLine(to: CGPoint(x: 16, y: h))
41 | }
42 |
43 | return path
44 | }
45 |
46 | func leftBubble(in rect: CGRect) -> Path {
47 | let w = rect.width
48 | let h = rect.height
49 |
50 | let path = Path { p in
51 | // Flip the x-coordinates of each point by subtracting them from the width
52 | p.move(to: CGPoint(x: w - 16, y: 16))
53 | p.addCurve(to: CGPoint(x: w - 32, y: 0),
54 | control1: CGPoint(x: w - 16, y: 8),
55 | control2: CGPoint(x: w - 24, y: 0))
56 | p.addLine(to: CGPoint(x: 8, y: 0))
57 | p.addLine(to: CGPoint(x: 16, y: 8))
58 | p.addLine(to: CGPoint(x: 16, y: h - 16))
59 |
60 | p.addCurve(to: CGPoint(x: 32, y: h),
61 | control1: CGPoint(x: 16, y: h - 8),
62 | control2: CGPoint(x: 24, y: h))
63 |
64 | p.addLine(to: CGPoint(x: w - 32, y: h))
65 | p.addCurve(to: CGPoint(x: w - 16, y: h - 16),
66 | control1: CGPoint(x: w - 24, y: h),
67 | control2: CGPoint(x: w - 16, y: h - 8))
68 |
69 | p.addLine(to: CGPoint(x: w - 16, y: h))
70 | }
71 |
72 | return path
73 | }
74 |
75 | }
76 |
77 |
78 |
--------------------------------------------------------------------------------
/OllamaGUI/UI/ChatBubble.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChatBubble.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/10/24.
6 | //
7 |
8 | import MarkdownUI
9 | import SwiftUI
10 |
11 | struct ChatBubble: View {
12 | var chat: ChatModel
13 |
14 | var body: some View {
15 | Group{
16 | if chat.isSystem {
17 | EmptyView()
18 | }
19 | else {
20 | HStack {
21 | if chat.isMe {
22 | Spacer()
23 | }
24 | content.clipShape(BubbleShape(role: chat.message?.role ?? .user))
25 | if !chat.isMe {
26 | Spacer()
27 | }
28 | }.frame(maxWidth: .infinity)
29 | }
30 | }
31 | }
32 |
33 | @ViewBuilder
34 | var content: some View {
35 | let message = (chat.message?.content ?? "").removeFirstBreakLine
36 | Markdown {
37 | message
38 | }
39 | .markdownTheme((chat.isMe) ? .user : .assistant)
40 | .padding(.horizontal, 30)
41 | .padding(.vertical, 16)
42 | .textSelection(.enabled)
43 | .foregroundColor((chat.isMe) ? .white : .black)
44 | .background((chat.isMe) ? .blue : .white)
45 |
46 |
47 | // Text(.init(message))
48 | // .padding(.horizontal, 30)
49 | // .padding(.vertical, 16)
50 | // .background((chat.isMe) ? .blue : .white)
51 | // .foregroundColor((chat.isMe) ? .white : .black)
52 | }
53 |
54 | }
55 |
56 |
--------------------------------------------------------------------------------
/OllamaGUI/UI/ChatHeader.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChatHeader.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/15/24.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct ChatHeader: View {
11 | @Environment(\.injected) var container
12 | var room:RoomEntity
13 | @Binding var show:Bool
14 | var onClean: ()->Void
15 | var body: some View {
16 | HStack(spacing: 0){
17 | Image(systemName: "message.fill").padding(.trailing)
18 | Text((room.title ?? "untitled").removeFirstBreakLine).lineLimit(1)
19 | Spacer()
20 | Button(action: {
21 | show.toggle()
22 | }, label: {
23 | Image(systemName: "xmark")
24 | }).buttonStyle(SidebarButton())
25 | }.padding(.leading).padding(.vertical)
26 | }
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/OllamaGUI/UI/ChatViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChatViewModel.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 3/13/24.
6 | //
7 |
8 | import Foundation
9 | import SwiftUI
10 | import Combine
11 |
12 | class ChatViewModel: ObservableObject {
13 | @Published var state: LangchainState = .initState
14 | @Published var bloc: LangchainBloc!
15 |
16 | func ignite(container: DIContainer, room: RoomEntity) {
17 | self.bloc = LangchainBloc(
18 | langchainUsecase: container.langchainusecase,
19 | chatUsecase: container.chatusecase,
20 | appSetting: container.appSetting,
21 | roomOption: room.option
22 | )
23 | print("bloc has been created")
24 | bloc.stateSubject.assign(to: &$state)
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/OllamaGUI/UI/Commen/ClearButton.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ClearButton.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/15/24.
6 | //
7 |
8 | import Foundation
9 | import SwiftUI
10 |
11 | struct ClearButton: ButtonStyle {
12 | private var enabled: Bool = true
13 |
14 | init(enabled: Bool = true) {
15 | self.enabled = enabled
16 | }
17 |
18 | func makeBody(configuration: Configuration) -> some View {
19 | configuration.label
20 | .opacity(configuration.isPressed ? 0.8 : 1)
21 | .padding(.vertical, 8)
22 | .padding(.horizontal, 15)
23 | .frame(minWidth: 48, minHeight: 0)
24 | .foregroundColor(.white)
25 | .focusEffectDisabled()
26 | .background(.clear)
27 | .clipShape(RoundedRectangle(cornerRadius: 3))
28 | }
29 | }
30 |
31 | #Preview {
32 | VStack {
33 | Button(action: {}) {
34 | Text("전송")
35 | }.buttonStyle(ClearButton())
36 | Button(action: {}) {
37 | Text("전송")
38 | }.buttonStyle(ClearButton(enabled: false))
39 |
40 | }.frame(width: 500, height: 500)
41 | }
42 |
--------------------------------------------------------------------------------
/OllamaGUI/UI/Commen/CommonButton.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CommonButton.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/11/24.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct CommonButton: ButtonStyle {
11 | private var enabled: Bool = true
12 |
13 | init(enabled: Bool = true) {
14 | self.enabled = enabled
15 | }
16 |
17 | func makeBody(configuration: Configuration) -> some View {
18 | configuration.label
19 | .opacity(configuration.isPressed ? 0.8 : 1)
20 | .padding(.vertical, 8)
21 | .padding(.horizontal, 15)
22 | .frame(minWidth: 48, minHeight: 0)
23 | .foregroundColor(.white)
24 | .focusEffectDisabled()
25 | .background(enabled ? .blue: .gray)
26 | .clipShape(RoundedRectangle(cornerRadius: 3))
27 | }
28 | }
29 |
30 | #Preview {
31 | VStack {
32 | Button(action: {}) {
33 | Text("전송")
34 | }.buttonStyle(CommonButton())
35 | Button(action: {}) {
36 | Text("전송")
37 | }.buttonStyle(CommonButton(enabled: false))
38 |
39 | }.frame(width: 500, height: 500)
40 | }
41 |
--------------------------------------------------------------------------------
/OllamaGUI/UI/Commen/Controller/KeyPressedController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // KeyPressedController.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/15/24.
6 | //
7 |
8 | import Foundation
9 | import Cocoa
10 |
11 | class KeyPressedController: ObservableObject {
12 | @Published var isShiftPressed = false
13 |
14 | init() {
15 | NSEvent
16 | .addLocalMonitorForEvents(matching: .flagsChanged) { [weak self] event -> NSEvent? in
17 | if event.modifierFlags.contains(.shift) {
18 | self?.isShiftPressed = true
19 | } else {
20 | self?.isShiftPressed = false
21 | }
22 | return event
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/OllamaGUI/UI/Commen/EditorButton.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CommonButton.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/11/24.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct EditorButton: ButtonStyle {
11 | @Binding var enabled: Bool
12 | @State private var color:Color = .gray
13 |
14 |
15 |
16 | func makeBody(configuration: Configuration) -> some View {
17 | configuration.label
18 | .frame(width: 20,height: 20)
19 | .opacity(configuration.isPressed ? 0.8 : 1)
20 | .frame(minWidth: 40, minHeight: 40,alignment: .center)
21 | .foregroundColor(enabled ? .blue : color)
22 | .background(.clear)
23 | .clipShape(RoundedRectangle(cornerRadius: 3))
24 | .onHover(perform: { hovering in
25 | if enabled {
26 | return
27 | }
28 | if hovering {
29 | color = .blue
30 | }else{
31 | color = .gray
32 | }
33 |
34 | })
35 | }
36 | }
37 |
38 | #Preview {
39 | VStack {
40 | Button(action: {}) {
41 | Image("MicIcon")
42 | }.buttonStyle(EditorButton(enabled: .constant(true)))
43 | Button(action: {}) {
44 | Image("MicIcon")
45 | }.buttonStyle(EditorButton(enabled: .constant(true)))
46 |
47 | }.frame(width: 500, height: 500)
48 | }
49 |
--------------------------------------------------------------------------------
/OllamaGUI/UI/Commen/SidebarButton.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SidebarButton.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/9/24.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct SidebarButton: ButtonStyle {
11 | func makeBody(configuration: Configuration) -> some View {
12 | configuration.label
13 | .frame(width: 25,height: 25)
14 | .frame(width: 40, height: 40,alignment: .center)
15 | .foregroundColor(.sidebarIcon)
16 | .opacity(configuration.isPressed ? 0.8 : 1)
17 | .focusEffectDisabled()
18 | }
19 |
20 | }
21 |
22 | #Preview {
23 | VStack {
24 | Button(action: {}) {
25 | Image(systemName: "message")
26 | }.buttonStyle(SidebarButton())
27 | }.frame(width: 500,height: 500)
28 | }
29 |
--------------------------------------------------------------------------------
/OllamaGUI/UI/Commen/XProgressView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProgressView.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/22/24.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct XProgressView: View {
11 | @Binding var progress: Float?
12 | var text: String
13 |
14 | @Binding var present: Bool
15 | var body: some View {
16 | VStack {
17 | Text(text).font(.body).padding()
18 | if progress != nil {
19 | ProgressView(value: progress)
20 | .frame(maxWidth: .infinity, minHeight: 20, maxHeight: 20)
21 | .padding(.bottom).padding(.horizontal)
22 | } else {
23 | ProgressView()
24 | .controlSize(.small).padding(.bottom)
25 | }
26 | }.frame(width: 300, height: 100)
27 | }
28 | }
29 |
30 | #Preview {
31 | XProgressView(
32 | progress: .constant(nil),
33 | text: "this is Text",
34 | present: .constant(true)
35 | )
36 | }
37 |
38 | #Preview {
39 | XProgressView(
40 | progress: .constant(0.5),
41 | text: "this is Text",
42 | present: .constant(true)
43 | )
44 | }
45 |
--------------------------------------------------------------------------------
/OllamaGUI/UI/Home/HomeView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HomeView.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/9/24.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct HomeView: View {
11 | var body: some View {
12 | Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/).frame(maxWidth: .infinity,maxHeight: .infinity)
13 | }
14 | }
15 |
16 | #Preview {
17 | HomeView()
18 | }
19 |
--------------------------------------------------------------------------------
/OllamaGUI/UI/Manager/Components/LibraryModelListView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LibraryModelList.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/20/24.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct LibraryModelListView: View {
11 | var model: OllamaModel
12 | @State var showTags = false
13 | @Binding var installed:[ModelInfoModel]
14 |
15 | var onUpdate: ()->Void
16 |
17 | var body: some View {
18 | VStack(spacing: 0) {
19 | HStack {
20 | Text(model.title)
21 | Spacer()
22 | Text(model.updatedAt)
23 | }
24 | Text(model.desc).textLeft.font(.body).foregroundColor(.gray)
25 | Spacer()
26 | HStack {
27 | Text(model.pulls)
28 | Text(model.tagsCount)
29 | Spacer()
30 | Button("show tags") {
31 | showTags.toggle()
32 | }
33 | }
34 |
35 | }.padding(.vertical).padding(.horizontal,0).frame(height: 80)
36 | .sheet(isPresented: $showTags, content: {
37 | TagsView(showTags:$showTags, model: model, installed:installed,onUpdate: onUpdate)
38 | })
39 | }
40 | }
41 |
42 | //#Preview {
43 | // List{
44 | // LibraryModelListView(model: OllamaModel(),installed:.constant([]))
45 | // }.listStyle(.plain)
46 | //}
47 |
--------------------------------------------------------------------------------
/OllamaGUI/UI/Manager/Components/ModelListView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ModelListView.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/20/24.
6 | //
7 |
8 | import Combine
9 | import SwiftUI
10 |
11 | struct ModelListView: View {
12 | @Environment(\.injected) var container
13 | var model: ModelInfoModel
14 |
15 | @State var showProgress: Bool = false
16 | @State var showAlert: Bool = false
17 | @State var cancel = Set()
18 | @State var subject = PassthroughSubject()
19 |
20 | var fetchModel: () -> Void
21 |
22 | var body: some View {
23 | VStack(spacing: 0) {
24 | HStack {
25 | Text(model.name)
26 | Spacer()
27 | Text(model.modifiedAt, style: .date)
28 | }
29 | Spacer()
30 | HStack {
31 | Spacer()
32 | Text(model.size.getSize)
33 | Button("remove") {
34 | handleClick()
35 | }
36 | }
37 |
38 | }.padding(.vertical).padding(.horizontal, 0).frame(height: 80)
39 | .onReceive(subject, perform: handleReceive)
40 | .sheet(isPresented: $showProgress, content: {
41 | XProgressView(
42 | progress: .constant(nil),
43 | text: "delete model \(model.name)",
44 | present: $showProgress
45 | )
46 | }).alert(isPresented: $showAlert, content: {
47 | Alert(
48 | title: Text("error"),
49 | message: Text("some error occurred when delete model"),
50 | dismissButton: .default(Text("ok"))
51 | )
52 | })
53 | }
54 | }
55 |
56 | extension ModelListView {
57 | func handleClick() {
58 | subject = container.interactor.deleteModel(
59 | cancel: &cancel,
60 | model: model,
61 | setting: container.appSetting
62 | )
63 | }
64 |
65 | func handleReceive(_ value: Bool) {
66 | showProgress = value
67 | if showProgress {
68 | fetchModel()
69 | } else {
70 | showAlert.toggle()
71 | }
72 | }
73 | }
74 |
75 | #Preview {
76 | List {
77 | // ModelListView(model: .preview)
78 | // ModelListView(model: .preview)
79 | // ModelListView(model: .preview)
80 | // ModelListView(model: .preview)
81 | // ModelListView(model: .preview)
82 | // ModelListView(model: .preview)
83 | }.listStyle(.plain)
84 | }
85 |
--------------------------------------------------------------------------------
/OllamaGUI/UI/OverlayToast.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OverlayToast.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/18/24.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct OverlayToast: View {
11 | var text: String = "preview"
12 |
13 | @State private var width: Double = 0
14 | @State private var opacity: Double = 0
15 | @State private var offsetY: Double = 20
16 |
17 | var body: some View {
18 | GeometryReader { geo in
19 |
20 | Text(text)
21 | .font(.body)
22 | .lineLimit(1)
23 | .padding(.horizontal)
24 | .padding(.vertical, 8)
25 | .background(.gray)
26 | .clipShape(RoundedRectangle(cornerRadius: 20))
27 | .frame(width: width)
28 | .position(CGPoint(x: geo.size.width / 2,
29 | y: geo.size.height - 170))
30 | .offset(y: offsetY)
31 | .opacity(opacity)
32 | .onAppear {
33 | withAnimation(.snappy) {
34 | width = Double(text.count * 14 + 16)
35 | opacity = 1
36 | offsetY = 0
37 | }
38 |
39 | DispatchQueue.global()
40 | .asyncAfter(deadline: .now() + 3) { [self] in
41 | DispatchQueue.main.async { [self] in
42 | withAnimation(.snappy) {
43 | width = 0
44 | opacity = 0
45 | offsetY = 20
46 | }
47 | }
48 | }
49 | }
50 | }
51 | }
52 | }
53 |
54 | #Preview {
55 | ChatView(
56 | show: .constant(true),
57 | position: .constant(.zero),
58 | floating: .constant(true),
59 | room: .randomRoom
60 | )
61 | }
62 |
--------------------------------------------------------------------------------
/OllamaGUI/UI/Room/RoomView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RoomView.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/17/24.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct RoomView: View {
11 | @Binding var rooms: [RoomEntity]
12 | var onInsert: () -> Void
13 | var onDelete: (RoomEntity) -> Void
14 |
15 | var body: some View {
16 | VStack {
17 | HStack {
18 | Text("Chat").font(.title)
19 | Spacer()
20 | Button(action: onInsert) {
21 | Image(systemName: "plus").resizable()
22 | .frame(width: 16, height: 16)
23 | }.buttonStyle(SidebarButton())
24 | }
25 | .padding(.top, 16)
26 | .padding(.leading)
27 | .padding(.bottom, 8)
28 | ScrollView {
29 | LazyVStack {
30 | ForEach(rooms, id: \.id) { room in
31 | RoomItem(room: room, onDelete: onDelete)
32 | }
33 | }
34 | }.frame(maxWidth: .infinity)
35 | }.ignoresSafeArea().background(.chat)
36 | }
37 | }
38 |
39 | #Preview {
40 | RootView().injectPreview()
41 | }
42 |
--------------------------------------------------------------------------------
/OllamaGUI/UI/SettingSheetViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SettingSheetViewModel.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 3/5/24.
6 | //
7 |
8 | import Foundation
9 |
10 | class SettingSheetViewModel: ObservableObject {
11 | @Published var options: RoomOptionEntity?
12 | @Published var system: String
13 | @Published var topk: Float
14 | @Published var topp: Float
15 | @Published var temperature: Float
16 |
17 |
18 |
19 | init() {
20 | options = nil
21 | system = ""
22 | topk = 40
23 | topp = 0.9
24 | temperature = 0.8
25 | }
26 |
27 |
28 | func reset() {
29 | options = nil
30 | system = ""
31 | topk = 40
32 | topp = 0.9
33 | temperature = 0.8
34 | }
35 |
36 |
37 | func apply() {
38 | if options == nil {
39 | options = RoomOptionEntity(model: nil, system: nil)
40 | }
41 | guard let options = options else {
42 | fatalError()
43 | }
44 | options.top_k = Int(topk)
45 | options.top_p = topp
46 | options.temperature = temperature
47 | if !system.isEmpty {
48 | options.system = system
49 | }
50 | print("success")
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/OllamaGUI/UI/SideBar/SideBar.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SideBar.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/9/24.
6 | //
7 |
8 | import Combine
9 | import SwiftUI
10 |
11 | struct SideBar: View {
12 | @Environment(\.injected) var container: DIContainer
13 | @Binding var rooms: [RoomEntity]
14 | @Binding var selected: RoomEntity?
15 |
16 | @State private var cancel = Set()
17 | @State private var subject = CurrentValueSubject(false)
18 | @State private var status: Bool = false
19 | @State private var showSetting: Bool = false
20 | var onSelect: (RoomEntity) -> Void
21 | var onInsert: () -> Void
22 | var onDelete: (RoomEntity) -> Void
23 |
24 | var body: some View {
25 | VStack {
26 | Spacer().frame(height: 35)
27 | Button(action: {}) {
28 | Image(systemName: "message").resizable()
29 | }.buttonStyle(SidebarButton())
30 | Spacer()
31 | Group {
32 | if status {
33 | Color.green
34 | } else {
35 | Color.red
36 | }
37 | }.frame(width: 15, height: 15)
38 | .clipShape(Circle())
39 | .shadow(radius: 5)
40 | Button(action: {
41 | showSetting.toggle()
42 | }) {
43 | Image(systemName: "gear").resizable()
44 | }.buttonStyle(SidebarButton())
45 | Spacer().frame(height: 35)
46 |
47 | }.onAppear {
48 | subject = container.interactor.checkNetwork(
49 | cancel: &cancel,
50 | setting: container.appSetting,
51 | baseUrl: nil,
52 | isTest: false
53 | )
54 | }.onReceive(subject, perform: { status in
55 | self.status = status
56 | })
57 | .sheet(isPresented: $showSetting, content: {
58 | SettingView(showSetting: $showSetting)
59 | })
60 | }
61 | }
62 |
63 | #Preview {
64 | RootView().injectPreview()
65 | }
66 |
--------------------------------------------------------------------------------
/OllamaGUI/UI/StopButton.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StopButton.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/15/24.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct StopButton: View {
11 |
12 | var onCancel:()->Void
13 | var body: some View {
14 | Button(action: {onCancel()}, label: {
15 | Label("STOP",systemImage: "stop.fill")
16 | }).buttonStyle(CommonButton())
17 | }
18 | }
19 |
20 |
--------------------------------------------------------------------------------
/OllamaGUI/UI/Tags/TagListItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TagListItem.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/22/24.
6 | //
7 |
8 | import Combine
9 | import Foundation
10 | import SwiftUI
11 |
12 | struct TagListItem: View {
13 | @Environment(\.injected) var container
14 |
15 | @State private var showProgress: Bool = false
16 | @State private var progress: Float?
17 | @State private var response: PullResponseModel?
18 | @State private var subject = PassthroughSubject<
19 | Loadable,
20 | Never
21 | >()
22 | @State private var bag = Set()
23 |
24 | var tag: OllamaTagModel
25 | var onPull: () -> Void
26 |
27 | var body: some View {
28 | VStack(spacing: 0) {
29 | HStack {
30 | Text(tag.title)
31 | Spacer()
32 | Text(tag.updatedAt)
33 | }
34 | Text(tag.sha).textLeft.font(.caption).foregroundColor(.gray)
35 | HStack {
36 | Text(tag.size).font(.caption).foregroundColor(.gray)
37 | Spacer()
38 | Button("pull") {
39 | handlePull()
40 | }.disabled(showProgress)
41 | }
42 |
43 | }.padding(.vertical).padding(.horizontal, 0).frame(height: 80)
44 | .sheet(
45 | isPresented: $showProgress,
46 | content: {
47 | XProgressView(
48 | progress: $progress,
49 | text: response?.status ?? "initialize",
50 | present: $showProgress
51 | )
52 | }
53 | ).onReceive(
54 | subject,
55 | perform: handleReceive
56 | )
57 | }
58 | }
59 |
60 | extension TagListItem {
61 | func handleReceive(value: Loadable) {
62 | switch value {
63 | case let .isLoading(last: val):
64 | response = val
65 | progress = val?.progress
66 | return
67 | case let .loaded(val):
68 | response = val
69 | progress = val.progress
70 | showProgress = false
71 | case .finished:
72 | showProgress = false
73 | onPull()
74 |
75 | default:
76 | return
77 | }
78 | }
79 |
80 | func handlePull() {
81 | subject = container.interactor.pullModel(
82 | cancel: &bag,
83 | model: tag,
84 | setting: container.appSetting
85 | )
86 | showProgress.toggle()
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/OllamaGUI/V2/Core.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Core.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 3/8/24.
6 | //
7 |
8 | import Foundation
9 |
--------------------------------------------------------------------------------
/OllamaGUI/V2/Core/SessionManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SessionManager.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 3/8/24.
6 | //
7 |
8 | import Foundation
9 |
10 | class SessionManager {
11 | var session: URLSession
12 |
13 | init() {
14 | session = URLSession(configuration: .default)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/OllamaGUI/V2/Data/Datasource/OllamaDatasource.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OllamaDatasource.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 3/8/24.
6 | //
7 |
8 | import Combine
9 | import Foundation
10 |
11 | protocol OllamaDatasource {
12 | var baseUrl: String { get set }
13 | var session: URLSession { get }
14 | func getEmbedding(prompt: String, model: String)
15 | -> AnyPublisher<[Float], NetworkError>
16 |
17 | func chat(req: ChatRequestModel) -> AnyPublisher
18 | }
19 |
20 | class OlamaDatasourceStub: OllamaDatasource {
21 | var baseUrl: String
22 | let session: URLSession
23 |
24 | init(baseUrl: String, session: URLSession) {
25 | self.baseUrl = baseUrl
26 | self.session = session
27 | }
28 |
29 | func getEmbedding(prompt _: String,
30 | model _: String) -> AnyPublisher<[Float], NetworkError>
31 | {
32 | return Just([]).setFailureType(to: NetworkError.self)
33 | .eraseToAnyPublisher()
34 | }
35 |
36 |
37 | func chat(req: ChatRequestModel) -> AnyPublisher {
38 | return Just(.init(entity: ChatEntity(message: .randomMessage, createdAt: .now))).setFailureType(to: NetworkError.self)
39 | .eraseToAnyPublisher()
40 | }
41 | }
42 |
43 | class OllamaDatasourceImpl: OllamaDatasource {
44 | var baseUrl: String
45 | let session: URLSession
46 |
47 | init(baseUrl: String, session: URLSession) {
48 | self.baseUrl = baseUrl
49 | self.session = session
50 | }
51 |
52 |
53 | func getEmbedding(prompt: String,
54 | model: String) -> AnyPublisher<[Float], NetworkError>
55 | {
56 | let api = APICall(
57 | session: session,
58 | baseUrl: baseUrl,
59 | url: "/api/embeddings",
60 | method: .post
61 | )
62 |
63 | let dto = EmbeddingDto(model: model, prompt: prompt)
64 |
65 | return api.call(data: dto).map { resDto in
66 | resDto.embedding
67 | }.eraseToAnyPublisher()
68 | }
69 |
70 |
71 | func chat(req: ChatRequestModel) -> AnyPublisher {
72 | var api = APICall(
73 | session: session, baseUrl: baseUrl, url: "/api/chat", method: .post)
74 |
75 | return api.callStream(data: req).eraseToAnyPublisher()
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/OllamaGUI/V2/Data/Datasource/WebDatasource.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WebDatasource.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 3/8/24.
6 | //
7 |
8 | import Combine
9 | import Foundation
10 |
11 | protocol WebDatasource {
12 | func crawlingWeb(for url: String) -> AnyPublisher
13 | }
14 |
15 | class WebDatasourceImpl: WebDatasource {
16 | var session: URLSession
17 |
18 | init(session: URLSession) {
19 | self.session = session
20 | }
21 |
22 | func crawlingWeb(for url: String) -> AnyPublisher {
23 | let req = APICall(session: session, baseUrl: url, url: "",
24 | method: .get)
25 | return req.callWithoutDecode().eraseToAnyPublisher()
26 | }
27 | }
28 |
29 | class WebDatasourceStub: WebDatasource {
30 | func crawlingWeb(for _: String) -> AnyPublisher {
31 | return Just("").setFailureType(to: NetworkError.self)
32 | .eraseToAnyPublisher()
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/OllamaGUI/V2/Data/Dto/EmbeddingDto.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EmbeddingDto.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 3/8/24.
6 | //
7 |
8 | import Foundation
9 |
10 | class EmbeddingDto: Encodable {
11 | var model: String
12 | var prompt: String
13 |
14 | init(model: String, prompt: String) {
15 | self.model = model
16 | self.prompt = prompt
17 | }
18 |
19 | enum CodingKeys: CodingKey {
20 | case model
21 | case prompt
22 | }
23 |
24 | func encode(to encoder: any Encoder) throws {
25 | var container = encoder.container(keyedBy: CodingKeys.self)
26 | try container.encode(model, forKey: .model)
27 | try container.encode(prompt, forKey: .prompt)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/OllamaGUI/V2/Data/Dto/EmbeddingResponseDto.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EmbeddingResponseDto.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 3/8/24.
6 | //
7 |
8 | import Foundation
9 |
10 | class EmbeddingResponseDto: Decodable {
11 | var embedding: [Float]
12 |
13 | enum CodingKeys: CodingKey {
14 | case embedding
15 | }
16 |
17 | required init(from decoder: any Decoder) throws {
18 | let container = try decoder.container(keyedBy: CodingKeys.self)
19 | embedding = try container.decode([Float].self, forKey: .embedding)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/OllamaGUI/V2/Data/Repository/CrawlingRepositoryImpl.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CrawlingRepositoryImpl.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 3/8/24.
6 | //
7 |
8 | import Foundation
9 | import Combine
10 |
11 | class CrawlingRepositoryImpl: CrawlingRepository {
12 | var datasource: WebDatasource
13 |
14 | init(datasource: WebDatasource) {
15 | self.datasource = datasource
16 | }
17 |
18 | func crawlingWeb(for url: String) -> AnyPublisher {
19 | datasource.crawlingWeb(for: url)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/OllamaGUI/V2/Data/Repository/OllmaRepositoryImpl.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EmbedingRepositoryImpl.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 3/8/24.
6 | //
7 |
8 | import Foundation
9 | import Combine
10 |
11 | class OllamaRepositoryImpl: OllamaRepository {
12 | var dataSource: OllamaDatasource
13 |
14 | init(dataSource: OllamaDatasource) {
15 | self.dataSource = dataSource
16 | }
17 |
18 | func getEmbeding(prompt: String,
19 | model: String) -> AnyPublisher<[Float], NetworkError>
20 | {
21 | dataSource.getEmbedding(prompt: prompt, model: model)
22 | }
23 |
24 | func chat(req: ChatRequestModel) -> AnyPublisher {
25 | dataSource.chat(req: req)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/OllamaGUI/V2/Domain/Repository/CrawlingRepository.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CrawlingRepository.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 3/8/24.
6 | //
7 |
8 | import Foundation
9 | import Combine
10 |
11 |
12 | protocol CrawlingRepository{
13 | func crawlingWeb(for: String) -> AnyPublisher
14 | }
15 |
--------------------------------------------------------------------------------
/OllamaGUI/V2/Domain/Repository/OllamaRepository.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EmbedingRepository.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 3/8/24.
6 | //
7 |
8 | import Foundation
9 | import Combine
10 |
11 | protocol OllamaRepository {
12 | func getEmbeding(prompt: String,model:String)->AnyPublisher<[Float],NetworkError>
13 | func chat(req:ChatRequestModel)->AnyPublisher
14 | }
15 |
--------------------------------------------------------------------------------
/OllamaGUI/V2/Domain/Usecase/ChatUsecase.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChatUsecase.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 3/11/24.
6 | //
7 |
8 | import Foundation
9 | import Combine
10 |
11 | class ChatUsecase {
12 | var ollamaRepository: OllamaRepository
13 | var bag = Set()
14 |
15 | init(ollamaRepository: OllamaRepository) {
16 | self.ollamaRepository = ollamaRepository
17 | }
18 |
19 | func cancelChat() {
20 | bag.removeAll()
21 | }
22 |
23 | func chatV2(req: ChatRequestModel, appSetting: AppSetting,option: RoomOptionEntity?) -> AnyPublisher {
24 | var dto = req
25 | dto.model = appSetting.model
26 | dto = dto.applyOption(option: option)
27 | return ollamaRepository.chat(req: dto).eraseToAnyPublisher()
28 | }
29 |
30 | func chat(req: ChatRequestModel, appSetting:AppSetting, options:RoomOptionEntity?) -> CurrentValueSubject,Never>{
31 | var dto = req
32 | dto.model = appSetting.model
33 | dto = dto.applyOption(option: options)
34 | let subject = CurrentValueSubject,Never>(.initState)
35 |
36 |
37 | ollamaRepository.chat(req: dto)
38 | .sink(receiveCompletion: { [weak self] com in
39 | switch com {
40 | case .finished:
41 | subject.send(.finished)
42 | subject.send(completion: .finished)
43 | self?.bag.removeAll()
44 | case let .failure(error):
45 | subject.send(.failed(error))
46 | self?.bag.removeAll()
47 | }
48 | }, receiveValue: { val in
49 | subject.send(.isLoading(last: val))
50 |
51 | })
52 | .store(in: &bag)
53 | return subject
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/OllamaGUI/V2/UI_v2/Chat/Bloc/LangchainEvent+State.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LangchainEvent+State.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 3/12/24.
6 | //
7 |
8 | import Foundation
9 |
10 | enum LangchainEvent {
11 | case GET_DOCUMENT_WEB(url: String)
12 | case REGENERATE_DOCUMENT(url: String)
13 | case GENERATE_EMBEDDING(prompt: String)
14 | case GET_ANSWER
15 | }
16 |
17 | enum LangchainState : BaseState{
18 | case initState
19 | case getDocument(url: String)
20 | case getEmbedding(progress: Int, total: Int)
21 | case idle(embeding: Embeddings,util: USearchUtil)
22 | case generating
23 | case readyToAsk(embedding: Embeddings, util: USearchUtil, context: [Document], prompt: String)
24 | case answer(embedding: Embeddings, util: USearchUtil, answer: Loadable)
25 | case generateAnswer(answer: String)
26 | case error(error: MuseError)
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/OllamaGUI/V2/UI_v2/Root/RootView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RootView.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 2/18/24.
6 | //
7 |
8 | import SwiftUI
9 | import SwiftUIIntrospect
10 |
11 | struct RootView: View {
12 | @Environment(\.modelContext) private var context
13 | @Environment(\.injected) private var container
14 |
15 | @ObservedObject private var viewModel = RootViewModel()
16 |
17 | var body: some View {
18 | Group {
19 | if viewModel.window != nil && viewModel.settingLoaded {
20 | root.onAppear {
21 | viewModel.afterWindowSet()
22 | }
23 | } else {
24 | EmptyView()
25 | }
26 | }
27 | .onAppear {
28 | viewModel.setup(container, context)
29 | viewModel.beforeWindowSet()
30 | }.background {
31 | WindowAccessor(window: $viewModel.window)
32 | }
33 | }
34 | }
35 |
36 | extension RootView {
37 | @ViewBuilder
38 | private var root: some View {
39 | NavigationSplitView(
40 | columnVisibility: $viewModel.sideBar, sidebar: {
41 | sidebar
42 | },
43 | detail: {
44 | room
45 | }
46 | )
47 | .navigationSplitViewStyle(.balanced)
48 | .background(.chatHover)
49 | .introspect(
50 | .navigationSplitView,
51 | on: .macOS(.v14, .v13),
52 | customize: { splitView in
53 | (splitView.delegate as? NSSplitViewController)?
54 | .splitViewItems
55 | .first?.canCollapse = false
56 | }
57 | )
58 | }
59 |
60 | @ViewBuilder
61 | private var room: some View {
62 | RoomView(
63 | rooms: $viewModel.rooms,
64 | onInsert: viewModel.onInsert,
65 | onDelete: viewModel.onDelete
66 | )
67 | }
68 |
69 | @ViewBuilder
70 | private var sidebar: some View {
71 | ZStack {
72 | Color.sidebar.ignoresSafeArea()
73 | SideBar(
74 | rooms: $viewModel.rooms,
75 | selected: $viewModel.room,
76 | onSelect: viewModel.onSelect,
77 | onInsert: viewModel.onInsert,
78 | onDelete: viewModel.onDelete
79 | )
80 | }.toolbar(removing: .sidebarToggle)
81 | .navigationSplitViewColumnWidth(
82 | min: 65,
83 | ideal: 65,
84 | max: 65
85 | )
86 | }
87 | }
88 |
89 |
90 | #Preview {
91 | RootView()
92 | }
93 |
--------------------------------------------------------------------------------
/OllamaGUI/V2/UI_v2/SidebarV2/SidebarV2.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SidebarV2.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 2/18/24.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct SidebarV2: View {
11 | var body: some View {
12 | Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
13 | }
14 | }
15 |
16 | #Preview {
17 | SidebarV2()
18 | }
19 |
--------------------------------------------------------------------------------
/OllamaGUI/V2/UI_v2/SidebarV2/SidebarV2ViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SidebarV2ViewModel.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 2/18/24.
6 | //
7 |
8 | import Foundation
9 |
10 |
11 |
--------------------------------------------------------------------------------
/OllamaGUI/V2/UI_v2/model/Embeddings.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Embeddings.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 3/12/24.
6 | //
7 |
8 | import Foundation
9 |
10 | enum EmbeddingsType {
11 | case web
12 | }
13 |
14 | protocol Embeddings {
15 | var type: EmbeddingsType { get }
16 | var doc: [Document] { get set }
17 | var vector: [[Float]] { get set }
18 | var name: String { get }
19 | }
20 |
21 | struct WebEmbeddings: Embeddings {
22 | var type: EmbeddingsType
23 | var doc: [Document]
24 | var html: String
25 | var url: String
26 | var vector: [[Float]]
27 |
28 | init(type: EmbeddingsType, doc: [Document], url: String) {
29 | self.type = type
30 | self.doc = doc
31 | self.url = url
32 | vector = []
33 | html = ""
34 | }
35 |
36 | var name: String {
37 | url.base64Data!.base64EncodedString()
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/OllamaGUI/ollamaGUI.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.files.user-selected.read-only
8 |
9 | com.apple.security.network.client
10 |
11 | com.apple.security.network.server
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/OllamaGUI/ollamaGUIApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ollamaGUIApp.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 1/9/24.
6 | //
7 |
8 | import SwiftData
9 | import SwiftUI
10 |
11 | struct VisualEffect: NSViewRepresentable {
12 | func makeNSView(context _: Self.Context) -> NSView {
13 | let view = NSVisualEffectView()
14 | view.blendingMode = .behindWindow
15 | view.state = .active
16 | view.material = .underWindowBackground
17 | return view
18 | }
19 |
20 | func updateNSView(_: NSView, context _: Context) {}
21 | }
22 |
23 | @main
24 | struct ollamaGUIApp: App {
25 | var body: some Scene {
26 | WindowGroup {
27 | RootView()
28 | .frame(minWidth: 390,maxWidth: 390, minHeight: 640,idealHeight:640)
29 | .inject()
30 | .preferredColorScheme(.dark)
31 | .modelContainer(
32 | for: [MessageEntity.self, ChatEntity.self, RoomEntity.self,AppSettingEntity.self]
33 | )
34 | }
35 | .windowStyle(HiddenTitleBarWindowStyle())
36 | .windowResizability(.contentSize)
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/OllamaGuiTest/Data/Datasource/OllamaDatasource.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OllamaDatasource.swift
3 | // ollamaGuiTest
4 | //
5 | // Created by 배상휘 on 3/8/24.
6 | //
7 |
8 | @testable import ollamaGUI
9 | import XCTest
10 |
11 | final class OllamaDatasourceTest: XCTestCase {
12 | var manager: SessionManager!
13 | var datasource: OllamaDatasource!
14 |
15 | override func setUp() {
16 | manager = SessionManager()
17 | datasource = OllamaDatasourceImpl(
18 | baseUrl: "http://localhost:11434",
19 | session: manager.session
20 | )
21 | }
22 |
23 | override func tearDown() {
24 | manager = nil
25 | datasource = nil
26 | }
27 |
28 | func test_임베딩() {
29 | let expectation = expectation(description: "get embeded")
30 | var res:[Float] = []
31 | let cancel = datasource.getEmbedding(prompt: "hello hi", model: "mistral")
32 | .sink(receiveCompletion: {
33 | switch $0 {
34 | case .finished:
35 | expectation.fulfill()
36 | XCTAssert(true,"success with \(res)")
37 | case let .failure(error):
38 | XCTAssert(false, "error with \(error.localizedDescription)")
39 | }
40 | }, receiveValue: { value in
41 | res = value
42 |
43 | })
44 |
45 | waitForExpectations(timeout: 20)
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/OllamaGuiTest/Data/Datasource/WebDatasource.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WebDatasource.swift
3 | // ollamaGuiTest
4 | //
5 | // Created by 배상휘 on 3/8/24.
6 | //
7 |
8 | @testable import ollamaGUI
9 | import XCTest
10 |
11 | final class WebDatasourceTest: XCTestCase {
12 | var manager: SessionManager!
13 | var datasource: WebDatasource!
14 |
15 | override func setUp() {
16 | manager = SessionManager()
17 | datasource = WebDatasourceImpl(
18 | session: manager.session
19 | )
20 | }
21 |
22 | override func tearDown() {
23 | manager = nil
24 | datasource = nil
25 | }
26 |
27 | func test_크롤링테스트() {
28 | let expectation = expectation(description: "crawling google")
29 | var res = ""
30 | _ = datasource.crawlingWeb(for: "https://google.com")
31 | .sink(receiveCompletion: {
32 | switch $0 {
33 | case .finished:
34 | expectation.fulfill()
35 | print(res)
36 | XCTAssert(true, "success with \(res)")
37 | case let .failure(error):
38 | XCTAssert(false, "error with \(error.localizedDescription)")
39 | expectation.fulfill()
40 | }
41 | }, receiveValue: { value in
42 | res = value
43 |
44 | })
45 |
46 | waitForExpectations(timeout: 20)
47 | }
48 |
49 | func test_크롤링테스트2() {
50 | let expectation = expectation(description: "crawling wiki")
51 | var res = ""
52 | _ = datasource.crawlingWeb(for: "https://en.wikipedia.org/wiki/Palworld")
53 | .sink(receiveCompletion: {
54 | switch $0 {
55 | case .finished:
56 | expectation.fulfill()
57 | print(res)
58 | XCTAssert(true, "success with \(res)")
59 | case let .failure(error):
60 | XCTAssert(false, "error with \(error.localizedDescription)")
61 | expectation.fulfill()
62 | }
63 | }, receiveValue: { value in
64 | res = value
65 |
66 | })
67 |
68 | waitForExpectations(timeout: 20)
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/OllamaGuiTest/Domain/Usecase/ChatUsecase.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChatUsecase.swift
3 | // ollamaGuiTest
4 | //
5 | // Created by 배상휘 on 3/11/24.
6 | //
7 |
8 | import Foundation
9 |
10 | import Combine
11 | @testable import ollamaGUI
12 | import SwiftData
13 | import XCTest
14 |
15 | class ChatUsecaseTest: XCTestCase {
16 | var container: ModelContainer!
17 | var chatUsecase: ChatUsecase!
18 | var appSetting: AppSetting!
19 |
20 | override func setUp() {
21 | let config = ModelConfiguration(isStoredInMemoryOnly: true)
22 | container = try? ModelContainer(for:
23 | MessageEntity.self, ChatEntity.self, RoomEntity.self,
24 | AppSettingEntity.self,
25 | configurations: config)
26 |
27 | let sessionManager = SessionManager()
28 | let ollamaDataSource = OllamaDatasourceImpl(
29 | baseUrl: "",
30 | session: sessionManager.session
31 | )
32 | appSetting = AppSetting(ollamaDs: ollamaDataSource)
33 | appSetting
34 | .updateSetting(.init(baseUrl: "http://localhost:11434",
35 | selectedModel: "mistral"))
36 |
37 | let ollamaRepository =
38 | OllamaRepositoryImpl(dataSource: ollamaDataSource)
39 | chatUsecase = ChatUsecase(ollamaRepository: ollamaRepository)
40 | }
41 |
42 | override func tearDown() {
43 | chatUsecase = nil
44 | container = nil
45 | }
46 |
47 | func test_채팅() {
48 | let ex = expectation(description: "wait for complete")
49 | let req = ChatRequestModel(of: .init(text: "hello"))
50 | var bag = Set()
51 | chatUsecase.chat(req: req, appSetting: appSetting, options: nil)
52 | .sink(
53 | receiveCompletion: { comp in
54 | switch comp {
55 | case .finished:
56 | ex.fulfill()
57 | }
58 |
59 | },
60 | receiveValue: { val in
61 | switch val {
62 | case let .failed(err):
63 | print(err.localizedDescription)
64 | ex.fulfill()
65 | return
66 | default:
67 | print(val)
68 | }
69 | }
70 | ).store(in: &bag)
71 |
72 | waitForExpectations(timeout: 20)
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/OllamaGuiTest/Domain/Usecase/Langchain+ChatUsecase.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Langchain+ChatUsecase.swift
3 | // ollamaGuiTest
4 | //
5 | // Created by 배상휘 on 3/12/24.
6 | //
7 |
8 | import Combine
9 | import Foundation
10 | @testable import ollamaGUI
11 | import SwiftData
12 | import XCTest
13 |
14 | class LangChainChatUsecaseTest: XCTestCase {
15 | var container: ModelContainer!
16 | var chatUsecase: ChatUsecase!
17 | var appSetting: AppSetting!
18 | var langchainUsecase: LangchainUsecase!
19 |
20 | override func setUp() {
21 | let config = ModelConfiguration(isStoredInMemoryOnly: true)
22 | container = try? ModelContainer(for:
23 | MessageEntity.self, ChatEntity.self, RoomEntity.self,
24 | AppSettingEntity.self,
25 | configurations: config)
26 |
27 | let sessionManager = SessionManager()
28 |
29 | let ollamaDataSource = OllamaDatasourceImpl(
30 | baseUrl: appSetting.baseUrl,
31 | session: sessionManager.session
32 | )
33 | appSetting = AppSetting(ollamaDs: ollamaDataSource)
34 | appSetting
35 | .updateSetting(.init(baseUrl: "http://localhost:11434",
36 | selectedModel: "mistral"))
37 | let webDataSource = WebDatasourceImpl(session: sessionManager.session)
38 | let ollamaRepository =
39 | OllamaRepositoryImpl(dataSource: ollamaDataSource)
40 | let crawlingRepository =
41 | CrawlingRepositoryImpl(datasource: webDataSource)
42 | chatUsecase = ChatUsecase(ollamaRepository: ollamaRepository)
43 | langchainUsecase = LangchainUsecase(
44 | embedingRepository: ollamaRepository,
45 | crawlingRepository: crawlingRepository
46 | )
47 | }
48 |
49 | override func tearDown() {
50 | chatUsecase = nil
51 | langchainUsecase = nil
52 | appSetting = nil
53 | container = nil
54 | }
55 |
56 | func test_EmbeddingChat() {
57 |
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/OllamaGuiTest/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSAppTransportSecurity
6 |
7 | NSAllowsArbitraryLoads
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/OllamaGuiTest/ollamaGuiTest.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ollamaGuiTest.swift
3 | // ollamaGuiTest
4 | //
5 | // Created by 배상휘 on 3/8/24.
6 | //
7 |
8 | import XCTest
9 | @testable import ollamaGUI
10 |
11 | final class ollamaGuiTest: XCTestCase {
12 |
13 | override func setUpWithError() throws {
14 | // Put setup code here. This method is called before the invocation of each test method in the class.
15 | }
16 |
17 | override func tearDownWithError() throws {
18 | // Put teardown code here. This method is called after the invocation of each test method in the class.
19 | }
20 |
21 | func testExample() throws {
22 | // This is an example of a functional test case.
23 | // Use XCTAssert and related functions to verify your tests produce the correct results.
24 | // Any test you write for XCTest can be annotated as throws and async.
25 | // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
26 | // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
27 | }
28 |
29 | func testPerformanceExample() throws {
30 | // This is an example of a performance test case.
31 | measure {
32 | // Put the code you want to measure the time of here.
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment the next line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | target 'ollamaGUI' do
5 | # Comment the next line if you don't want to use dynamic frameworks
6 | use_frameworks!
7 |
8 | # Pods for ollamaGUI
9 | pod 'SwiftUIIntrospect', '~> 1.0'
10 | pod 'Alamofire'
11 | pod 'SwiftSoup'
12 |
13 | end
14 |
--------------------------------------------------------------------------------
/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Alamofire (5.8.1)
3 | - SwiftSoup (2.7.0)
4 | - SwiftUIIntrospect (1.1.1)
5 |
6 | DEPENDENCIES:
7 | - Alamofire
8 | - SwiftSoup
9 | - SwiftUIIntrospect (~> 1.0)
10 |
11 | SPEC REPOS:
12 | trunk:
13 | - Alamofire
14 | - SwiftSoup
15 | - SwiftUIIntrospect
16 |
17 | SPEC CHECKSUMS:
18 | Alamofire: 3ca42e259043ee0dc5c0cdd76c4bc568b8e42af7
19 | SwiftSoup: 06cbbf665257adfbfe0c927c63de246e5e844b9d
20 | SwiftUIIntrospect: db5290a3492424eb4afcab77cebcd4595de3bd71
21 |
22 | PODFILE CHECKSUM: fd8561c90a9346cbc2ae69807a3d7301b3553a18
23 |
24 | COCOAPODS: 1.14.3
25 |
--------------------------------------------------------------------------------
/Pods/Alamofire/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014-2022 Alamofire Software Foundation (http://alamofire.org/)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/Pods/Alamofire/Source/Alamofire.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Alamofire.swift
3 | //
4 | // Copyright (c) 2014-2021 Alamofire Software Foundation (http://alamofire.org/)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Dispatch
26 | import Foundation
27 | #if canImport(FoundationNetworking)
28 | @_exported import FoundationNetworking
29 | #endif
30 |
31 | // Enforce minimum Swift version for all platforms and build systems.
32 | #if swift(<5.5)
33 | #error("Alamofire doesn't support Swift versions below 5.5.")
34 | #endif
35 |
36 | /// Reference to `Session.default` for quick bootstrapping and examples.
37 | public let AF = Session.default
38 |
39 | /// Current Alamofire version. Necessary since SPM doesn't use dynamic libraries. Plus this will be more accurate.
40 | let version = "5.8.0"
41 |
--------------------------------------------------------------------------------
/Pods/Alamofire/Source/AlamofireExtended.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AlamofireExtended.swift
3 | //
4 | // Copyright (c) 2019 Alamofire Software Foundation (http://alamofire.org/)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | /// Type that acts as a generic extension point for all `AlamofireExtended` types.
26 | public struct AlamofireExtension {
27 | /// Stores the type or meta-type of any extended type.
28 | public private(set) var type: ExtendedType
29 |
30 | /// Create an instance from the provided value.
31 | ///
32 | /// - Parameter type: Instance being extended.
33 | public init(_ type: ExtendedType) {
34 | self.type = type
35 | }
36 | }
37 |
38 | /// Protocol describing the `af` extension points for Alamofire extended types.
39 | public protocol AlamofireExtended {
40 | /// Type being extended.
41 | associatedtype ExtendedType
42 |
43 | /// Static Alamofire extension point.
44 | static var af: AlamofireExtension.Type { get set }
45 | /// Instance Alamofire extension point.
46 | var af: AlamofireExtension { get set }
47 | }
48 |
49 | extension AlamofireExtended {
50 | /// Static Alamofire extension point.
51 | public static var af: AlamofireExtension.Type {
52 | get { AlamofireExtension.self }
53 | set {}
54 | }
55 |
56 | /// Instance Alamofire extension point.
57 | public var af: AlamofireExtension {
58 | get { AlamofireExtension(self) }
59 | set {}
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Pods/Alamofire/Source/DispatchQueue+Alamofire.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DispatchQueue+Alamofire.swift
3 | //
4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Dispatch
26 | import Foundation
27 |
28 | extension DispatchQueue {
29 | /// Execute the provided closure after a `TimeInterval`.
30 | ///
31 | /// - Parameters:
32 | /// - delay: `TimeInterval` to delay execution.
33 | /// - closure: Closure to execute.
34 | func after(_ delay: TimeInterval, execute closure: @escaping () -> Void) {
35 | asyncAfter(deadline: .now() + delay, execute: closure)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Pods/Alamofire/Source/HTTPMethod.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HTTPMethod.swift
3 | //
4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | /// Type representing HTTP methods. Raw `String` value is stored and compared case-sensitively, so
26 | /// `HTTPMethod.get != HTTPMethod(rawValue: "get")`.
27 | ///
28 | /// See https://tools.ietf.org/html/rfc7231#section-4.3
29 | public struct HTTPMethod: RawRepresentable, Equatable, Hashable {
30 | /// `CONNECT` method.
31 | public static let connect = HTTPMethod(rawValue: "CONNECT")
32 | /// `DELETE` method.
33 | public static let delete = HTTPMethod(rawValue: "DELETE")
34 | /// `GET` method.
35 | public static let get = HTTPMethod(rawValue: "GET")
36 | /// `HEAD` method.
37 | public static let head = HTTPMethod(rawValue: "HEAD")
38 | /// `OPTIONS` method.
39 | public static let options = HTTPMethod(rawValue: "OPTIONS")
40 | /// `PATCH` method.
41 | public static let patch = HTTPMethod(rawValue: "PATCH")
42 | /// `POST` method.
43 | public static let post = HTTPMethod(rawValue: "POST")
44 | /// `PUT` method.
45 | public static let put = HTTPMethod(rawValue: "PUT")
46 | /// `QUERY` method.
47 | public static let query = HTTPMethod(rawValue: "QUERY")
48 | /// `TRACE` method.
49 | public static let trace = HTTPMethod(rawValue: "TRACE")
50 |
51 | public let rawValue: String
52 |
53 | public init(rawValue: String) {
54 | self.rawValue = rawValue
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Pods/Alamofire/Source/OperationQueue+Alamofire.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OperationQueue+Alamofire.swift
3 | //
4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | extension OperationQueue {
28 | /// Creates an instance using the provided parameters.
29 | ///
30 | /// - Parameters:
31 | /// - qualityOfService: `QualityOfService` to be applied to the queue. `.default` by default.
32 | /// - maxConcurrentOperationCount: Maximum concurrent operations.
33 | /// `OperationQueue.defaultMaxConcurrentOperationCount` by default.
34 | /// - underlyingQueue: Underlying `DispatchQueue`. `nil` by default.
35 | /// - name: Name for the queue. `nil` by default.
36 | /// - startSuspended: Whether the queue starts suspended. `false` by default.
37 | convenience init(qualityOfService: QualityOfService = .default,
38 | maxConcurrentOperationCount: Int = OperationQueue.defaultMaxConcurrentOperationCount,
39 | underlyingQueue: DispatchQueue? = nil,
40 | name: String? = nil,
41 | startSuspended: Bool = false) {
42 | self.init()
43 | self.qualityOfService = qualityOfService
44 | self.maxConcurrentOperationCount = maxConcurrentOperationCount
45 | self.underlyingQueue = underlyingQueue
46 | self.name = name
47 | isSuspended = startSuspended
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Pods/Alamofire/Source/StringEncoding+Alamofire.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StringEncoding+Alamofire.swift
3 | //
4 | // Copyright (c) 2020 Alamofire Software Foundation (http://alamofire.org/)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | extension String.Encoding {
28 | /// Creates an encoding from the IANA charset name.
29 | ///
30 | /// - Notes: These mappings match those [provided by CoreFoundation](https://opensource.apple.com/source/CF/CF-476.18/CFStringUtilities.c.auto.html)
31 | ///
32 | /// - Parameter name: IANA charset name.
33 | init?(ianaCharsetName name: String) {
34 | switch name.lowercased() {
35 | case "utf-8":
36 | self = .utf8
37 | case "iso-8859-1":
38 | self = .isoLatin1
39 | case "unicode-1-1", "iso-10646-ucs-2", "utf-16":
40 | self = .utf16
41 | case "utf-16be":
42 | self = .utf16BigEndian
43 | case "utf-16le":
44 | self = .utf16LittleEndian
45 | case "utf-32":
46 | self = .utf32
47 | case "utf-32be":
48 | self = .utf32BigEndian
49 | case "utf-32le":
50 | self = .utf32LittleEndian
51 | default:
52 | return nil
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Pods/Alamofire/Source/URLRequest+Alamofire.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URLRequest+Alamofire.swift
3 | //
4 | // Copyright (c) 2019 Alamofire Software Foundation (http://alamofire.org/)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | extension URLRequest {
28 | /// Returns the `httpMethod` as Alamofire's `HTTPMethod` type.
29 | public var method: HTTPMethod? {
30 | get { httpMethod.map(HTTPMethod.init) }
31 | set { httpMethod = newValue?.rawValue }
32 | }
33 |
34 | public func validate() throws {
35 | if method == .get, let bodyData = httpBody {
36 | throw AFError.urlRequestValidationFailed(reason: .bodyDataInGETRequest(bodyData))
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Pods/Alamofire/Source/URLSessionConfiguration+Alamofire.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URLSessionConfiguration+Alamofire.swift
3 | //
4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | extension URLSessionConfiguration: AlamofireExtended {}
28 | extension AlamofireExtension where ExtendedType: URLSessionConfiguration {
29 | /// Alamofire's default configuration. Same as `URLSessionConfiguration.default` but adds Alamofire default
30 | /// `Accept-Language`, `Accept-Encoding`, and `User-Agent` headers.
31 | public static var `default`: URLSessionConfiguration {
32 | let configuration = URLSessionConfiguration.default
33 | configuration.headers = .default
34 |
35 | return configuration
36 | }
37 |
38 | /// `.ephemeral` configuration with Alamofire's default `Accept-Language`, `Accept-Encoding`, and `User-Agent`
39 | /// headers.
40 | public static var ephemeral: URLSessionConfiguration {
41 | let configuration = URLSessionConfiguration.ephemeral
42 | configuration.headers = .default
43 |
44 | return configuration
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Pods/Manifest.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Alamofire (5.8.1)
3 | - SwiftSoup (2.7.0)
4 | - SwiftUIIntrospect (1.1.1)
5 |
6 | DEPENDENCIES:
7 | - Alamofire
8 | - SwiftSoup
9 | - SwiftUIIntrospect (~> 1.0)
10 |
11 | SPEC REPOS:
12 | trunk:
13 | - Alamofire
14 | - SwiftSoup
15 | - SwiftUIIntrospect
16 |
17 | SPEC CHECKSUMS:
18 | Alamofire: 3ca42e259043ee0dc5c0cdd76c4bc568b8e42af7
19 | SwiftSoup: 06cbbf665257adfbfe0c927c63de246e5e844b9d
20 | SwiftUIIntrospect: db5290a3492424eb4afcab77cebcd4595de3bd71
21 |
22 | PODFILE CHECKSUM: fd8561c90a9346cbc2ae69807a3d7301b3553a18
23 |
24 | COCOAPODS: 1.14.3
25 |
--------------------------------------------------------------------------------
/Pods/Pods.xcodeproj/xcuserdata/baesanghwi.xcuserdatad/xcschemes/Alamofire.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
53 |
54 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/Pods/Pods.xcodeproj/xcuserdata/baesanghwi.xcuserdatad/xcschemes/Pods-ollamaGUI.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
53 |
54 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/Pods/Pods.xcodeproj/xcuserdata/baesanghwi.xcuserdatad/xcschemes/SwiftUIIntrospect.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
53 |
54 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/Pods/Pods.xcodeproj/xcuserdata/baesanghwi.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | Alamofire.xcscheme
8 |
9 | isShown
10 |
11 |
12 | Pods-ollamaGUI.xcscheme
13 |
14 | isShown
15 |
16 |
17 | SwiftSoup.xcscheme
18 |
19 | isShown
20 |
21 |
22 | SwiftUIIntrospect.xcscheme
23 |
24 | isShown
25 |
26 |
27 |
28 | SuppressBuildableAutocreation
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Pods/SwiftUIIntrospect/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2019 Timber Software
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/Pods/SwiftUIIntrospect/Sources/IntrospectableViewType.swift:
--------------------------------------------------------------------------------
1 | #if !os(watchOS)
2 | public protocol IntrospectableViewType {
3 | /// The scope of introspection for this particular view type, i.e. where introspect
4 | /// should look to find the desired target view relative to the applied
5 | /// `.introspect(...)` modifier.
6 | ///
7 | /// While the scope can be overridden by the user in their `.introspect(...)` call,
8 | /// most of the time it's preferable to defer to the view type's own scope,
9 | /// as it guarantees introspection is working as intended by the vendor.
10 | ///
11 | /// Defaults to `.receiver` if left unimplemented, which is a sensible one in
12 | /// most cases if you're looking to implement your own view type.
13 | var scope: IntrospectionScope { get }
14 | }
15 |
16 | extension IntrospectableViewType {
17 | public var scope: IntrospectionScope { .receiver }
18 | }
19 | #endif
20 |
--------------------------------------------------------------------------------
/Pods/SwiftUIIntrospect/Sources/PlatformView.swift:
--------------------------------------------------------------------------------
1 | #if !os(watchOS)
2 | import SwiftUI
3 |
4 | #if canImport(UIKit)
5 | public typealias PlatformView = UIView
6 | #elseif canImport(AppKit)
7 | public typealias PlatformView = NSView
8 | #endif
9 |
10 | #if canImport(UIKit)
11 | public typealias PlatformViewController = UIViewController
12 | #elseif canImport(AppKit)
13 | public typealias PlatformViewController = NSViewController
14 | #endif
15 |
16 | #if canImport(UIKit)
17 | typealias _PlatformViewControllerRepresentable = UIViewControllerRepresentable
18 | #elseif canImport(AppKit)
19 | typealias _PlatformViewControllerRepresentable = NSViewControllerRepresentable
20 | #endif
21 |
22 | protocol PlatformViewControllerRepresentable: _PlatformViewControllerRepresentable {
23 | #if canImport(UIKit)
24 | typealias ViewController = UIViewControllerType
25 | #elseif canImport(AppKit)
26 | typealias ViewController = NSViewControllerType
27 | #endif
28 |
29 | func makePlatformViewController(context: Context) -> ViewController
30 | func updatePlatformViewController(_ controller: ViewController, context: Context)
31 | static func dismantlePlatformViewController(_ controller: ViewController, coordinator: Coordinator)
32 | }
33 |
34 | extension PlatformViewControllerRepresentable {
35 | #if canImport(UIKit)
36 | func makeUIViewController(context: Context) -> ViewController {
37 | makePlatformViewController(context: context)
38 | }
39 | func updateUIViewController(_ controller: ViewController, context: Context) {
40 | updatePlatformViewController(controller, context: context)
41 | }
42 | static func dismantleUIViewController(_ controller: ViewController, coordinator: Coordinator) {
43 | dismantlePlatformViewController(controller, coordinator: coordinator)
44 | }
45 | #elseif canImport(AppKit)
46 | func makeNSViewController(context: Context) -> ViewController {
47 | makePlatformViewController(context: context)
48 | }
49 | func updateNSViewController(_ controller: ViewController, context: Context) {
50 | updatePlatformViewController(controller, context: context)
51 | }
52 | static func dismantleNSViewController(_ controller: ViewController, coordinator: Coordinator) {
53 | dismantlePlatformViewController(controller, coordinator: coordinator)
54 | }
55 | #endif
56 | }
57 | #endif
58 |
--------------------------------------------------------------------------------
/Pods/SwiftUIIntrospect/Sources/Utils.swift:
--------------------------------------------------------------------------------
1 | postfix operator ~
2 |
3 | postfix func ~ (lhs: LHS) -> T {
4 | lhs as! T
5 | }
6 |
7 | postfix func ~ (lhs: LHS?) -> T? {
8 | lhs as? T
9 | }
10 |
11 | func recursiveSequence(_ sequence: S, children: @escaping (S.Element) -> S) -> AnySequence {
12 | AnySequence {
13 | var mainIterator = sequence.makeIterator()
14 | // Current iterator, or `nil` if all sequences are exhausted:
15 | var iterator: AnyIterator?
16 |
17 | return AnyIterator {
18 | guard let iterator, let element = iterator.next() else {
19 | if let element = mainIterator.next() {
20 | iterator = recursiveSequence(children(element), children: children).makeIterator()
21 | return element
22 | }
23 | return nil
24 | }
25 | return element
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Pods/SwiftUIIntrospect/Sources/ViewTypes/Button.swift:
--------------------------------------------------------------------------------
1 | #if !os(watchOS)
2 | import SwiftUI
3 |
4 | /// An abstract representation of the `Button` type in SwiftUI.
5 | ///
6 | /// ### iOS
7 | ///
8 | /// Not available.
9 | ///
10 | /// ### tvOS
11 | ///
12 | /// Not available.
13 | ///
14 | /// ### macOS
15 | ///
16 | /// ```swift
17 | /// struct ContentView: View {
18 | /// var body: some View {
19 | /// Button("Action", action: {})
20 | /// .introspect(.button, on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) {
21 | /// print(type(of: $0)) // NSButton
22 | /// }
23 | /// }
24 | /// }
25 | /// ```
26 | ///
27 | /// ### visionOS
28 | ///
29 | /// Not available.
30 | public struct ButtonType: IntrospectableViewType {}
31 |
32 | #if !os(iOS) && !os(tvOS) && !os(visionOS)
33 | extension IntrospectableViewType where Self == ButtonType {
34 | public static var button: Self { .init() }
35 | }
36 |
37 | #if canImport(AppKit) && !targetEnvironment(macCatalyst)
38 | extension macOSViewVersion {
39 | public static let v10_15 = Self(for: .v10_15)
40 | public static let v11 = Self(for: .v11)
41 | public static let v12 = Self(for: .v12)
42 | public static let v13 = Self(for: .v13)
43 | public static let v14 = Self(for: .v14)
44 | }
45 | #endif
46 | #endif
47 | #endif
48 |
--------------------------------------------------------------------------------
/Pods/SwiftUIIntrospect/Sources/ViewTypes/ColorPicker.swift:
--------------------------------------------------------------------------------
1 | #if !os(watchOS)
2 | import SwiftUI
3 |
4 | /// An abstract representation of the `ColorPicker` type in SwiftUI.
5 | ///
6 | /// ### iOS
7 | ///
8 | /// ```swift
9 | /// struct ContentView: View {
10 | /// @State var color = Color.red
11 | ///
12 | /// var body: some View {
13 | /// ColorPicker("Pick a color", selection: $color)
14 | /// .introspect(.colorPicker, on: .iOS(.v14, .v15, .v16, .v17)) {
15 | /// print(type(of: $0)) // UIColorPicker
16 | /// }
17 | /// }
18 | /// }
19 | /// ```
20 | ///
21 | /// ### tvOS
22 | ///
23 | /// Not available.
24 | ///
25 | /// ### macOS
26 | ///
27 | /// ```swift
28 | /// struct ContentView: View {
29 | /// @State var color = Color.red
30 | ///
31 | /// var body: some View {
32 | /// ColorPicker("Pick a color", selection: $color)
33 | /// .introspect(.colorPicker, on: .macOS(.v11, .v12, .v13, .v14)) {
34 | /// print(type(of: $0)) // NSColorPicker
35 | /// }
36 | /// }
37 | /// }
38 | /// ```
39 | ///
40 | /// ### visionOS
41 | ///
42 | /// ```swift
43 | /// struct ContentView: View {
44 | /// @State var color = Color.red
45 | ///
46 | /// var body: some View {
47 | /// ColorPicker("Pick a color", selection: $color)
48 | /// .introspect(.colorPicker, on: .visionOS(.v1)) {
49 | /// print(type(of: $0)) // UIColorPicker
50 | /// }
51 | /// }
52 | /// }
53 | /// ```
54 | public struct ColorPickerType: IntrospectableViewType {}
55 |
56 | #if !os(tvOS)
57 | extension IntrospectableViewType where Self == ColorPickerType {
58 | public static var colorPicker: Self { .init() }
59 | }
60 |
61 | #if canImport(UIKit)
62 | @available(iOS 14, *)
63 | extension iOSViewVersion {
64 | @available(*, unavailable, message: "ColorPicker isn't available on iOS 13")
65 | public static let v13 = Self.unavailable()
66 | public static let v14 = Self(for: .v14)
67 | public static let v15 = Self(for: .v15)
68 | public static let v16 = Self(for: .v16)
69 | public static let v17 = Self(for: .v17)
70 | }
71 |
72 | @available(iOS 14, *)
73 | extension visionOSViewVersion {
74 | public static let v1 = Self(for: .v1)
75 | }
76 | #elseif canImport(AppKit)
77 | @available(macOS 11, *)
78 | extension macOSViewVersion {
79 | @available(*, unavailable, message: "ColorPicker isn't available on macOS 10.15")
80 | public static let v10_15 = Self.unavailable()
81 | public static let v11 = Self(for: .v11)
82 | public static let v12 = Self(for: .v12)
83 | public static let v13 = Self(for: .v13)
84 | public static let v14 = Self(for: .v14)
85 | }
86 | #endif
87 | #endif
88 | #endif
89 |
--------------------------------------------------------------------------------
/Pods/SwiftUIIntrospect/Sources/ViewTypes/DatePicker.swift:
--------------------------------------------------------------------------------
1 | #if !os(watchOS)
2 | import SwiftUI
3 |
4 | /// An abstract representation of the `DatePicker` type in SwiftUI.
5 | ///
6 | /// ### iOS
7 | ///
8 | /// ```swift
9 | /// struct ContentView: View {
10 | /// @State var date = Date()
11 | ///
12 | /// var body: some View {
13 | /// DatePicker("Pick a date", selection: $date)
14 | /// .introspect(.datePicker, on: .iOS(.v13, .v14, .v15, .v16, .v17)) {
15 | /// print(type(of: $0)) // UIDatePicker
16 | /// }
17 | /// }
18 | /// }
19 | /// ```
20 | ///
21 | /// ### tvOS
22 | ///
23 | /// Not available.
24 | ///
25 | /// ```swift
26 | /// struct ContentView: View {
27 | /// @State var date = Date()
28 | ///
29 | /// var body: some View {
30 | /// DatePicker("Pick a date", selection: $date)
31 | /// .introspect(.datePicker, on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) {
32 | /// print(type(of: $0)) // NSDatePicker
33 | /// }
34 | /// }
35 | /// }
36 | /// ```
37 | ///
38 | /// ### visionOS
39 | ///
40 | /// ```swift
41 | /// struct ContentView: View {
42 | /// @State var date = Date()
43 | ///
44 | /// var body: some View {
45 | /// DatePicker("Pick a date", selection: $date)
46 | /// .introspect(.datePicker, on: .visionOS(.v1)) {
47 | /// print(type(of: $0)) // UIDatePicker
48 | /// }
49 | /// }
50 | /// }
51 | /// ```
52 | public struct DatePickerType: IntrospectableViewType {}
53 |
54 | #if !os(tvOS)
55 | extension IntrospectableViewType where Self == DatePickerType {
56 | public static var datePicker: Self { .init() }
57 | }
58 |
59 | #if canImport(UIKit)
60 | extension iOSViewVersion {
61 | public static let v13 = Self(for: .v13)
62 | public static let v14 = Self(for: .v14)
63 | public static let v15 = Self(for: .v15)
64 | public static let v16 = Self(for: .v16)
65 | public static let v17 = Self(for: .v17)
66 | }
67 |
68 | extension visionOSViewVersion {
69 | public static let v1 = Self(for: .v1)
70 | }
71 | #elseif canImport(AppKit)
72 | extension macOSViewVersion {
73 | public static let v10_15 = Self(for: .v10_15)
74 | public static let v11 = Self(for: .v11)
75 | public static let v12 = Self(for: .v12)
76 | public static let v13 = Self(for: .v13)
77 | public static let v14 = Self(for: .v14)
78 | }
79 | #endif
80 | #endif
81 | #endif
82 |
--------------------------------------------------------------------------------
/Pods/SwiftUIIntrospect/Sources/ViewTypes/DatePickerWithFieldStyle.swift:
--------------------------------------------------------------------------------
1 | #if !os(watchOS)
2 | import SwiftUI
3 |
4 | /// An abstract representation of the `DatePicker` type in SwiftUI, with `.field` style.
5 | ///
6 | /// ### iOS
7 | ///
8 | /// Not available.
9 | ///
10 | /// ### tvOS
11 | ///
12 | /// Not available.
13 | ///
14 | /// ### macOS
15 | ///
16 | /// ```swift
17 | /// struct ContentView: View {
18 | /// @State var date = Date()
19 | ///
20 | /// var body: some View {
21 | /// DatePicker("Pick a date", selection: $date)
22 | /// .datePickerStyle(.field)
23 | /// .introspect(.datePicker(style: .field), on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) {
24 | /// print(type(of: $0)) // NSDatePicker
25 | /// }
26 | /// }
27 | /// }
28 | /// ```
29 | ///
30 | /// ### visionOS
31 | ///
32 | /// Not available.
33 | public struct DatePickerWithFieldStyleType: IntrospectableViewType {
34 | public enum Style {
35 | case field
36 | }
37 | }
38 |
39 | #if !os(iOS) && !os(tvOS) && !os(visionOS)
40 | extension IntrospectableViewType where Self == DatePickerWithFieldStyleType {
41 | public static func datePicker(style: Self.Style) -> Self { .init() }
42 | }
43 |
44 | #if canImport(AppKit) && !targetEnvironment(macCatalyst)
45 | extension macOSViewVersion {
46 | public static let v10_15 = Self(for: .v10_15)
47 | public static let v11 = Self(for: .v11)
48 | public static let v12 = Self(for: .v12)
49 | public static let v13 = Self(for: .v13)
50 | public static let v14 = Self(for: .v14)
51 | }
52 | #endif
53 | #endif
54 | #endif
55 |
--------------------------------------------------------------------------------
/Pods/SwiftUIIntrospect/Sources/ViewTypes/DatePickerWithStepperFieldStyle.swift:
--------------------------------------------------------------------------------
1 | #if !os(watchOS)
2 | import SwiftUI
3 |
4 | /// An abstract representation of the `DatePicker` type in SwiftUI, with `.stepperField` style.
5 | ///
6 | /// ### iOS
7 | ///
8 | /// Not available.
9 | ///
10 | /// ### tvOS
11 | ///
12 | /// Not available.
13 | ///
14 | /// ### macOS
15 | ///
16 | /// ```swift
17 | /// struct ContentView: View {
18 | /// @State var date = Date()
19 | ///
20 | /// var body: some View {
21 | /// DatePicker("Pick a date", selection: $date)
22 | /// .datePickerStyle(.stepperField)
23 | /// .introspect(.datePicker(style: .stepperField), on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) {
24 | /// print(type(of: $0)) // NSDatePicker
25 | /// }
26 | /// }
27 | /// }
28 | /// ```
29 | ///
30 | /// ### visionOS
31 | ///
32 | /// Not available.
33 | public struct DatePickerWithStepperFieldStyleType: IntrospectableViewType {
34 | public enum Style {
35 | case stepperField
36 | }
37 | }
38 |
39 | #if !os(iOS) && !os(tvOS) && !os(visionOS)
40 | extension IntrospectableViewType where Self == DatePickerWithStepperFieldStyleType {
41 | public static func datePicker(style: Self.Style) -> Self { .init() }
42 | }
43 |
44 | #if canImport(AppKit) && !targetEnvironment(macCatalyst)
45 | extension macOSViewVersion {
46 | public static let v10_15 = Self(for: .v10_15)
47 | public static let v11 = Self(for: .v11)
48 | public static let v12 = Self(for: .v12)
49 | public static let v13 = Self(for: .v13)
50 | public static let v14 = Self(for: .v14)
51 | }
52 | #endif
53 | #endif
54 | #endif
55 |
--------------------------------------------------------------------------------
/Pods/SwiftUIIntrospect/Sources/ViewTypes/DatePickerWithWheelStyle.swift:
--------------------------------------------------------------------------------
1 | #if !os(watchOS)
2 | import SwiftUI
3 |
4 | /// An abstract representation of the `DatePicker` type in SwiftUI, with `.wheel` style.
5 | ///
6 | /// ### iOS
7 | ///
8 | /// ```swift
9 | /// struct ContentView: View {
10 | /// @State var date = Date()
11 | ///
12 | /// var body: some View {
13 | /// DatePicker("Pick a date", selection: $date)
14 | /// .datePickerStyle(.wheel)
15 | /// .introspect(.datePicker(style: .wheel), on: .iOS(.v13, .v14, .v15, .v16, .v17)) {
16 | /// print(type(of: $0)) // UIDatePicker
17 | /// }
18 | /// }
19 | /// }
20 | /// ```
21 | ///
22 | /// ### tvOS
23 | ///
24 | /// Not available.
25 | ///
26 | /// ### macOS
27 | ///
28 | /// Not available.
29 | ///
30 | /// ### visionOS
31 | ///
32 | /// ```swift
33 | /// struct ContentView: View {
34 | /// @State var date = Date()
35 | ///
36 | /// var body: some View {
37 | /// DatePicker("Pick a date", selection: $date)
38 | /// .datePickerStyle(.wheel)
39 | /// .introspect(.datePicker(style: .wheel), on: .visionOS(.v1)) {
40 | /// print(type(of: $0)) // UIDatePicker
41 | /// }
42 | /// }
43 | /// }
44 | /// ```
45 | public struct DatePickerWithWheelStyleType: IntrospectableViewType {
46 | public enum Style {
47 | case wheel
48 | }
49 | }
50 |
51 | #if !os(tvOS) && !os(macOS)
52 | extension IntrospectableViewType where Self == DatePickerWithWheelStyleType {
53 | public static func datePicker(style: Self.Style) -> Self { .init() }
54 | }
55 |
56 | #if canImport(UIKit)
57 | extension iOSViewVersion {
58 | public static let v13 = Self(for: .v13)
59 | public static let v14 = Self(for: .v14)
60 | public static let v15 = Self(for: .v15)
61 | public static let v16 = Self(for: .v16)
62 | public static let v17 = Self(for: .v17)
63 | }
64 |
65 | extension visionOSViewVersion {
66 | public static let v1 = Self(for: .v1)
67 | }
68 | #endif
69 | #endif
70 | #endif
71 |
--------------------------------------------------------------------------------
/Pods/SwiftUIIntrospect/Sources/ViewTypes/Form.swift:
--------------------------------------------------------------------------------
1 | #if !os(watchOS)
2 | import SwiftUI
3 |
4 | /// An abstract representation of the `Form` type in SwiftUI.
5 | ///
6 | /// ### iOS
7 | ///
8 | /// ```swift
9 | /// struct ContentView: View {
10 | /// var body: some View {
11 | /// Form {
12 | /// Text("Item 1")
13 | /// Text("Item 2")
14 | /// Text("Item 3")
15 | /// }
16 | /// .introspect(.form, on: .iOS(.v13, .v14, .v15)) {
17 | /// print(type(of: $0)) // UITableView
18 | /// }
19 | /// .introspect(.form, on: .iOS(.v16, .v17)) {
20 | /// print(type(of: $0)) // UICollectionView
21 | /// }
22 | /// }
23 | /// }
24 | /// ```
25 | ///
26 | /// ### tvOS
27 | ///
28 | /// ```swift
29 | /// struct ContentView: View {
30 | /// var body: some View {
31 | /// Form {
32 | /// Text("Item 1")
33 | /// Text("Item 2")
34 | /// Text("Item 3")
35 | /// }
36 | /// .introspect(.form, on: .tvOS(.v13, .v14, .v15, .v16, .v17)) {
37 | /// print(type(of: $0)) // UITableView
38 | /// }
39 | /// }
40 | /// }
41 | /// ```
42 | ///
43 | /// ### macOS
44 | ///
45 | /// Not available.
46 | ///
47 | /// ### visionOS
48 | ///
49 | /// ```swift
50 | /// struct ContentView: View {
51 | /// var body: some View {
52 | /// Form {
53 | /// Text("Item 1")
54 | /// Text("Item 2")
55 | /// Text("Item 3")
56 | /// }
57 | /// .introspect(.form, on: .visionOS(.v1)) {
58 | /// print(type(of: $0)) // UICollectionView
59 | /// }
60 | /// }
61 | /// }
62 | /// ```
63 | public struct FormType: IntrospectableViewType {}
64 |
65 | #if !os(macOS)
66 | extension IntrospectableViewType where Self == FormType {
67 | public static var form: Self { .init() }
68 | }
69 |
70 | #if canImport(UIKit)
71 | extension iOSViewVersion {
72 | public static let v13 = Self(for: .v13)
73 | public static let v14 = Self(for: .v14)
74 | public static let v15 = Self(for: .v15)
75 | }
76 |
77 | extension iOSViewVersion {
78 | public static let v16 = Self(for: .v16)
79 | public static let v17 = Self(for: .v17)
80 | }
81 |
82 | extension tvOSViewVersion {
83 | public static let v13 = Self(for: .v13)
84 | public static let v14 = Self(for: .v14)
85 | public static let v15 = Self(for: .v15)
86 | public static let v16 = Self(for: .v16)
87 | public static let v17 = Self(for: .v17)
88 | }
89 |
90 | extension visionOSViewVersion {
91 | public static let v1 = Self(for: .v1)
92 | }
93 | #endif
94 | #endif
95 | #endif
96 |
--------------------------------------------------------------------------------
/Pods/SwiftUIIntrospect/Sources/ViewTypes/ListWithBorderedStyle.swift:
--------------------------------------------------------------------------------
1 | #if !os(watchOS)
2 | import SwiftUI
3 |
4 | /// An abstract representation of the `List` type in SwiftUI, with `.bordered` style.
5 | ///
6 | /// ### iOS
7 | ///
8 | /// Not available.
9 | ///
10 | /// ### tvOS
11 | ///
12 | /// Not available.
13 | ///
14 | /// ### macOS
15 | ///
16 | /// ```swift
17 | /// struct ContentView: View {
18 | /// var body: some View {
19 | /// List {
20 | /// Text("Item 1")
21 | /// Text("Item 2")
22 | /// Text("Item 3")
23 | /// }
24 | /// .listStyle(.bordered)
25 | /// .introspect(.list(style: .bordered), on: .macOS(.v12, .v13, .v14)) {
26 | /// print(type(of: $0)) // NSTableView
27 | /// }
28 | /// }
29 | /// }
30 | /// ```
31 | ///
32 | /// ### visionOS
33 | ///
34 | /// Not available.
35 | public struct ListWithBorderedStyleType: IntrospectableViewType {
36 | public enum Style {
37 | case bordered
38 | }
39 | }
40 |
41 | #if !os(iOS) && !os(tvOS) && !os(visionOS)
42 | extension IntrospectableViewType where Self == ListWithBorderedStyleType {
43 | public static func list(style: Self.Style) -> Self { .init() }
44 | }
45 |
46 | #if canImport(AppKit) && !targetEnvironment(macCatalyst)
47 | extension macOSViewVersion {
48 | @available(*, unavailable, message: ".listStyle(.insetGrouped) isn't available on macOS 10.15")
49 | public static let v10_15 = Self.unavailable()
50 | @available(*, unavailable, message: ".listStyle(.insetGrouped) isn't available on macOS 11")
51 | public static let v11 = Self.unavailable()
52 | public static let v12 = Self(for: .v12)
53 | public static let v13 = Self(for: .v13)
54 | public static let v14 = Self(for: .v14)
55 | }
56 | #endif
57 | #endif
58 | #endif
59 |
--------------------------------------------------------------------------------
/Pods/SwiftUIIntrospect/Sources/ViewTypes/ListWithInsetGroupedStyle.swift:
--------------------------------------------------------------------------------
1 | #if !os(watchOS)
2 | import SwiftUI
3 |
4 | /// An abstract representation of the `List` type in SwiftUI, with `.insetGrouped` style.
5 | ///
6 | /// ### iOS
7 | ///
8 | /// ```swift
9 | /// struct ContentView: View {
10 | /// var body: some View {
11 | /// List {
12 | /// Text("Item 1")
13 | /// Text("Item 2")
14 | /// Text("Item 3")
15 | /// }
16 | /// .listStyle(.insetGrouped)
17 | /// .introspect(.list(style: .insetGrouped), on: .iOS(.v14, .v15)) {
18 | /// print(type(of: $0)) // UITableView
19 | /// }
20 | /// .introspect(.list(style: .insetGrouped), on: .iOS(.v16, .v17)) {
21 | /// print(type(of: $0)) // UICollectionView
22 | /// }
23 | /// }
24 | /// }
25 | /// ```
26 | ///
27 | /// ### tvOS
28 | ///
29 | /// Not available.
30 | ///
31 | /// ### macOS
32 | ///
33 | /// Not available.
34 | ///
35 | /// ### visionOS
36 | ///
37 | /// ```swift
38 | /// struct ContentView: View {
39 | /// var body: some View {
40 | /// List {
41 | /// Text("Item 1")
42 | /// Text("Item 2")
43 | /// Text("Item 3")
44 | /// }
45 | /// .listStyle(.insetGrouped)
46 | /// .introspect(.list(style: .insetGrouped), on: .visionOS(.v1)) {
47 | /// print(type(of: $0)) // UICollectionView
48 | /// }
49 | /// }
50 | /// }
51 | /// ```
52 | public struct ListWithInsetGroupedStyleType: IntrospectableViewType {
53 | public enum Style {
54 | case insetGrouped
55 | }
56 | }
57 |
58 | #if !os(tvOS) && !os(macOS)
59 | extension IntrospectableViewType where Self == ListWithInsetGroupedStyleType {
60 | public static func list(style: Self.Style) -> Self { .init() }
61 | }
62 |
63 | #if canImport(UIKit)
64 | extension iOSViewVersion {
65 | @available(*, unavailable, message: ".listStyle(.insetGrouped) isn't available on iOS 13")
66 | public static let v13 = Self(for: .v13)
67 | public static let v14 = Self(for: .v14)
68 | public static let v15 = Self(for: .v15)
69 | }
70 |
71 | extension iOSViewVersion {
72 | public static let v16 = Self(for: .v16)
73 | public static let v17 = Self(for: .v17)
74 | }
75 |
76 | extension visionOSViewVersion {
77 | public static let v1 = Self(for: .v1)
78 | }
79 | #endif
80 | #endif
81 | #endif
82 |
--------------------------------------------------------------------------------
/Pods/SwiftUIIntrospect/Sources/ViewTypes/PickerWithMenuStyle.swift:
--------------------------------------------------------------------------------
1 | #if !os(watchOS)
2 | import SwiftUI
3 |
4 | /// An abstract representation of the `Picker` type in SwiftUI, with `.menu` style.
5 | ///
6 | /// ### iOS
7 | ///
8 | /// Not available.
9 | ///
10 | /// ### tvOS
11 | ///
12 | /// Not available.
13 | ///
14 | /// ### macOS
15 | ///
16 | /// ```swift
17 | /// struct ContentView: View {
18 | /// @State var selection = "1"
19 | ///
20 | /// var body: some View {
21 | /// Picker("Pick a number", selection: $selection) {
22 | /// Text("1").tag("1")
23 | /// Text("2").tag("2")
24 | /// Text("3").tag("3")
25 | /// }
26 | /// .pickerStyle(.menu)
27 | /// .introspect(.picker(style: .menu), on: .macOS(.v11, .v12, .v13, .v14)) {
28 | /// print(type(of: $0)) // NSPopUpButton
29 | /// }
30 | /// }
31 | /// }
32 | /// ```
33 | ///
34 | /// ### visionOS
35 | ///
36 | /// Not available.
37 | public struct PickerWithMenuStyleType: IntrospectableViewType {
38 | public enum Style {
39 | case menu
40 | }
41 | }
42 |
43 | #if !os(iOS) && !os(tvOS) && !os(visionOS)
44 | extension IntrospectableViewType where Self == PickerWithMenuStyleType {
45 | public static func picker(style: Self.Style) -> Self { .init() }
46 | }
47 |
48 | #if canImport(AppKit) && !targetEnvironment(macCatalyst)
49 | extension macOSViewVersion {
50 | @available(*, unavailable, message: ".pickerStyle(.menu) isn't available on macOS 10.15")
51 | public static let v10_15 = Self.unavailable()
52 | public static let v11 = Self(for: .v11)
53 | public static let v12 = Self(for: .v12)
54 | public static let v13 = Self(for: .v13)
55 | public static let v14 = Self(for: .v14)
56 | }
57 | #endif
58 | #endif
59 | #endif
60 |
--------------------------------------------------------------------------------
/Pods/SwiftUIIntrospect/Sources/ViewTypes/PickerWithWheelStyle.swift:
--------------------------------------------------------------------------------
1 | #if !os(watchOS)
2 | import SwiftUI
3 |
4 | /// An abstract representation of the `Picker` type in SwiftUI, with `.wheel` style.
5 | ///
6 | /// ### iOS
7 | ///
8 | /// ```swift
9 | /// struct ContentView: View {
10 | /// @State var selection = "1"
11 | ///
12 | /// var body: some View {
13 | /// Picker("Pick a number", selection: $selection) {
14 | /// Text("1").tag("1")
15 | /// Text("2").tag("2")
16 | /// Text("3").tag("3")
17 | /// }
18 | /// .pickerStyle(.wheel)
19 | /// .introspect(.picker(style: .wheel), on: .iOS(.v13, .v14, .v15, .v16, .v17)) {
20 | /// print(type(of: $0)) // UIPickerView
21 | /// }
22 | /// }
23 | /// }
24 | /// ```
25 | ///
26 | /// ### tvOS
27 | ///
28 | /// Not available.
29 | ///
30 | /// ### macOS
31 | ///
32 | /// Not available.
33 | ///
34 | /// ### visionOS
35 | ///
36 | /// ```swift
37 | /// struct ContentView: View {
38 | /// @State var selection = "1"
39 | ///
40 | /// var body: some View {
41 | /// Picker("Pick a number", selection: $selection) {
42 | /// Text("1").tag("1")
43 | /// Text("2").tag("2")
44 | /// Text("3").tag("3")
45 | /// }
46 | /// .pickerStyle(.wheel)
47 | /// .introspect(.picker(style: .wheel), on: .visionOS(.v1)) {
48 | /// print(type(of: $0)) // UIPickerView
49 | /// }
50 | /// }
51 | /// }
52 | /// ```
53 | public struct PickerWithWheelStyleType: IntrospectableViewType {
54 | public enum Style {
55 | case wheel
56 | }
57 | }
58 |
59 | #if !os(tvOS) && !os(macOS)
60 | extension IntrospectableViewType where Self == PickerWithWheelStyleType {
61 | public static func picker(style: Self.Style) -> Self { .init() }
62 | }
63 |
64 | #if canImport(UIKit)
65 | extension iOSViewVersion {
66 | public static let v13 = Self(for: .v13)
67 | public static let v14 = Self(for: .v14)
68 | public static let v15 = Self(for: .v15)
69 | public static let v16 = Self(for: .v16)
70 | public static let v17 = Self(for: .v17)
71 | }
72 |
73 | extension visionOSViewVersion {
74 | public static let v1 = Self(for: .v1)
75 | }
76 | #endif
77 | #endif
78 | #endif
79 |
--------------------------------------------------------------------------------
/Pods/SwiftUIIntrospect/Sources/ViewTypes/Popover.swift:
--------------------------------------------------------------------------------
1 | #if !os(watchOS)
2 | import SwiftUI
3 |
4 | /// An abstract representation of `.popover` in SwiftUI.
5 | ///
6 | /// ### iOS
7 | ///
8 | /// ```swift
9 | /// struct ContentView: View {
10 | /// @State var isPresented = false
11 | ///
12 | /// var body: some View {
13 | /// Button("Present", action: { isPresented = true })
14 | /// .popover(isPresented: $isPresented) {
15 | /// Button("Dismiss", action: { isPresented = false })
16 | /// .introspect(.popover, on: .iOS(.v13, .v14, .v15, .v16, .v17)) {
17 | /// print(type(of: $0)) // UIPopoverPresentationController
18 | /// }
19 | /// }
20 | /// }
21 | /// }
22 | /// ```
23 | ///
24 | /// ### tvOS
25 | ///
26 | /// Not available.
27 | ///
28 | /// ### macOS
29 | ///
30 | /// Not available.
31 | ///
32 | /// ### visionOS
33 | ///
34 | /// ```swift
35 | /// struct ContentView: View {
36 | /// @State var isPresented = false
37 | ///
38 | /// var body: some View {
39 | /// Button("Present", action: { isPresented = true })
40 | /// .popover(isPresented: $isPresented) {
41 | /// Button("Dismiss", action: { isPresented = false })
42 | /// .introspect(.popover, on: .visionOS(.v1)) {
43 | /// print(type(of: $0)) // UIPopoverPresentationController
44 | /// }
45 | /// }
46 | /// }
47 | /// }
48 | /// ```
49 | public struct PopoverType: IntrospectableViewType {
50 | public var scope: IntrospectionScope { .ancestor }
51 | }
52 |
53 | #if !os(tvOS) && !os(macOS)
54 | extension IntrospectableViewType where Self == PopoverType {
55 | public static var popover: Self { .init() }
56 | }
57 |
58 | #if canImport(UIKit)
59 | extension iOSViewVersion {
60 | public static let v13 = Self(for: .v13, selector: selector)
61 | public static let v14 = Self(for: .v14, selector: selector)
62 | public static let v15 = Self(for: .v15, selector: selector)
63 | public static let v16 = Self(for: .v16, selector: selector)
64 | public static let v17 = Self(for: .v17, selector: selector)
65 |
66 | private static var selector: IntrospectionSelector {
67 | .from(UIViewController.self, selector: \.popoverPresentationController)
68 | }
69 | }
70 |
71 | extension visionOSViewVersion {
72 | public static let v1 = Self(for: .v1, selector: selector)
73 |
74 | private static var selector: IntrospectionSelector {
75 | .from(UIViewController.self, selector: \.popoverPresentationController)
76 | }
77 | }
78 | #endif
79 | #endif
80 | #endif
81 |
--------------------------------------------------------------------------------
/Pods/SwiftUIIntrospect/Sources/ViewTypes/Slider.swift:
--------------------------------------------------------------------------------
1 | #if !os(watchOS)
2 | import SwiftUI
3 |
4 | /// An abstract representation of the `Slider` type in SwiftUI.
5 | ///
6 | /// ### iOS
7 | ///
8 | /// ```swift
9 | /// struct ContentView: View {
10 | /// @State var selection = 0.5
11 | ///
12 | /// var body: some View {
13 | /// Slider(value: $selection, in: 0...1)
14 | /// .introspect(.slider, on: .iOS(.v13, .v14, .v15, .v16, .v17)) {
15 | /// print(type(of: $0)) // UISlider
16 | /// }
17 | /// }
18 | /// }
19 | /// ```
20 | ///
21 | /// ### tvOS
22 | ///
23 | /// Not available.
24 | ///
25 | /// ### macOS
26 | ///
27 | /// ```swift
28 | /// struct ContentView: View {
29 | /// @State var selection = 0.5
30 | ///
31 | /// var body: some View {
32 | /// Slider(value: $selection, in: 0...1)
33 | /// .introspect(.slider, on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) {
34 | /// print(type(of: $0)) // NSSlider
35 | /// }
36 | /// }
37 | /// }
38 | /// ```
39 | ///
40 | /// ### visionOS
41 | ///
42 | /// Not available.
43 | public struct SliderType: IntrospectableViewType {}
44 |
45 | #if !os(tvOS) && !os(visionOS)
46 | extension IntrospectableViewType where Self == SliderType {
47 | public static var slider: Self { .init() }
48 | }
49 |
50 | #if canImport(UIKit)
51 | extension iOSViewVersion {
52 | public static let v13 = Self(for: .v13)
53 | public static let v14 = Self(for: .v14)
54 | public static let v15 = Self(for: .v15)
55 | public static let v16 = Self(for: .v16)
56 | public static let v17 = Self(for: .v17)
57 | }
58 | #elseif canImport(AppKit)
59 | extension macOSViewVersion {
60 | public static let v10_15 = Self(for: .v10_15)
61 | public static let v11 = Self(for: .v11)
62 | public static let v12 = Self(for: .v12)
63 | public static let v13 = Self(for: .v13)
64 | public static let v14 = Self(for: .v14)
65 | }
66 | #endif
67 | #endif
68 | #endif
69 |
--------------------------------------------------------------------------------
/Pods/SwiftUIIntrospect/Sources/ViewTypes/Stepper.swift:
--------------------------------------------------------------------------------
1 | #if !os(watchOS)
2 | import SwiftUI
3 |
4 | /// An abstract representation of the `Stepper` type in SwiftUI.
5 | ///
6 | /// ### iOS
7 | ///
8 | /// ```swift
9 | /// struct ContentView: View {
10 | /// @State var selection = 5
11 | ///
12 | /// var body: some View {
13 | /// Stepper("Select a number", value: $selection, in: 0...10)
14 | /// .introspect(.stepper, on: .iOS(.v13, .v14, .v15, .v16, .v17)) {
15 | /// print(type(of: $0)) // UIStepper
16 | /// }
17 | /// }
18 | /// }
19 | /// ```
20 | ///
21 | /// ### tvOS
22 | ///
23 | /// Not available.
24 | ///
25 | /// ### macOS
26 | ///
27 | /// ```swift
28 | /// struct ContentView: View {
29 | /// @State var selection = 5
30 | ///
31 | /// var body: some View {
32 | /// Stepper("Select a number", value: $selection, in: 0...10)
33 | /// .introspect(.stepper, on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) {
34 | /// print(type(of: $0)) // NSStepper
35 | /// }
36 | /// }
37 | /// }
38 | /// ```
39 | ///
40 | /// ### visionOS
41 | ///
42 | /// Not available.
43 | public struct StepperType: IntrospectableViewType {}
44 |
45 | #if !os(tvOS) && !os(visionOS)
46 | extension IntrospectableViewType where Self == StepperType {
47 | public static var stepper: Self { .init() }
48 | }
49 |
50 | #if canImport(UIKit)
51 | extension iOSViewVersion {
52 | public static let v13 = Self(for: .v13)
53 | public static let v14 = Self(for: .v14)
54 | public static let v15 = Self(for: .v15)
55 | public static let v16 = Self(for: .v16)
56 | public static let v17 = Self(for: .v17)
57 | }
58 | #elseif canImport(AppKit)
59 | extension macOSViewVersion {
60 | public static let v10_15 = Self(for: .v10_15)
61 | public static let v11 = Self(for: .v11)
62 | public static let v12 = Self(for: .v12)
63 | public static let v13 = Self(for: .v13)
64 | public static let v14 = Self(for: .v14)
65 | }
66 | #endif
67 | #endif
68 | #endif
69 |
--------------------------------------------------------------------------------
/Pods/SwiftUIIntrospect/Sources/ViewTypes/TextEditor.swift:
--------------------------------------------------------------------------------
1 | #if !os(watchOS)
2 | import SwiftUI
3 |
4 | /// An abstract representation of the `TextEditor` type in SwiftUI.
5 | ///
6 | /// ### iOS
7 | ///
8 | /// ```swift
9 | /// struct ContentView: View {
10 | /// @State var text = "Lorem ipsum"
11 | ///
12 | /// var body: some View {
13 | /// TextEditor(text: $text)
14 | /// .introspect(.textEditor, on: .iOS(.v14, .v15, .v16, .v17)) {
15 | /// print(type(of: $0)) // UITextView
16 | /// }
17 | /// }
18 | /// }
19 | /// ```
20 | ///
21 | /// ### tvOS
22 | ///
23 | /// Not available.
24 | ///
25 | /// ### macOS
26 | ///
27 | /// ```swift
28 | /// struct ContentView: View {
29 | /// @State var text = "Lorem ipsum"
30 | ///
31 | /// var body: some View {
32 | /// TextEditor(text: $text)
33 | /// .introspect(.textEditor, on: .macOS(.v11, .v12, .v13, .v14)) {
34 | /// print(type(of: $0)) // NSTextView
35 | /// }
36 | /// }
37 | /// }
38 | /// ```
39 | ///
40 | /// ### visionOS
41 | ///
42 | /// ```swift
43 | /// struct ContentView: View {
44 | /// @State var text = "Lorem ipsum"
45 | ///
46 | /// var body: some View {
47 | /// TextEditor(text: $text)
48 | /// .introspect(.textEditor, on: .visionOS(.v1)) {
49 | /// print(type(of: $0)) // UITextView
50 | /// }
51 | /// }
52 | /// }
53 | /// ```
54 | public struct TextEditorType: IntrospectableViewType {}
55 |
56 | #if !os(tvOS)
57 | extension IntrospectableViewType where Self == TextEditorType {
58 | public static var textEditor: Self { .init() }
59 | }
60 |
61 | #if canImport(UIKit)
62 | extension iOSViewVersion {
63 | @available(*, unavailable, message: "TextEditor isn't available on iOS 13")
64 | public static let v13 = Self.unavailable()
65 | public static let v14 = Self(for: .v14)
66 | public static let v15 = Self(for: .v15)
67 | public static let v16 = Self(for: .v16)
68 | public static let v17 = Self(for: .v17)
69 | }
70 |
71 | extension visionOSViewVersion {
72 | public static let v1 = Self(for: .v1)
73 | }
74 | #elseif canImport(AppKit)
75 | extension macOSViewVersion {
76 | @available(*, unavailable, message: "TextEditor isn't available on macOS 10.15")
77 | public static let v10_15 = Self.unavailable()
78 | public static let v11 = Self(for: .v11)
79 | public static let v12 = Self(for: .v12)
80 | public static let v13 = Self(for: .v13)
81 | public static let v14 = Self(for: .v14)
82 | }
83 | #endif
84 | #endif
85 | #endif
86 |
--------------------------------------------------------------------------------
/Pods/SwiftUIIntrospect/Sources/ViewTypes/Toggle.swift:
--------------------------------------------------------------------------------
1 | #if !os(watchOS)
2 | import SwiftUI
3 |
4 | /// An abstract representation of the `Toggle` type in SwiftUI.
5 | ///
6 | /// ### iOS
7 | ///
8 | /// ```swift
9 | /// struct ContentView: View {
10 | /// @State var isOn = false
11 | ///
12 | /// var body: some View {
13 | /// Toggle("Toggle", isOn: $isOn)
14 | /// .introspect(.toggle, on: .iOS(.v13, .v14, .v15, .v16, .v17)) {
15 | /// print(type(of: $0)) // UISwitch
16 | /// }
17 | /// }
18 | /// }
19 | /// ```
20 | ///
21 | /// ### tvOS
22 | ///
23 | /// Not available.
24 | ///
25 | /// ### macOS
26 | ///
27 | /// ```swift
28 | /// struct ContentView: View {
29 | /// @State var isOn = false
30 | ///
31 | /// var body: some View {
32 | /// Toggle("Toggle", isOn: $isOn)
33 | /// .introspect(.toggle, on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) {
34 | /// print(type(of: $0)) // NSButton
35 | /// }
36 | /// }
37 | /// }
38 | /// ```
39 | ///
40 | /// ### visionOS
41 | ///
42 | /// Not available.
43 | public struct ToggleType: IntrospectableViewType {}
44 |
45 | #if !os(tvOS) && !os(visionOS)
46 | extension IntrospectableViewType where Self == ToggleType {
47 | public static var toggle: Self { .init() }
48 | }
49 |
50 | #if canImport(UIKit)
51 | extension iOSViewVersion {
52 | public static let v13 = Self(for: .v13)
53 | public static let v14 = Self(for: .v14)
54 | public static let v15 = Self(for: .v15)
55 | public static let v16 = Self(for: .v16)
56 | public static let v17 = Self(for: .v17)
57 | }
58 | #elseif canImport(AppKit)
59 | extension macOSViewVersion {
60 | public static let v10_15 = Self(for: .v10_15)
61 | public static let v11 = Self(for: .v11)
62 | public static let v12 = Self(for: .v12)
63 | public static let v13 = Self(for: .v13)
64 | public static let v14 = Self(for: .v14)
65 | }
66 | #endif
67 | #endif
68 | #endif
69 |
--------------------------------------------------------------------------------
/Pods/SwiftUIIntrospect/Sources/ViewTypes/ToggleWithButtonStyle.swift:
--------------------------------------------------------------------------------
1 | #if !os(watchOS)
2 | import SwiftUI
3 |
4 | /// An abstract representation of the `Toggle` type in SwiftUI, with `.button` style.
5 | ///
6 | /// ### iOS
7 | ///
8 | /// Not available.
9 | ///
10 | /// ### tvOS
11 | ///
12 | /// Not available.
13 | ///
14 | /// ### macOS
15 | ///
16 | /// ```swift
17 | /// struct ContentView: View {
18 | /// @State var isOn = false
19 | ///
20 | /// var body: some View {
21 | /// Toggle("Toggle", isOn: $isOn)
22 | /// .toggleStyle(.button)
23 | /// .introspect(.toggle(style: .button), on: .macOS(.v12, .v13, .v14)) {
24 | /// print(type(of: $0)) // NSButton
25 | /// }
26 | /// }
27 | /// }
28 | /// ```
29 | ///
30 | /// ### visionOS
31 | ///
32 | /// Not available.
33 | public struct ToggleWithButtonStyleType: IntrospectableViewType {
34 | public enum Style {
35 | case button
36 | }
37 | }
38 |
39 | #if !os(iOS) && !os(tvOS) && !os(visionOS)
40 | extension IntrospectableViewType where Self == ToggleWithButtonStyleType {
41 | public static func toggle(style: Self.Style) -> Self { .init() }
42 | }
43 |
44 | #if canImport(AppKit) && !targetEnvironment(macCatalyst)
45 | extension macOSViewVersion {
46 | @available(*, unavailable, message: ".toggleStyle(.button) isn't available on macOS 10.15")
47 | public static let v10_15 = Self.unavailable()
48 | @available(*, unavailable, message: ".toggleStyle(.button) isn't available on macOS 11")
49 | public static let v11 = Self.unavailable()
50 | public static let v12 = Self(for: .v12)
51 | public static let v13 = Self(for: .v13)
52 | public static let v14 = Self(for: .v14)
53 | }
54 | #endif
55 | #endif
56 | #endif
57 |
--------------------------------------------------------------------------------
/Pods/SwiftUIIntrospect/Sources/ViewTypes/ToggleWithCheckboxStyle.swift:
--------------------------------------------------------------------------------
1 | #if !os(watchOS)
2 | import SwiftUI
3 |
4 | /// An abstract representation of the `Toggle` type in SwiftUI, with `.checkbox` style.
5 | ///
6 | /// ### iOS
7 | ///
8 | /// Not available.
9 | ///
10 | /// ### tvOS
11 | ///
12 | /// Not available.
13 | ///
14 | /// ### macOS
15 | ///
16 | /// ```swift
17 | /// struct ContentView: View {
18 | /// @State var isOn = false
19 | ///
20 | /// var body: some View {
21 | /// Toggle("Checkbox", isOn: $isOn)
22 | /// .toggleStyle(.checkbox)
23 | /// .introspect(.toggle(style: .checkbox), on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) {
24 | /// print(type(of: $0)) // NSButton
25 | /// }
26 | /// }
27 | /// }
28 | /// ```
29 | ///
30 | /// ### visionOS
31 | ///
32 | /// Not available.
33 | public struct ToggleWithCheckboxStyleType: IntrospectableViewType {
34 | public enum Style {
35 | case checkbox
36 | }
37 | }
38 |
39 | #if !os(iOS) && !os(tvOS) && !os(visionOS)
40 | extension IntrospectableViewType where Self == ToggleWithCheckboxStyleType {
41 | public static func toggle(style: Self.Style) -> Self { .init() }
42 | }
43 |
44 | #if canImport(AppKit) && !targetEnvironment(macCatalyst)
45 | extension macOSViewVersion {
46 | public static let v10_15 = Self(for: .v10_15)
47 | public static let v11 = Self(for: .v11)
48 | public static let v12 = Self(for: .v12)
49 | public static let v13 = Self(for: .v13)
50 | public static let v14 = Self(for: .v14)
51 | }
52 | #endif
53 | #endif
54 | #endif
55 |
--------------------------------------------------------------------------------
/Pods/SwiftUIIntrospect/Sources/ViewTypes/ToggleWithSwitchStyle.swift:
--------------------------------------------------------------------------------
1 | #if !os(watchOS)
2 | import SwiftUI
3 |
4 | /// An abstract representation of the `Toggle` type in SwiftUI, with `.switch` style.
5 | ///
6 | /// ### iOS
7 | ///
8 | /// ```swift
9 | /// struct ContentView: View {
10 | /// @State var isOn = false
11 | ///
12 | /// var body: some View {
13 | /// Toggle("Switch", isOn: $isOn)
14 | /// .toggleStyle(.switch)
15 | /// .introspect(.toggle(style: .switch), on: .iOS(.v13, .v14, .v15, .v16, .v17)) {
16 | /// print(type(of: $0)) // UISwitch
17 | /// }
18 | /// }
19 | /// }
20 | /// ```
21 | ///
22 | /// ### tvOS
23 | ///
24 | /// Not available.
25 | ///
26 | /// ### macOS
27 | ///
28 | /// ```swift
29 | /// struct ContentView: View {
30 | /// @State var isOn = false
31 | ///
32 | /// var body: some View {
33 | /// Toggle("Switch", isOn: $isOn)
34 | /// .toggleStyle(.switch)
35 | /// .introspect(.toggle(style: .switch), on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) {
36 | /// print(type(of: $0)) // NSSwitch
37 | /// }
38 | /// }
39 | /// }
40 | /// ```
41 | ///
42 | /// ### visionOS
43 | ///
44 | /// Not available.
45 | public struct ToggleWithSwitchStyleType: IntrospectableViewType {
46 | public enum Style {
47 | case `switch`
48 | }
49 | }
50 |
51 | #if !os(tvOS) && !os(visionOS)
52 | extension IntrospectableViewType where Self == ToggleWithSwitchStyleType {
53 | public static func toggle(style: Self.Style) -> Self { .init() }
54 | }
55 |
56 | #if canImport(UIKit)
57 | extension iOSViewVersion {
58 | public static let v13 = Self(for: .v13)
59 | public static let v14 = Self(for: .v14)
60 | public static let v15 = Self(for: .v15)
61 | public static let v16 = Self(for: .v16)
62 | public static let v17 = Self(for: .v17)
63 | }
64 | #elseif canImport(AppKit)
65 | extension macOSViewVersion {
66 | public static let v10_15 = Self(for: .v10_15)
67 | public static let v11 = Self(for: .v11)
68 | public static let v12 = Self(for: .v12)
69 | public static let v13 = Self(for: .v13)
70 | public static let v14 = Self(for: .v14)
71 | }
72 | #endif
73 | #endif
74 | #endif
75 |
--------------------------------------------------------------------------------
/Pods/SwiftUIIntrospect/Sources/Weak.swift:
--------------------------------------------------------------------------------
1 | @_spi(Advanced)
2 | @propertyWrapper
3 | public final class Weak {
4 | private weak var _wrappedValue: T?
5 |
6 | public var wrappedValue: T? {
7 | get { _wrappedValue }
8 | set { _wrappedValue = newValue }
9 | }
10 |
11 | public init(wrappedValue: T? = nil) {
12 | self._wrappedValue = wrappedValue
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Alamofire/Alamofire-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | ${PODS_DEVELOPMENT_LANGUAGE}
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 5.8.1
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Alamofire/Alamofire-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Alamofire : NSObject
3 | @end
4 | @implementation PodsDummy_Alamofire
5 | @end
6 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Alamofire/Alamofire-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Alamofire/Alamofire-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double AlamofireVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char AlamofireVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Alamofire/Alamofire.debug.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | CODE_SIGN_IDENTITY =
3 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Alamofire
4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
5 | LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
6 | OTHER_LDFLAGS = $(inherited) -framework "CFNetwork"
7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
8 | PODS_BUILD_DIR = ${BUILD_DIR}
9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
10 | PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE}
11 | PODS_ROOT = ${SRCROOT}
12 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/Alamofire
13 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
14 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
15 | SKIP_INSTALL = YES
16 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
17 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Alamofire/Alamofire.modulemap:
--------------------------------------------------------------------------------
1 | framework module Alamofire {
2 | umbrella header "Alamofire-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Alamofire/Alamofire.release.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | CODE_SIGN_IDENTITY =
3 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Alamofire
4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
5 | LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
6 | OTHER_LDFLAGS = $(inherited) -framework "CFNetwork"
7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
8 | PODS_BUILD_DIR = ${BUILD_DIR}
9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
10 | PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE}
11 | PODS_ROOT = ${SRCROOT}
12 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/Alamofire
13 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
14 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
15 | SKIP_INSTALL = YES
16 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
17 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-ollamaGUI/Pods-ollamaGUI-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | ${PODS_DEVELOPMENT_LANGUAGE}
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-ollamaGUI/Pods-ollamaGUI-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_ollamaGUI : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_ollamaGUI
5 | @end
6 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-ollamaGUI/Pods-ollamaGUI-frameworks-Debug-input-files.xcfilelist:
--------------------------------------------------------------------------------
1 | ${PODS_ROOT}/Target Support Files/Pods-ollamaGUI/Pods-ollamaGUI-frameworks.sh
2 | ${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework
3 | ${BUILT_PRODUCTS_DIR}/SwiftSoup/SwiftSoup.framework
4 | ${BUILT_PRODUCTS_DIR}/SwiftUIIntrospect/SwiftUIIntrospect.framework
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-ollamaGUI/Pods-ollamaGUI-frameworks-Debug-output-files.xcfilelist:
--------------------------------------------------------------------------------
1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework
2 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftSoup.framework
3 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftUIIntrospect.framework
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-ollamaGUI/Pods-ollamaGUI-frameworks-Release-input-files.xcfilelist:
--------------------------------------------------------------------------------
1 | ${PODS_ROOT}/Target Support Files/Pods-ollamaGUI/Pods-ollamaGUI-frameworks.sh
2 | ${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework
3 | ${BUILT_PRODUCTS_DIR}/SwiftSoup/SwiftSoup.framework
4 | ${BUILT_PRODUCTS_DIR}/SwiftUIIntrospect/SwiftUIIntrospect.framework
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-ollamaGUI/Pods-ollamaGUI-frameworks-Release-output-files.xcfilelist:
--------------------------------------------------------------------------------
1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework
2 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftSoup.framework
3 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftUIIntrospect.framework
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-ollamaGUI/Pods-ollamaGUI-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double Pods_ollamaGUIVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char Pods_ollamaGUIVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-ollamaGUI/Pods-ollamaGUI.debug.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftSoup" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftUIIntrospect"
4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftSoup/SwiftSoup.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftUIIntrospect/SwiftUIIntrospect.framework/Headers"
6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/../Frameworks' '@loader_path/Frameworks' "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
7 | LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
8 | OTHER_LDFLAGS = $(inherited) -framework "Alamofire" -framework "CFNetwork" -framework "SwiftSoup" -framework "SwiftUIIntrospect"
9 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
10 | PODS_BUILD_DIR = ${BUILD_DIR}
11 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
12 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
13 | PODS_ROOT = ${SRCROOT}/Pods
14 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
15 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
16 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-ollamaGUI/Pods-ollamaGUI.modulemap:
--------------------------------------------------------------------------------
1 | framework module Pods_ollamaGUI {
2 | umbrella header "Pods-ollamaGUI-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-ollamaGUI/Pods-ollamaGUI.release.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftSoup" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftUIIntrospect"
4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftSoup/SwiftSoup.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftUIIntrospect/SwiftUIIntrospect.framework/Headers"
6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/../Frameworks' '@loader_path/Frameworks' "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
7 | LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
8 | OTHER_LDFLAGS = $(inherited) -framework "Alamofire" -framework "CFNetwork" -framework "SwiftSoup" -framework "SwiftUIIntrospect"
9 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
10 | PODS_BUILD_DIR = ${BUILD_DIR}
11 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
12 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
13 | PODS_ROOT = ${SRCROOT}/Pods
14 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
15 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
16 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/SwiftUIIntrospect/SwiftUIIntrospect-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | ${PODS_DEVELOPMENT_LANGUAGE}
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.1.1
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/SwiftUIIntrospect/SwiftUIIntrospect-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_SwiftUIIntrospect : NSObject
3 | @end
4 | @implementation PodsDummy_SwiftUIIntrospect
5 | @end
6 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/SwiftUIIntrospect/SwiftUIIntrospect-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/SwiftUIIntrospect/SwiftUIIntrospect-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double SwiftUIIntrospectVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char SwiftUIIntrospectVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/SwiftUIIntrospect/SwiftUIIntrospect.debug.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | CODE_SIGN_IDENTITY =
3 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SwiftUIIntrospect
4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
5 | LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
6 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
7 | PODS_BUILD_DIR = ${BUILD_DIR}
8 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
9 | PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE}
10 | PODS_ROOT = ${SRCROOT}
11 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/SwiftUIIntrospect
12 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
13 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
14 | SKIP_INSTALL = YES
15 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
16 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/SwiftUIIntrospect/SwiftUIIntrospect.modulemap:
--------------------------------------------------------------------------------
1 | framework module SwiftUIIntrospect {
2 | umbrella header "SwiftUIIntrospect-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/SwiftUIIntrospect/SwiftUIIntrospect.release.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | CODE_SIGN_IDENTITY =
3 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SwiftUIIntrospect
4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
5 | LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
6 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
7 | PODS_BUILD_DIR = ${BUILD_DIR}
8 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
9 | PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE}
10 | PODS_ROOT = ${SRCROOT}
11 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/SwiftUIIntrospect
12 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
13 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
14 | SKIP_INSTALL = YES
15 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OllamaGUI by SwiftUI
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | https://github.com/enoch1118/ollamaGUI/assets/54224095/d056434a-f27e-41a9-940b-be7053f6920c
10 |
11 | ### Now can test langchain in ollama GUI
12 |
13 |
14 |
15 |
16 | This feature is completely native and does not require an API key.
17 | It's a bit slow so far, but it does provide per-website storage, so once created, website embeds can be reused.
18 | Since it's still in preview, you can't use it except for the window of the feature.
19 |
20 |
21 |
22 | ### Introduction to Ollamagui
23 | ollama is a lightweight, extensible framework that lets you run powerful LLMs like Llama 2, Code Llama, and others on your own computer. This means you don't need to rely on cloud-based services or have specific hardware requirements.
24 |
25 | OllamaGUI: A user interface (GUI) application built for macOS using SwiftUI framework, help you to use ollama model easily
26 |
27 | ### Installation
28 |
29 | ##### Requirements
30 | * need llama2 model https://ai.meta.com/llama/
31 | * ensure ollama server is running https://ollama.ai/
32 |
33 | ##### Clone the GitHub repository:
34 | > ```bash
35 | >git clone https://github.com/enoch1118/ollamaGUI.git
36 | >```
37 |
38 | ##### Open the project in Xcode:
39 | Open Xcode.
40 | Go to "File" -> "Open".
41 | Locate the ollamagui.xcworkspace file within the cloned repository and open it.
42 |
43 | ##### Install dependencies:
44 |
45 | If you haven't already, install CocoaPods Open your terminal and run
46 | ```
47 | sudo gem install cocoapods.
48 | ```
49 | In the terminal, navigate to the root of the OllamaGui project directory
50 | ```
51 | pod install
52 | ```
53 | to install required dependencies.
54 |
55 |
56 | ### Dependencies
57 |
58 | 1. swift-markdown-ui
59 | https://github.com/gonzalezreal/swift-markdown-ui
60 | 2. SwiftUIIntrospect
61 | https://github.com/siteline/swiftui-introspect
62 | 3. Alamofire
63 | https://github.com/Alamofire/Alamofire
64 |
65 |
66 | --- langchain
67 |
68 | 4. USearch
69 | https://github.com/unum-cloud/usearch
--------------------------------------------------------------------------------
/image/1.1v.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enoch1118/ollamaGUI/b094a09cff130c60e9c14bf1dcbf0bff1e4020ca/image/1.1v.png
--------------------------------------------------------------------------------
/image/gif.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enoch1118/ollamaGUI/b094a09cff130c60e9c14bf1dcbf0bff1e4020ca/image/gif.gif
--------------------------------------------------------------------------------
/image/langchain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enoch1118/ollamaGUI/b094a09cff130c60e9c14bf1dcbf0bff1e4020ca/image/langchain.png
--------------------------------------------------------------------------------
/image/png.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enoch1118/ollamaGUI/b094a09cff130c60e9c14bf1dcbf0bff1e4020ca/image/png.png
--------------------------------------------------------------------------------
/image/png2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enoch1118/ollamaGUI/b094a09cff130c60e9c14bf1dcbf0bff1e4020ca/image/png2.png
--------------------------------------------------------------------------------
/image/png3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enoch1118/ollamaGUI/b094a09cff130c60e9c14bf1dcbf0bff1e4020ca/image/png3.png
--------------------------------------------------------------------------------
/ollamaGUI.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ollamaGUI.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ollamaGUI.xcodeproj/xcuserdata/baesanghwi.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | ollamaGUI.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 3
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | AC842E342B4D16F700F9EC3F
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ollamaGUI.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ollamaGUI.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ollamaGUI.xcworkspace/xcshareddata/swiftpm/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "originHash" : "02f0af96540e313ebd0891a4fdfdda56927deee2522081f4e6b08a023c69747a",
3 | "pins" : [
4 | {
5 | "identity" : "networkimage",
6 | "kind" : "remoteSourceControl",
7 | "location" : "https://github.com/gonzalezreal/NetworkImage",
8 | "state" : {
9 | "revision" : "7aff8d1b31148d32c5933d75557d42f6323ee3d1",
10 | "version" : "6.0.0"
11 | }
12 | },
13 | {
14 | "identity" : "swift-markdown-ui",
15 | "kind" : "remoteSourceControl",
16 | "location" : "https://github.com/gonzalezreal/swift-markdown-ui",
17 | "state" : {
18 | "revision" : "ae799d015a5374708f7b4c85f3294c05f2a564e2",
19 | "version" : "2.3.0"
20 | }
21 | },
22 | {
23 | "identity" : "usearch",
24 | "kind" : "remoteSourceControl",
25 | "location" : "https://github.com/unum-cloud/usearch.git",
26 | "state" : {
27 | "revision" : "f79d8180122c717203b74f7a7473964c413cb5c1",
28 | "version" : "2.9.2"
29 | }
30 | }
31 | ],
32 | "version" : 3
33 | }
34 |
--------------------------------------------------------------------------------
/ollamaGUI/V2/Core/Error/MuseError.swift:
--------------------------------------------------------------------------------
1 | //
2 | // File.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 3/12/24.
6 | //
7 |
8 | import Foundation
9 |
10 | enum MuseError: Error {
11 | case getDocumentError(url: String)
12 | }
13 |
14 | extension MuseError {
15 | var localizedDescription: String {
16 | switch self {
17 | case let .getDocumentError(url):
18 | return "get document from \(url) failed"
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ollamaGUI/V2/Core/Protocol/BaseBloc.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BaseBLoc.swift
3 | // ollamaGUI
4 | //
5 | // Created by 배상휘 on 3/12/24.
6 | //
7 |
8 | import Combine
9 | import Foundation
10 |
11 | /// is Event is State
12 | class BaseBloc where S: BaseState {
13 | var eventListener: PassthroughSubject
14 | var stateSubject: CurrentValueSubject
15 | var cancel: Set
16 |
17 | init() {
18 | stateSubject = .init(.initState)
19 | eventListener = .init()
20 | cancel = Set()
21 | }
22 |
23 | func _ignite() {
24 | eventListener.sink(receiveValue: _registerEvent)
25 | .store(in: &cancel)
26 | }
27 |
28 | func _registerEvent(event: E) {
29 | if showLog {
30 | print(String(describing: event))
31 | }
32 | }
33 |
34 | func addEvent(event: E) {
35 | eventListener.send(event)
36 | }
37 |
38 | func emit(state: S) {
39 | stateSubject.send(state)
40 | }
41 |
42 | var showLog: Bool {
43 | true
44 | }
45 | }
46 |
47 | protocol BaseState {
48 | static var initState: Self { get }
49 | }
50 |
--------------------------------------------------------------------------------