该库为使用 OpenAI 全新的 Realtime API 实现多模态对话提供了一个简单的接口。
它可以自动处理录制用户的麦克风和播放助手响应,并为您提供一个透明的 API 层,以用于高级用例。
Swift Package Manager 允许开发者轻松地将软件包集成到他们的 Xcode 项目和软件包中;并且也完全集成到 swift 编译器中。
一旦您设置好 Swift 软件包,将 Git 链接添加到您的 Package.swift 文件的 dependencies 值中。
dependencies: [
.package(url: "https://github.com/m1guelpf/swift-realtime-openai.git", .branch("main"))
]
您可以使用内置 AI 聊天的类似 iMessage 的应用程序,代码少于 60 行(包括 UI!)
import OpenAI
import SwiftUI
struct ContentView: View {
@State private var newMessage: String = ""
@State private var conversation = Conversation(authToken: OPENAI_KEY)
var messages: [Item.Message] {
conversation.entries.compactMap { switch $0 {
case let .message(message): return message
default: return nil
} }
}
var body: some View {
VStack(spacing: 0) {
ScrollView {
VStack(spacing: 12) {
ForEach(messages, id: \.id) { message in
MessageBubble(message: message)
}
}
.padding()
}
HStack(spacing: 12) {
HStack {
TextField("Chat", text: $newMessage, onCommit: { sendMessage() })
.frame(height: 40)
.submitLabel(.send)
if newMessage != "" {
Button(action: sendMessage) {
Image(systemName: "arrow.up.circle.fill")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 28, height: 28)
.foregroundStyle(.white, .blue)
}
}
}
.padding(.leading)
.padding(.trailing, 6)
.overlay(RoundedRectangle(cornerRadius: 20).stroke(.quaternary, lineWidth: 1))
}
.padding()
}
.navigationTitle("Chat")
.navigationBarTitleDisplayMode(.inline)
.onAppear { try! conversation.startHandlingVoice() }
}
func sendMessage() {
guard newMessage != "" else { return }
Task {
try await conversation.send(from: .user, text: newMessage)
newMessage = ""
}
}
}
或者,如果您只是想要一个简单的应用程序,让用户可以说话,AI 可以回应
import OpenAI
import SwiftUI
struct ContentView: View {
@State private var conversation = Conversation(authToken: OPENAI_KEY)
var body: some View {
Text("Say something!")
.onAppear { try! conversation.startListening() }
}
}
Conversation
类为管理与模型的对话提供了一个高级接口。它封装了 RealtimeAPI
类,并处理发送和接收消息以及管理对话历史记录的细节。它还可以选择处理录制用户的麦克风并将其发送到 API,以及播放模型响应,因为它们是流式传输进来的。
您可以通过 messages
属性访问对话中的消息。请注意,这不包括函数调用及其响应,仅包括用户和模型之间的消息。要访问完整的对话历史记录,请使用 entries
属性。例如
ScrollView {
ScrollViewReader { scrollView in
VStack(spacing: 12) {
ForEach(conversation.messages, id: \.id) { message in
MessageBubble(message: message).id(message.id)
}
}
.onReceive(conversation.messages.publisher) { _ in
withAnimation { scrollView.scrollTo(conversation.messages.last?.id, anchor: .center) }
}
}
}
您可以使用 setSession(_: Session)
或 updateSession(withChanges: (inout Session) -> Void)
方法自定义当前会话。请注意,它们要求已经建立会话,因此建议您从 whenConnected(_: @Sendable () async throws -> Void)
回调中调用它们,或者首先等待 waitForConnection()
。例如
try await conversation.whenConnected {
try await conversation.updateSession { session in
// update system prompt
session.instructions = "You are a helpful assistant."
// enable transcription of users' voice messages
session.inputAudioTranscription = Session.InputAudioTranscription()
// ...
}
}
Conversation
类可以自动处理双向语音对话。调用 startListening()
将开始监听用户的声音并将其发送到模型,并播放模型的响应。调用 stopListening()
将停止监听,但继续播放响应。
如果您只想播放模型响应,请调用 startHandlingVoice()
。要停止监听和播放响应,请调用 stopHandlingVoice()
。
要发送文本消息,请调用 send(from: Item.ItemRole, text: String, response: Response.Config? = nil)
,提供发送者的角色(.user
,.assistant
或 .system
)和消息的内容。您可以选择性地提供 Response.Config
对象来自定义响应,例如启用或禁用函数调用。
要手动发送音频消息(或其中的一部分),请使用有效的音频块调用 send(audioDelta: Data, commit: Bool = false)
。如果 commit
为 true
,模型将认为消息已完成并开始响应它。否则,它可能会等待更多音频,具体取决于您的 Session.turnDetection
设置。
要手动发送事件到 API,请使用 send(event: RealtimeAPI.ClientEvent)
方法。请注意,这绕过了 Conversation
类中的一些逻辑,例如处理中断,因此您应该尽可能优先使用其他方法。
要直接与 API 交互,请创建 RealtimeAPI
的新实例,并提供可用的连接器之一。有一些辅助方法可以让您从 apiKey 或 URLRequest
创建实例,如下所示
let api = RealtimeAPI.webSocket(authToken: YOUR_OPENAI_API_KEY, model: String = "gpt-4o-realtime-preview") // or RealtimeAPI.webSocket(connectingTo: URLRequest)
let api = RealtimeAPI.webRTC(authToken: YOUR_OPENAI_API_KEY, model: String = "gpt-4o-realtime-preview") // or RealtimeAPI.webRTC(connectingTo: URLRequest)
您可以通过 events
属性监听新事件,如下所示
for try await event in api.events {
switch event {
case let .sessionCreated(event):
print(event.session.id)
}
}
要发送事件到 API,请使用 ClientEvent
实例调用 send
方法
try await api.send(event: .updateSession(session))
try await api.send(event: .appendInputAudioBuffer(encoding: audioData))
try await api.send(event: .createResponse())
本项目根据 MIT 许可证获得许可 - 有关详细信息,请参阅 LICENSE 文件。