Skip to content

Commit 627cad2

Browse files
Adding README
1 parent 0760c3b commit 627cad2

14 files changed

+316
-130
lines changed

PolyAIExample/PolyAIExample/ApiKeysIntroView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ struct ApiKeyIntroView: View {
5858
.buttonStyle(.bordered)
5959
.padding()
6060
.textFieldStyle(.roundedBorder)
61-
NavigationLink(destination: OptionsListView(service: PolyAIServiceFactory.configurations(configurations))) {
61+
NavigationLink(destination: OptionsListView(service: PolyAIServiceFactory.serviceWith(configurations))) {
6262
Text("Continue")
6363
.padding()
6464
.padding(.horizontal, 48)

README.md

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,84 @@
88
[![xcode-version](https://img.shields.io/badge/xcode-15%20-brightgreen)](https://developer.apple.com/xcode/)
99
[![swift-package-manager](https://img.shields.io/badge/package%20manager-compatible-brightgreen.svg?logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNjJweCIgaGVpZ2h0PSI0OXB4IiB2aWV3Qm94PSIwIDAgNjIgNDkiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDYzLjEgKDkyNDUyKSAtIGh0dHBzOi8vc2tldGNoLmNvbSAtLT4KICAgIDx0aXRsZT5Hcm91cDwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxnIGlkPSJQYWdlLTEiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxnIGlkPSJHcm91cCIgZmlsbC1ydWxlPSJub256ZXJvIj4KICAgICAgICAgICAgPHBvbHlnb24gaWQ9IlBhdGgiIGZpbGw9IiNEQkI1NTEiIHBvaW50cz0iNTEuMzEwMzQ0OCAwIDEwLjY4OTY1NTIgMCAwIDEzLjUxNzI0MTQgMCA0OSA2MiA0OSA2MiAxMy41MTcyNDE0Ij48L3BvbHlnb24+CiAgICAgICAgICAgIDxwb2x5Z29uIGlkPSJQYXRoIiBmaWxsPSIjRjdFM0FGIiBwb2ludHM9IjI3IDI1IDMxIDI1IDM1IDI1IDM3IDI1IDM3IDE0IDI1IDE0IDI1IDI1Ij48L3BvbHlnb24+CiAgICAgICAgICAgIDxwb2x5Z29uIGlkPSJQYXRoIiBmaWxsPSIjRUZDNzVFIiBwb2ludHM9IjEwLjY4OTY1NTIgMCAwIDE0IDYyIDE0IDUxLjMxMDM0NDggMCI+PC9wb2x5Z29uPgogICAgICAgICAgICA8cG9seWdvbiBpZD0iUmVjdGFuZ2xlIiBmaWxsPSIjRjdFM0FGIiBwb2ludHM9IjI3IDAgMzUgMCAzNyAxNCAyNSAxNCI+PC9wb2x5Z29uPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+)](https://github.com/apple/swift-package-manager)
1010

11+
1112
An open-source Swift package that simplifies LLM message completions, inspired by [liteLLM](https://litellm.ai/) and adapted for Swift developers, following Swift conventions.
1213

13-
Call different LLM APIs using the OpenAI format; currently supporting OpenAI and Anthropic, with more models, including Gemini, coming soon.
14+
## Table of Contents
15+
16+
- [Description](#description)
17+
- [Installation](#installation)
18+
- [Usage](#usage)
19+
- [Message](#message)
20+
- [Collaboration](#collaboration)
21+
22+
## Description
23+
24+
Call different LLM APIs using the OpenAI format; currently supporting [OpenAI](https://github.com/jamesrochabrun/SwiftOpenAI) and [Anthropic](https://github.com/jamesrochabrun/SwiftAnthropic), with more models, including Gemini, coming soon.
25+
26+
## Installation
27+
28+
### Swift Package Manager
29+
30+
1. Open your Swift project in Xcode.
31+
2. Go to `File` -> `Add Package Dependency`.
32+
3. In the search bar, enter [this URL](https://github.com/jamesrochabrun/PolyAI).
33+
4. Choose the version you'd like to install.
34+
5. Click `Add Package`.
35+
36+
### Important
37+
38+
⚠️ Please take precautions to keep your API keys secure.
39+
40+
> Remember that your API keys are a secret! Do not share it with others or expose
41+
> it in any client-side code (browsers, apps). Production requests must be
42+
> routed through your backend server where your API keys can be securely
43+
> loaded from an environment variable or key management service.
44+
45+
## Usage
46+
47+
To interface with different LLMs, you need only to supply the corresponding LLM configuration and adjust the parameters accordingly.
48+
49+
First, import the PolyAI package:
50+
51+
```swift
52+
import PolyAI
53+
```
54+
55+
Then, define the LLM configurations. Currently, OpenAI and Anthropic are supported:
56+
57+
```swift
58+
let openAIConfiguration: LLMConfiguration = .openAI(apiKey: "your_openai_api_key_here")
59+
let anthropicConfiguration: LLMConfiguration = .anthropic(apiKey: "your_anthropic_api_key_here")
60+
let configurations = [openAIConfiguration, anthropicConfiguration]
61+
```
62+
63+
With the configurations set, initialize the service:
64+
65+
```swift
66+
let service = PolyAIServiceFactory.serviceWith(configurations)
67+
```
68+
69+
Now, you have access to both the OpenAI and Anthropic APIs in a single package, with Gemini coming soon! 🚀
70+
71+
## Message
72+
73+
To send a message using OpenAI:
74+
75+
```swift
76+
let prompt = "How are you today?"
77+
let parameters: LLMParameter = .openAI(model: .gpt4turbo, messages: [.init(role: .user, content: prompt)])
78+
let stream = try await service.streamMessage(parameters)
79+
```
80+
81+
To interact with Anthropic instead, all you need to do is update the parameters:
82+
83+
```swift
84+
let prompt = "How are you today?"
85+
let parameters: LLMParameter = .anthropic(model: .claude3Sonnet, messages: [.init(role: .user, content: prompt)], maxTokens: 1024)
86+
let stream = try await service.streamMessage(parameters)
87+
```
88+
89+
## Collaboration
90+
91+
Open a PR for any proposed change pointing it to `main` branch.

Sources/PolyAI/Interfaces/Parameters/LLMMessageParameter.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import Foundation
99

1010
// MARK: LLMMessageParameter
1111

12+
/// A protocol defining the basic requirements for a message parameter used with LLM services.
1213
public protocol LLMMessageParameter {
1314

1415
var role: String { get }
@@ -19,14 +20,21 @@ public protocol LLMMessageParameter {
1920

2021
public struct LLMMessage: LLMMessageParameter {
2122

23+
/// The role of the sender in the conversation, such as "user" or "assistant".
2224
public var role: String
25+
26+
/// The content of the message being sent.
2327
public var content: String
2428

2529
public enum Role: String {
2630
case user
2731
case assistant
2832
}
2933

34+
/// Initializes a new message with specified role and content.
35+
/// - Parameters:
36+
/// - role: The role of the sender of the message.
37+
/// - content: The content of the message.
3038
public init(
3139
role: Role,
3240
content: String)

Sources/PolyAI/Interfaces/Parameters/LLMParameter.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,24 @@ import Foundation
99
import SwiftOpenAI
1010
import SwiftAnthropic
1111

12+
/// An enum representing the parameters required to interface with different LLM services.
1213
public enum LLMParameter {
1314

15+
/// Represents a configuration for interacting with OpenAI's models.
16+
/// - Parameters:
17+
/// - model: The specific model of OpenAI to use.
18+
/// - messages: An array of messages to send to the model.
19+
/// - maxTokens: An optional maximum number of tokens to generate. Defaults to `nil`.
1420
case openAI(model: SwiftOpenAI.Model, messages: [LLMMessage], maxTokens: Int? = nil)
21+
22+
/// Represents a configuration for interacting with Anthropic's models.
23+
/// - Parameters:
24+
/// - model: The specific model of Anthropic to use.
25+
/// - messages: An array of messages to send to the model.
26+
/// - maxTokens: The maximum number of tokens to generate.
1527
case anthropic(model: SwiftAnthropic.Model, messages: [LLMMessage], maxTokens: Int)
1628

29+
/// A computed property that returns the name of the LLM service based on the case.
1730
var llmService: String {
1831
switch self {
1932
case .openAI: return "OpenAI"

Sources/PolyAI/Interfaces/Response/LLMMessageResponse.swift

Lines changed: 0 additions & 92 deletions
This file was deleted.

Sources/PolyAI/Interfaces/Response/LLMMessageStreamResponse.swift

Lines changed: 0 additions & 35 deletions
This file was deleted.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//
2+
// LLMMessageResponse+Anthropic.swift
3+
//
4+
//
5+
// Created by James Rochabrun on 4/15/24.
6+
//
7+
8+
import Foundation
9+
import SwiftAnthropic
10+
11+
// MARK: Anthropic
12+
13+
extension MessageResponse: LLMMessageResponse {
14+
15+
public var createdAt: Int? {
16+
nil
17+
}
18+
19+
public var contentDescription: String {
20+
content.map { contentItem in
21+
switch contentItem {
22+
case .text(let text):
23+
return text
24+
case .toolUse(_, let name, _):
25+
return "Tool: \(name)"
26+
}
27+
}.first ?? ""
28+
}
29+
30+
public var usageMetrics: UsageMetrics {
31+
ChatUsageMetrics(inputTokens: usage.inputTokens, outputTokens: usage.outputTokens, totalTokens: nil)
32+
}
33+
34+
public var tools: [ToolUsage] {
35+
[]
36+
}
37+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//
2+
// LLMMessageResponse+OpenAI.swift
3+
//
4+
//
5+
// Created by James Rochabrun on 4/15/24.
6+
//
7+
8+
import Foundation
9+
import SwiftOpenAI
10+
11+
// MARK: OpenAI
12+
13+
extension ChatCompletionObject: LLMMessageResponse {
14+
15+
public var createdAt: Int? {
16+
created
17+
}
18+
19+
public var contentDescription: String {
20+
choices.first?.message.content ?? ""
21+
}
22+
23+
public var usageMetrics: UsageMetrics {
24+
ChatUsageMetrics(inputTokens: usage.promptTokens, outputTokens: usage.completionTokens, totalTokens: usage.totalTokens)
25+
}
26+
27+
public var tools: [ToolUsage] {
28+
[]
29+
}
30+
31+
public var role: String {
32+
choices.first?.message.role ?? "unknown"
33+
}
34+
}

0 commit comments

Comments
 (0)