diff --git a/Playground/Playground.xcodeproj/project.pbxproj b/Playground/Playground.xcodeproj/project.pbxproj index b58f795..3f8bda2 100644 --- a/Playground/Playground.xcodeproj/project.pbxproj +++ b/Playground/Playground.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 0A983C092CA8AB14008C3A04 /* LLMChatAnthropic in Frameworks */ = {isa = PBXBuildFile; productRef = 0A983C082CA8AB14008C3A04 /* LLMChatAnthropic */; }; + 0AD273C62CBF221C00B907C2 /* AIModelRetriever in Frameworks */ = {isa = PBXBuildFile; productRef = 0AD273C52CBF221C00B907C2 /* AIModelRetriever */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -28,6 +29,7 @@ buildActionMask = 2147483647; files = ( 0A983C092CA8AB14008C3A04 /* LLMChatAnthropic in Frameworks */, + 0AD273C62CBF221C00B907C2 /* AIModelRetriever in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -71,6 +73,7 @@ name = Playground; packageProductDependencies = ( 0A983C082CA8AB14008C3A04 /* LLMChatAnthropic */, + 0AD273C52CBF221C00B907C2 /* AIModelRetriever */, ); productName = Playground; productReference = 0A983BED2CA8AA94008C3A04 /* Playground.app */; @@ -102,6 +105,7 @@ minimizedProjectReferenceProxies = 1; packageReferences = ( 0A983C072CA8AB14008C3A04 /* XCLocalSwiftPackageReference "../../swift-llm-chat-anthropic" */, + 0AD273C42CBF221C00B907C2 /* XCRemoteSwiftPackageReference "swift-ai-model-retriever" */, ); preferredProjectObjectVersion = 77; productRefGroup = 0A983BEE2CA8AA94008C3A04 /* Products */; @@ -345,11 +349,27 @@ }; /* End XCLocalSwiftPackageReference section */ +/* Begin XCRemoteSwiftPackageReference section */ + 0AD273C42CBF221C00B907C2 /* XCRemoteSwiftPackageReference "swift-ai-model-retriever" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/kevinhermawan/swift-ai-model-retriever.git"; + requirement = { + branch = main; + kind = branch; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + /* Begin XCSwiftPackageProductDependency section */ 0A983C082CA8AB14008C3A04 /* LLMChatAnthropic */ = { isa = XCSwiftPackageProductDependency; productName = LLMChatAnthropic; }; + 0AD273C52CBF221C00B907C2 /* AIModelRetriever */ = { + isa = XCSwiftPackageProductDependency; + package = 0AD273C42CBF221C00B907C2 /* XCRemoteSwiftPackageReference "swift-ai-model-retriever" */; + productName = AIModelRetriever; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 0A983BE52CA8AA94008C3A04 /* Project object */; diff --git a/Playground/Playground.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Playground/Playground.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index af6f831..e5c66c9 100644 --- a/Playground/Playground.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Playground/Playground.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,6 +1,15 @@ { - "originHash" : "2daebb55d9d33ef1f7c749292979cb98d35958bdcd51cdd5c0191cde25d9b02b", + "originHash" : "9babdbe0d420e7da0e4b1fdca252d3d06b03638f979b3d4ce55ccda4d14b84d3", "pins" : [ + { + "identity" : "swift-ai-model-retriever", + "kind" : "remoteSourceControl", + "location" : "https://github.com/kevinhermawan/swift-ai-model-retriever.git", + "state" : { + "branch" : "main", + "revision" : "5d22906f1bedcb53452257c784ebffa72e9ad1cb" + } + }, { "identity" : "swift-json-schema", "kind" : "remoteSourceControl", diff --git a/Playground/Playground/ViewModels/AppViewModel.swift b/Playground/Playground/ViewModels/AppViewModel.swift index 29c832f..9744559 100644 --- a/Playground/Playground/ViewModels/AppViewModel.swift +++ b/Playground/Playground/ViewModels/AppViewModel.swift @@ -6,22 +6,19 @@ // import Foundation +import AIModelRetriever import LLMChatAnthropic @Observable final class AppViewModel { - let models: [String] = [ - "claude-3-5-sonnet-20240620", - "claude-3-opus-20240229", - "claude-3-sonnet-20240229", - "claude-3-haiku-20240307" - ] - var stream = true var apiKey: String = "" + var chat = LLMChatAnthropic(apiKey: "") + var modelRetriever = AIModelRetriever() - var selectedModel: String = "claude-3-5-sonnet-20240620" + var models = [String]() + var selectedModel: String = "" var systemPrompt: String = "You're a helpful AI assistant." var temperature = 0.5 @@ -30,6 +27,7 @@ final class AppViewModel { self.apiKey = existingApiKey } + fetchModels() configureChat() } @@ -44,6 +42,15 @@ final class AppViewModel { } private func configureChat() { - chat = LLMChatAnthropic(apiKey: apiKey, customHeaders: ["anthropic-beta": "prompt-caching-2024-07-31"]) + chat = LLMChatAnthropic(apiKey: apiKey, headers: ["anthropic-beta": "prompt-caching-2024-07-31"]) + } + + private func fetchModels() { + let llmModels = modelRetriever.anthropic() + models = llmModels.map(\.id) + + if let firstModel = models.first { + selectedModel = firstModel + } } } diff --git a/README.md b/README.md index d0ebf9f..d266400 100644 --- a/README.md +++ b/README.md @@ -48,8 +48,8 @@ let chat = LLMChatAnthropic(apiKey: "") // Initialize with custom endpoint and headers let chat = LLMChatAnthropic( apiKey: "", - endpoint: "https://custom-api.example.com/v1/chat/completions", - customHeaders: ["Custom-Header": "Value"] + endpoint: URL(string: "https://custom-api.example.com/v1/messages")!, + headers: ["Custom-Header": "Value"] ) ``` @@ -172,7 +172,7 @@ To learn more about tool use, check out the [Anthropic documentation](https://do ```swift let chat = LLMChatAnthropic( apiKey: "", - customHeaders: ["anthropic-beta": "prompt-caching-2024-07-31"] // Required + headers: ["anthropic-beta": "prompt-caching-2024-07-31"] // Required ) let messages = [ @@ -193,14 +193,14 @@ let task = Task { To learn more about prompt caching, check out the [Anthropic documentation](https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching). -## Donations +## Support If you find `LLMChatAnthropic` helpful and would like to support its development, consider making a donation. Your contribution helps maintain the project and develop new features. - [GitHub Sponsors](https://github.com/sponsors/kevinhermawan) - [Buy Me a Coffee](https://buymeacoffee.com/kevinhermawan) -Your support is greatly appreciated! +Your support is greatly appreciated! ❤️ ## Contributing diff --git a/Sources/LLMChatAnthropic/Documentation.docc/Documentation.md b/Sources/LLMChatAnthropic/Documentation.docc/Documentation.md index e1af1ff..14a9b9a 100644 --- a/Sources/LLMChatAnthropic/Documentation.docc/Documentation.md +++ b/Sources/LLMChatAnthropic/Documentation.docc/Documentation.md @@ -19,8 +19,8 @@ let chat = LLMChatAnthropic(apiKey: "") // Initialize with custom endpoint and headers let chat = LLMChatAnthropic( apiKey: "", - endpoint: "https://custom-api.example.com/v1/chat/completions", - customHeaders: ["Custom-Header": "Value"] + endpoint: URL(string: "https://custom-api.example.com/v1/messages")!, + headers: ["Custom-Header": "Value"] ) ``` @@ -143,7 +143,7 @@ To learn more about tool use, check out the [Anthropic documentation](https://do ```swift let chat = LLMChatAnthropic( apiKey: "", - customHeaders: ["anthropic-beta": "prompt-caching-2024-07-31"] // Required + headers: ["anthropic-beta": "prompt-caching-2024-07-31"] // Required ) let messages = [ diff --git a/Sources/LLMChatAnthropic/LLMChatAnthropic.swift b/Sources/LLMChatAnthropic/LLMChatAnthropic.swift index 3831b3f..ed75791 100644 --- a/Sources/LLMChatAnthropic/LLMChatAnthropic.swift +++ b/Sources/LLMChatAnthropic/LLMChatAnthropic.swift @@ -11,20 +11,20 @@ import Foundation public struct LLMChatAnthropic { private let apiKey: String private let endpoint: URL - private var customHeaders: [String: String]? = nil + private var headers: [String: String]? = nil /// Creates a new instance of ``LLMChatAnthropic``. /// /// - Parameters: /// - apiKey: Your Anthropic API key. /// - endpoint: The Anthropic-compatible endpoint. - /// - customHeaders: Additional HTTP headers to include in the requests. + /// - headers: Additional HTTP headers to include in the requests. /// /// - Note: Make sure to include the complete URL for the `endpoint`, including the protocol (http:// or https://) and its path. - public init(apiKey: String, endpoint: URL? = nil, customHeaders: [String: String]? = nil) { + public init(apiKey: String, endpoint: URL? = nil, headers: [String: String]? = nil) { self.apiKey = apiKey self.endpoint = endpoint ?? URL(string: "https://api.anthropic.com/v1/messages")! - self.customHeaders = customHeaders + self.headers = headers } } @@ -133,25 +133,25 @@ extension LLMChatAnthropic { // MARK: - Helper Methods private extension LLMChatAnthropic { - var defaultHeaders: [String: String] { - var headers = [ + var allHeaders: [String: String] { + var defaultHeaders = [ "Anthropic-Version": "2023-06-01", "Content-Type": "application/json", "X-Api-Key": apiKey ] - if let customHeaders { - headers.merge(customHeaders) { _, new in new } + if let headers { + defaultHeaders.merge(headers) { _, new in new } } - return headers + return defaultHeaders } func createRequest(for url: URL, with body: RequestBody) throws -> URLRequest { var request = URLRequest(url: url) request.httpMethod = "POST" request.httpBody = try JSONEncoder().encode(body) - request.allHTTPHeaderFields = defaultHeaders + request.allHTTPHeaderFields = allHeaders return request }