generated from StanfordBDHG/SwiftPackageTemplate
-
-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1747a62
commit 8ffcccf
Showing
15 changed files
with
323 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
// | ||
// This source file is part of the Stanford Spezi open source project | ||
// | ||
// SPDX-FileCopyrightText: 2022 Stanford University and the project authors (see CONTRIBUTORS.md) | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
|
||
|
||
import OpenAI | ||
import Spezi | ||
import SpeziLocalStorage | ||
import SpeziSecureStorage | ||
import SwiftUI | ||
|
||
|
||
/// `OpenAIComponent` is a module responsible for to coordinate the interactions with the OpenAI GPT API. | ||
public class OpenAIComponent<ComponentStandard: Standard>: Component, ObservableObject, ObservableObjectProvider { | ||
@Dependency private var localStorage: LocalStorage | ||
@Dependency private var secureStorage: SecureStorage | ||
|
||
/// The OpenAI GPT Model type that is used to interact with the OpenAI API | ||
@AppStorage(OpenAIConstants.modelStorageKey) public var openAIModel: Model = .gpt3_5Turbo | ||
private var defaultAPIToken: String? | ||
|
||
/// The API token used to interact with the OpenAI API | ||
public var apiToken: String? { | ||
get { | ||
try? secureStorage.retrieveCredentials(OpenAIConstants.credentialsUsername, server: OpenAIConstants.credentialsServer)?.password | ||
} | ||
set { | ||
objectWillChange.send() | ||
if let newValue { | ||
try? secureStorage.store( | ||
credentials: Credentials(username: OpenAIConstants.credentialsUsername, password: newValue), | ||
server: OpenAIConstants.credentialsServer | ||
) | ||
} else { | ||
try? secureStorage.deleteCredentials(OpenAIConstants.credentialsUsername, server: OpenAIConstants.credentialsServer) | ||
} | ||
} | ||
} | ||
|
||
|
||
/// Initializes a new instance of `OpenAIGPT` with the specified API token and OpenAI model. | ||
/// | ||
/// - Parameters: | ||
/// - apiToken: The API token for the OpenAI API. | ||
/// - openAIModel: The OpenAI model to use for querying. | ||
public init(apiToken: String? = nil, openAIModel model: Model? = nil) { | ||
if UserDefaults.standard.object(forKey: OpenAIConstants.modelStorageKey) == nil { | ||
self.openAIModel = openAIModel | ||
} | ||
|
||
defaultAPIToken = apiToken | ||
} | ||
|
||
|
||
public func configure() { | ||
if self.apiToken == nil, let defaultAPIToken { | ||
self.apiToken = defaultAPIToken | ||
} | ||
} | ||
|
||
|
||
/// Queries the OpenAI API using the provided messages. | ||
/// | ||
/// - Parameters: | ||
/// - messages: A collection of chat messages used in the conversation. | ||
/// | ||
/// - Returns: The content of the response from the API. | ||
public func queryAPI(withChat chat: [Chat]) async throws -> AsyncThrowingStream<ChatStreamResult, Error> { | ||
guard let apiToken, !apiToken.isEmpty else { | ||
throw OpenAIError.noAPIToken | ||
} | ||
|
||
let openAIClient = OpenAI(apiToken: apiToken) | ||
let query = ChatQuery(model: openAIModel, messages: chat) | ||
return openAIClient.chatsStream(query: query) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// | ||
// This source file is part of the Stanford Spezi open source project | ||
// | ||
// SPDX-FileCopyrightText: 2022 Stanford University and the project authors (see CONTRIBUTORS.md) | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
|
||
|
||
enum OpenAIConstants { | ||
static let modelStorageKey = "OpenAIGPT.Model" | ||
static let credentialsServer = "openapi.org" | ||
static let credentialsUsername = "OpenAIGPT" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// | ||
// This source file is part of the Stanford Spezi open source project | ||
// | ||
// SPDX-FileCopyrightText: 2022 Stanford University and the project authors (see CONTRIBUTORS.md) | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
|
||
|
||
/// An error that can appear from an API call to the OpenAI API. | ||
public enum OpenAIError: Error { | ||
/// There was no OpenAI API token provided. | ||
case noAPIToken | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# ``SpeziOpenAI`` | ||
|
||
<!-- | ||
# | ||
# This source file is part of the Stanford Spezi open source project | ||
# | ||
# SPDX-FileCopyrightText: 2022 Stanford University and the project authors (see CONTRIBUTORS.md) | ||
# | ||
# SPDX-License-Identifier: MIT | ||
# | ||
--> | ||
|
||
Module to interact with the OpenAI API to interact with GPT-based large language models (LLMs). | ||
|
||
## Configuration | ||
|
||
``` | ||
class ExampleDelegate: SpeziAppDelegate { | ||
override var configuration: Configuration { | ||
Configuration(standard: /* ... */) { | ||
OpenAIComponent() | ||
// ... | ||
} | ||
} | ||
} | ||
``` | ||
|
||
You can provide a default API token or model configuration to the OpenAI component's ``OpenAIComponent/init(apiToken:openAIModel:)`` initializer in the configuration. | ||
The choice of model and the API key are persisted across application launches. | ||
|
||
|
||
## Usage | ||
|
||
The ``OpenAIComponent`` can subsequentially be used in a SwiftUI View using the environment dependency injection mechanism. | ||
|
||
``` | ||
struct ExampleOpenAIView: View { | ||
@EnvironmentObject var openAI: OpenAIComponent</* ... */> | ||
// ... | ||
} | ||
``` | ||
|
||
The ``OpenAIComponent``'s ``OpenAIComponent/apiToken`` and ``OpenAIComponent/openAIModel`` can be accessed and changed at runtime. | ||
The ``OpenAIComponent/queryAPI(withChat:)`` function allows the interaction with the GPT-based OpenAI models. | ||
|
||
|
||
## Types | ||
|
||
### Open AI GPT | ||
|
||
- ``OpenAIGPT`` | ||
- ``OpenAIGPTError`` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// | ||
// This source file is part of the SpeziML open-source project | ||
// | ||
// SPDX-FileCopyrightText: 2022 Stanford University and the project authors (see CONTRIBUTORS.md) | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
|
||
import SpeziOpenAI | ||
import SwiftUI | ||
import XCTSpezi | ||
|
||
|
||
struct ContentView: View { | ||
@EnvironmentObject var openAI: OpenAIComponent<TestAppStandard> | ||
|
||
|
||
var body: some View { | ||
Text("Your token is: \(openAI.apiToken ?? "")") | ||
Text("Your choice of model is: \(openAI.openAIModel)") | ||
Button("Test Token Change") { | ||
openAI.apiToken = "New Token" | ||
} | ||
Button("Test Model Change") { | ||
openAI.openAIModel = .gpt4 | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// | ||
// This source file is part of the SpeziML open-source project | ||
// | ||
// SPDX-FileCopyrightText: 2022 Stanford University and the project authors (see CONTRIBUTORS.md) | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
|
||
import Spezi | ||
import SpeziOpenAI | ||
import XCTSpezi | ||
|
||
|
||
class TestAppDelegate: SpeziAppDelegate { | ||
override var configuration: Configuration { | ||
Configuration(standard: TestAppStandard()) { | ||
OpenAIComponent() | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.