Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions Sources/Core/Models/Item.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,14 @@ import MetaCodable
case text(String)
case audio(Audio)
case inputText(String)
case inputImage(String)
case inputAudio(Audio)

public var text: String? {
switch self {
case let .text(text): text
case let .inputText(text): text
case let .inputImage(image): image
case let .audio(audio): audio.transcript
case let .inputAudio(audio): audio.transcript
}
Expand Down Expand Up @@ -419,6 +421,7 @@ extension Item.Message.Content: Codable {
case text
case audio
case transcript
case image_url
}

private struct Text: Codable {
Expand All @@ -440,7 +443,10 @@ extension Item.Message.Content: Codable {
case "input_text":
let container = try decoder.container(keyedBy: Text.CodingKeys.self)
self = try .inputText(container.decode(String.self, forKey: .text))
case "output_audio":
case "input_image":
let inner = try decoder.container(keyedBy: CodingKeys.self)
self = try .inputImage(inner.decodeIfPresent(String.self, forKey: .image_url) ?? "")
case "output_audio":
self = try .audio(Item.Audio(from: decoder))
case "input_audio":
self = try .inputAudio(Item.Audio(from: decoder))
Expand All @@ -459,7 +465,10 @@ extension Item.Message.Content: Codable {
case let .inputText(text):
try container.encode(text, forKey: .text)
try container.encode("input_text", forKey: .type)
case let .audio(audio):
case let .inputImage(imageURL):
try container.encode(imageURL, forKey: .image_url)
try container.encode("input_image", forKey: .type)
case let .audio(audio):
try container.encode("output_audio", forKey: .type)
try container.encode(audio.audio, forKey: .audio)
try container.encode(audio.transcript, forKey: .transcript)
Expand Down
23 changes: 19 additions & 4 deletions Sources/UI/Conversation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public enum ConversationError: Error {
public final class Conversation: @unchecked Sendable {
public typealias SessionUpdateCallback = (inout Session) -> Void

private let client: WebRTCConnector
private let client: WebRTCConnector
private var task: Task<Void, Error>!
private let sessionUpdateCallback: SessionUpdateCallback?
private let errorStream: AsyncStream<ServerError>.Continuation
Expand Down Expand Up @@ -152,11 +152,25 @@ public final class Conversation: @unchecked Sendable {
/// Send a text message and wait for a response.
/// Optionally, you can provide a response configuration to customize the model's behavior.
public func send(from role: Item.Message.Role, text: String, response: Response.Config? = nil) throws {
try send(event: .createConversationItem(.message(Item.Message(id: String(randomLength: 32), role: role, content: [.inputText(text)]))))
let id = UUID().uuidString.replacingOccurrences(of: "-", with: "") // random 32 character string
try send(event: .createConversationItem(.message(Item.Message(id: id, role: role, content: [.inputText(text)]))))
try send(event: .createResponse(using: response))
}

/// Send the response of a function call.
/// Send an image + text message and wait for a response.
public func send(from role: Item.Message.Role, image: Data, response: Response.Config? = nil) throws {
let dataURI = "data:image/jpeg;base64,\(image.base64EncodedString())"
let id = UUID().uuidString.replacingOccurrences(of: "-", with: "") // random 32 character string
let message = Item.Message(
id: id,
role: role,
content: [.inputImage(dataURI)]
)
try send(event: .createConversationItem(.message(message)))
try send(event: .createResponse(using: response))
}

/// Send the response of a function call.
public func send(result output: Item.FunctionCallOutput) throws {
try send(event: .createConversationItem(.functionCallOutput(output)))
}
Expand All @@ -176,7 +190,8 @@ private extension Conversation {
if let sessionUpdateCallback { try updateSession(withChanges: sessionUpdateCallback) }
case let .sessionUpdated(_, session):
self.session = session
case let .conversationItemCreated(_, item, _):
case let .conversationItemCreated(_, item, _),
let .conversationItemAdded(_, item, _):
entries.append(item)
case let .conversationItemDeleted(_, itemId):
entries.removeAll { $0.id == itemId }
Expand Down
8 changes: 0 additions & 8 deletions Sources/UI/Extensions/String+random.swift

This file was deleted.