Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds support for on-device LLMs with SpeziLLMLocal #39

Merged
merged 14 commits into from
May 13, 2024
2 changes: 2 additions & 0 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ jobs:
uses: StanfordBDHG/.github/.github/workflows/create-and-upload-coverage-report.yml@v2
with:
coveragereports: HealthGPT.xcresult
secrets:
token: ${{ secrets.CODECOV_TOKEN }}
53 changes: 35 additions & 18 deletions HealthGPT.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,14 @@
2F4E21D829F0518B0067EE98 /* OnboardingUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F4E21D729F0518B0067EE98 /* OnboardingUITests.swift */; };
2F4E23832989D51F0013F3D9 /* HealthGPTAppTestingSetup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F4E23822989D51F0013F3D9 /* HealthGPTAppTestingSetup.swift */; };
2F5E32BD297E05EA003432F8 /* HealthGPTAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F5E32BC297E05EA003432F8 /* HealthGPTAppDelegate.swift */; };
2FF8DBF429F041C500239E1A /* OpenAI in Frameworks */ = {isa = PBXBuildFile; productRef = 2FF8DBF329F041C500239E1A /* OpenAI */; };
63439A4E2BA6069E008BDBFD /* SpeziLLM in Frameworks */ = {isa = PBXBuildFile; productRef = 63439A4D2BA6069E008BDBFD /* SpeziLLM */; };
63439A502BA6069E008BDBFD /* SpeziLLMOpenAI in Frameworks */ = {isa = PBXBuildFile; productRef = 63439A4F2BA6069E008BDBFD /* SpeziLLMOpenAI */; };
634523F12BAEF62E00A6E2A1 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 634523F02BAEF62D00A6E2A1 /* Localizable.xcstrings */; };
63497B6C2BBF095A001F8419 /* LLMSourceSelection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63497B6B2BBF095A001F8419 /* LLMSourceSelection.swift */; };
63497B6E2BBF0C0B001F8419 /* LLMSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63497B6D2BBF0C0B001F8419 /* LLMSource.swift */; };
63DAAF712BBEB14A009E5E19 /* SpeziLLMLocal in Frameworks */ = {isa = PBXBuildFile; productRef = 63DAAF702BBEB14A009E5E19 /* SpeziLLMLocal */; };
63DAAF732BBEB14A009E5E19 /* SpeziLLMLocalDownload in Frameworks */ = {isa = PBXBuildFile; productRef = 63DAAF722BBEB14A009E5E19 /* SpeziLLMLocalDownload */; };
63DAAF752BBEB24D009E5E19 /* LLMLocalDownload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63DAAF742BBEB24D009E5E19 /* LLMLocalDownload.swift */; };
653A2551283387FE005D4D48 /* HealthGPTApplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 653A2550283387FE005D4D48 /* HealthGPTApplication.swift */; };
653A255528338800005D4D48 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 653A255428338800005D4D48 /* Assets.xcassets */; };
E21D86A029EDB17500490C26 /* HealthDataFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = E21D869F29EDB17500490C26 /* HealthDataFetcher.swift */; };
Expand Down Expand Up @@ -98,6 +102,9 @@
2F5E32BC297E05EA003432F8 /* HealthGPTAppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HealthGPTAppDelegate.swift; sourceTree = "<group>"; };
2FAEC07F297F583900C11C42 /* HealthGPT.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = HealthGPT.entitlements; sourceTree = "<group>"; };
634523F02BAEF62D00A6E2A1 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
63497B6B2BBF095A001F8419 /* LLMSourceSelection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LLMSourceSelection.swift; sourceTree = "<group>"; };
63497B6D2BBF0C0B001F8419 /* LLMSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LLMSource.swift; sourceTree = "<group>"; };
63DAAF742BBEB24D009E5E19 /* LLMLocalDownload.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LLMLocalDownload.swift; sourceTree = "<group>"; };
653A254D283387FE005D4D48 /* HealthGPT.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HealthGPT.app; sourceTree = BUILT_PRODUCTS_DIR; };
653A2550283387FE005D4D48 /* HealthGPTApplication.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HealthGPTApplication.swift; sourceTree = "<group>"; };
653A255428338800005D4D48 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
Expand Down Expand Up @@ -131,14 +138,15 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
63DAAF712BBEB14A009E5E19 /* SpeziLLMLocal in Frameworks */,
63439A4E2BA6069E008BDBFD /* SpeziLLM in Frameworks */,
27859C072A34F17800397C85 /* SpeziOnboarding in Frameworks */,
27859C012A34F15E00397C85 /* XCTSpezi in Frameworks */,
63DAAF732BBEB14A009E5E19 /* SpeziLLMLocalDownload in Frameworks */,
27859C042A34F16B00397C85 /* SpeziHealthKit in Frameworks */,
27859BFF2A34F15E00397C85 /* Spezi in Frameworks */,
27859C102A34F1A900397C85 /* SpeziLocalStorage in Frameworks */,
63439A502BA6069E008BDBFD /* SpeziLLMOpenAI in Frameworks */,
2FF8DBF429F041C500239E1A /* OpenAI in Frameworks */,
27859C122A34F1A900397C85 /* SpeziSecureStorage in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -165,6 +173,9 @@
275DEFD829EEC6B80079D453 /* OnboardingFlow.swift */,
275DEFDA29EEC6CA0079D453 /* String+ModuleLocalized.swift */,
275DEFDC29EEC6DC0079D453 /* Welcome.swift */,
63DAAF742BBEB24D009E5E19 /* LLMLocalDownload.swift */,
63497B6B2BBF095A001F8419 /* LLMSourceSelection.swift */,
63497B6D2BBF0C0B001F8419 /* LLMSource.swift */,
);
path = Onboarding;
sourceTree = "<group>";
Expand Down Expand Up @@ -328,7 +339,6 @@
);
name = HealthGPT;
packageProductDependencies = (
2FF8DBF329F041C500239E1A /* OpenAI */,
27859BFE2A34F15E00397C85 /* Spezi */,
27859C002A34F15E00397C85 /* XCTSpezi */,
27859C032A34F16B00397C85 /* SpeziHealthKit */,
Expand All @@ -337,6 +347,8 @@
27859C112A34F1A900397C85 /* SpeziSecureStorage */,
63439A4D2BA6069E008BDBFD /* SpeziLLM */,
63439A4F2BA6069E008BDBFD /* SpeziLLMOpenAI */,
63DAAF702BBEB14A009E5E19 /* SpeziLLMLocal */,
63DAAF722BBEB14A009E5E19 /* SpeziLLMLocalDownload */,
);
productName = TemplateApplication;
productReference = 653A254D283387FE005D4D48 /* HealthGPT.app */;
Expand Down Expand Up @@ -375,7 +387,6 @@
);
mainGroup = 653A2544283387FE005D4D48;
packageReferences = (
2FF8DBF229F041C500239E1A /* XCRemoteSwiftPackageReference "OpenAI" */,
27859BFD2A34F15E00397C85 /* XCRemoteSwiftPackageReference "Spezi" */,
27859C022A34F16A00397C85 /* XCRemoteSwiftPackageReference "SpeziHealthKit" */,
27859C052A34F17800397C85 /* XCRemoteSwiftPackageReference "SpeziOnboarding" */,
Expand Down Expand Up @@ -470,17 +481,20 @@
275DEFD729EEC6A60079D453 /* Disclaimer.swift in Sources */,
275DEFF429EECA180079D453 /* CodableArray+RawRepresentable.swift in Sources */,
2719BC7829F0A31500995C31 /* SettingsView.swift in Sources */,
63DAAF752BBEB24D009E5E19 /* LLMLocalDownload.swift in Sources */,
2F4242992A8B0432006E2B01 /* HealthGPTStandard.swift in Sources */,
2F4242972A8B03A5006E2B01 /* OpenAIModelSelection.swift in Sources */,
2F4E23832989D51F0013F3D9 /* HealthGPTAppTestingSetup.swift in Sources */,
272FB34E2A03CDFF0010B98D /* HealthDataFetcher+Process.swift in Sources */,
275DEFD029EEC5D20079D453 /* FeatureFlags.swift in Sources */,
272FB3522A03D14C0010B98D /* HealthData.swift in Sources */,
63497B6E2BBF0C0B001F8419 /* LLMSource.swift in Sources */,
F381BD3C2A4DE41900BCEB69 /* HealthDataInterpreter.swift in Sources */,
275DEFF229EECA030079D453 /* Binding+Negate.swift in Sources */,
2F5E32BD297E05EA003432F8 /* HealthGPTAppDelegate.swift in Sources */,
275DEFD529EEC6870079D453 /* HealthKitPermissions.swift in Sources */,
272FB3542A03F1860010B98D /* PromptGenerator.swift in Sources */,
63497B6C2BBF095A001F8419 /* LLMSourceSelection.swift in Sources */,
275DEFDB29EEC6CA0079D453 /* String+ModuleLocalized.swift in Sources */,
2719BC8029F0A5DD00995C31 /* UIApplication+Keyboard.swift in Sources */,
E22B62EF29E8CE1E008F3484 /* HealthGPTView.swift in Sources */,
Expand Down Expand Up @@ -680,6 +694,7 @@
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = TEST;
SWIFT_OBJC_INTEROP_MODE = objcxx;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Test;
Expand Down Expand Up @@ -725,6 +740,7 @@
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
"SWIFT_ELicenseRef-TemplateApplication_LOC_STRINGS" = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_INTEROP_MODE = objcxx;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
};
Expand Down Expand Up @@ -787,6 +803,7 @@
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OBJC_INTEROP_MODE = objcxx;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
Expand Down Expand Up @@ -841,6 +858,7 @@
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OBJC_INTEROP_MODE = objcxx;
SWIFT_OPTIMIZATION_LEVEL = "-O";
VALIDATE_PRODUCT = YES;
};
Expand Down Expand Up @@ -887,6 +905,7 @@
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
"SWIFT_ELicenseRef-TemplateApplication_LOC_STRINGS" = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_INTEROP_MODE = objcxx;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
};
Expand Down Expand Up @@ -936,6 +955,7 @@
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
"SWIFT_ELicenseRef-TemplateApplication_LOC_STRINGS" = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_INTEROP_MODE = objcxx;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
};
Expand Down Expand Up @@ -1043,20 +1063,12 @@
minimumVersion = 1.0.1;
};
};
2FF8DBF229F041C500239E1A /* XCRemoteSwiftPackageReference "OpenAI" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/MacPaw/OpenAI.git";
requirement = {
kind = upToNextMinorVersion;
minimumVersion = 0.2.6;
};
};
63439A4C2BA6069E008BDBFD /* XCRemoteSwiftPackageReference "SpeziLLM" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/StanfordSpezi/SpeziLLM";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 0.7.1;
minimumVersion = 0.8.1;
};
};
/* End XCRemoteSwiftPackageReference section */
Expand Down Expand Up @@ -1112,11 +1124,6 @@
package = 27859C262A34F2DE00397C85 /* XCRemoteSwiftPackageReference "XCTRuntimeAssertions" */;
productName = XCTRuntimeAssertions;
};
2FF8DBF329F041C500239E1A /* OpenAI */ = {
isa = XCSwiftPackageProductDependency;
package = 2FF8DBF229F041C500239E1A /* XCRemoteSwiftPackageReference "OpenAI" */;
productName = OpenAI;
};
63439A4D2BA6069E008BDBFD /* SpeziLLM */ = {
isa = XCSwiftPackageProductDependency;
package = 63439A4C2BA6069E008BDBFD /* XCRemoteSwiftPackageReference "SpeziLLM" */;
Expand All @@ -1127,6 +1134,16 @@
package = 63439A4C2BA6069E008BDBFD /* XCRemoteSwiftPackageReference "SpeziLLM" */;
productName = SpeziLLMOpenAI;
};
63DAAF702BBEB14A009E5E19 /* SpeziLLMLocal */ = {
isa = XCSwiftPackageProductDependency;
package = 63439A4C2BA6069E008BDBFD /* XCRemoteSwiftPackageReference "SpeziLLM" */;
productName = SpeziLLMLocal;
};
63DAAF722BBEB14A009E5E19 /* SpeziLLMLocalDownload */ = {
isa = XCSwiftPackageProductDependency;
package = 63439A4C2BA6069E008BDBFD /* XCRemoteSwiftPackageReference "SpeziLLM" */;
productName = SpeziLLMLocalDownload;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 653A2545283387FE005D4D48 /* Project object */;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
{
"originHash" : "98a3d0589c1bc602c69147b70f8a44c2f8b44cfc1469b8ed82df6bf8db92de53",
"originHash" : "763dd6c3fb283cd30c2edd3e18fad0c0f9ef9fb226c4b08bdd490e0a7de07181",
"pins" : [
{
"identity" : "llama.cpp",
"kind" : "remoteSourceControl",
"location" : "https://github.com/StanfordBDHG/llama.cpp",
"state" : {
"revision" : "7bfd6d4b5bbc9fd47bd023bdbb35f96c827977f3",
"version" : "0.2.1"
"revision" : "6839853a321778906e210a33ee2c6aec52f34c97",
"version" : "0.3.3"
}
},
{
"identity" : "openai",
"kind" : "remoteSourceControl",
"location" : "https://github.com/MacPaw/OpenAI.git",
"location" : "https://github.com/StanfordBDHG/OpenAI",
"state" : {
"revision" : "35afc9a6ee127b8f22a85a31aec2036a987478af",
"version" : "0.2.6"
"revision" : "29316babb446c34bb07bf528d96de7eb41e7b03c",
"version" : "0.2.8"
}
},
{
Expand All @@ -33,8 +33,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/StanfordSpezi/SpeziChat",
"state" : {
"revision" : "2334583105224b0c04fc36989db82b000021d31d",
"version" : "0.1.9"
"revision" : "aaa10d71431b78ece8bf29f95c0050632714984d",
"version" : "0.2.0"
}
},
{
Expand All @@ -60,8 +60,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/StanfordSpezi/SpeziLLM",
"state" : {
"revision" : "dc37b91ed55c9d50eaf58e645d454cb62e3681d1",
"version" : "0.7.2"
"revision" : "94f14f6a1d0fb4c7bb54efa6b6241f18dfc5004d",
"version" : "0.8.2"
}
},
{
Expand Down
4 changes: 4 additions & 0 deletions HealthGPT.xcodeproj/xcshareddata/xcschemes/HealthGPT.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@
argument = "--mockMode"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "--localLLM"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "--showOnboarding"
isEnabled = "NO">
Expand Down
23 changes: 7 additions & 16 deletions HealthGPT/HealthGPT/HealthDataInterpreter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Foundation
import Spezi
import SpeziChat
import SpeziLLM
import SpeziLLMLocal
import SpeziLLMOpenAI
import SpeziSpeechSynthesizer

Expand All @@ -23,26 +24,16 @@ class HealthDataInterpreter: DefaultInitializable, Module, EnvironmentAccessible
@ObservationIgnored private var systemPrompt = ""

required init() { }


/// Creates an `LLMSchema`, sets it up for use with an `LLMRunner`, injects the system prompt

/// Creates an `LLMRunner`, from an `LLMSchema` and injects the system prompt
/// into the context, and assigns the resulting `LLMSession` to the `llm` property. For more
/// information, please refer to the [`SpeziLLM`](https://swiftpackageindex.com/StanfordSpezi/SpeziLLM/documentation/spezillm) documentation.
///
/// If the `--mockMode` feature flag is set, this function will use `LLMMockSchema()`, otherwise
/// will use `LLMOpenAISchema` with the model type specified in the `model` parameter.
/// - Parameter model: the type of OpenAI model to use
/// - Parameter schema: the LLMSchema to use
@MainActor
func prepareLLM(with model: LLMOpenAIModelType) async {
var llmSchema: any LLMSchema

if FeatureFlags.mockMode {
llmSchema = LLMMockSchema()
} else {
llmSchema = LLMOpenAISchema(parameters: .init(modelType: model))
}

let llm = llmRunner(with: llmSchema)
func prepareLLM(with schema: any LLMSchema) async {
let llm = llmRunner(with: schema)
systemPrompt = await generateSystemPrompt()
llm.context.append(systemMessage: systemPrompt)
self.llm = llm
Expand All @@ -52,7 +43,7 @@ class HealthDataInterpreter: DefaultInitializable, Module, EnvironmentAccessible
@MainActor
func queryLLM() async throws {
guard let llm,
llm.context.last?.role == .user || !(llm.context.contains(where: { $0.role == .assistant }) ) else {
llm.context.last?.role == .user || !(llm.context.contains(where: { $0.role == .assistant() }) ) else {
return
}

Expand Down
18 changes: 15 additions & 3 deletions HealthGPT/HealthGPT/HealthGPTView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import SpeziChat
import SpeziLLM
import SpeziLLMLocal
import SpeziLLMOpenAI
import SpeziSpeechSynthesizer
import SwiftUI
Expand All @@ -16,6 +17,7 @@
struct HealthGPTView: View {
@AppStorage(StorageKeys.onboardingFlowComplete) var completedOnboardingFlow = false
@AppStorage(StorageKeys.enableTextToSpeech) private var textToSpeech = StorageKeys.Defaults.enableTextToSpeech
@AppStorage(StorageKeys.llmSource) private var llmSource = StorageKeys.Defaults.llmSource
@AppStorage(StorageKeys.openAIModel) private var openAIModel = LLMOpenAIModelType.gpt4

@Environment(HealthDataInterpreter.self) private var healthDataInterpreter
Expand All @@ -26,9 +28,10 @@
var body: some View {
NavigationStack {
if let llm = healthDataInterpreter.llm {
let contextBinding = Binding { llm.context } set: { llm.context = $0 }
let contextBinding = Binding { llm.context.chat } set: { llm.context.chat = $0 }

ChatView(contextBinding, exportFormat: .text)
.speak(llm.context, muted: !textToSpeech)
.speak(llm.context.chat, muted: !textToSpeech)
.speechToolbarButton(muted: !$textToSpeech)
.viewStateAlert(state: llm.state)
.navigationTitle("WELCOME_TITLE")
Expand Down Expand Up @@ -65,7 +68,16 @@
Text(errorMessage)
}
.task {
await healthDataInterpreter.prepareLLM(with: openAIModel)
if FeatureFlags.mockMode {
await healthDataInterpreter.prepareLLM(with: LLMMockSchema())
} else if FeatureFlags.localLLM || llmSource == .local {
await healthDataInterpreter.prepareLLM(with: LLMLocalSchema(
modelPath: .cachesDirectory.appending(path: "llm.gguf"),
formatChat: LLMLocalSchema.PromptFormattingDefaults.llama3
))

Check warning on line 77 in HealthGPT/HealthGPT/HealthGPTView.swift

View check run for this annotation

Codecov / codecov/patch

HealthGPT/HealthGPT/HealthGPTView.swift#L74-L77

Added lines #L74 - L77 were not covered by tests
} else {
await healthDataInterpreter.prepareLLM(with: LLMOpenAISchema(parameters: .init(modelType: openAIModel)))
}
}
}

Expand Down
8 changes: 6 additions & 2 deletions HealthGPT/HealthGPT/SettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,18 @@
@Environment(\.dismiss) private var dismiss
@Environment(HealthDataInterpreter.self) private var healthDataInterpreter
@AppStorage(StorageKeys.enableTextToSpeech) private var enableTextToSpeech = StorageKeys.Defaults.enableTextToSpeech
@AppStorage(StorageKeys.llmSource) private var llmSource = StorageKeys.Defaults.llmSource
@AppStorage(StorageKeys.openAIModel) private var openAIModel = LLMOpenAIModelType.gpt4
let logger = Logger(subsystem: "HealthGPT", category: "Settings")


var body: some View {
NavigationStack(path: $path) {
List {
openAISettings
if !FeatureFlags.localLLM && !(llmSource == .local) {
openAISettings
}

chatSettings
speechSettings
disclaimer
Expand Down Expand Up @@ -102,7 +106,7 @@
) { model in
Task {
openAIModel = model
await healthDataInterpreter.prepareLLM(with: model)
await healthDataInterpreter.prepareLLM(with: LLMOpenAISchema(parameters: .init(modelType: model)))

Check warning on line 109 in HealthGPT/HealthGPT/SettingsView.swift

View check run for this annotation

Codecov / codecov/patch

HealthGPT/HealthGPT/SettingsView.swift#L109

Added line #L109 was not covered by tests
path.removeLast()
}
}
Expand Down
Loading
Loading