Skip to content

Commit

Permalink
refactor: removes Alamofire from chat and generate (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinhermawan authored Jun 8, 2024
1 parent b6d5444 commit 5bc64cf
Show file tree
Hide file tree
Showing 12 changed files with 145 additions and 246 deletions.
8 changes: 4 additions & 4 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
// swift-tools-version: 5.7
// swift-tools-version: 5.9
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "OllamaKit",
platforms: [
.iOS(.v13),
.macOS(.v11),
.macCatalyst(.v13)
.iOS(.v15),
.macOS(.v13),

This comment has been minimized.

Copy link
@longseespace

longseespace Jul 19, 2024

Any idea why it requires macOS 13 now @kevinhermawan? This is a breaking change for me 😅

This comment has been minimized.

Copy link
@kevinhermawan

kevinhermawan Jul 19, 2024

Author Owner

Hi @longseespace, I'm using bytes(from:delegate:), which requires macOS 12. We can't set the minimum macOS version to 11, but it's still working on macOS 12. Should I downgrade the minimum requirement to macOS 12?

This comment has been minimized.

Copy link
@longseespace

longseespace Jul 19, 2024

Yes. I only need macOS 12 support

This comment has been minimized.

Copy link
@kevinhermawan

kevinhermawan Jul 19, 2024

Author Owner

This comment has been minimized.

Copy link
@longseespace

longseespace Jul 19, 2024

Awesome work. Thank you 🙏

.macCatalyst(.v15)
],
products: [
.library(
Expand Down
66 changes: 12 additions & 54 deletions Sources/OllamaKit/OllamaKit+Chat.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
// Created by Kevin Hermawan on 02/01/24.
//

import Alamofire
import Combine
import Foundation

Expand All @@ -32,32 +31,13 @@ extension OllamaKit {
/// - Parameter data: The ``OKChatRequestData`` used to initiate the chat streaming from the Ollama API.
/// - Returns: An `AsyncThrowingStream<OKChatResponse, Error>` emitting the live stream of chat responses from the Ollama API.
public func chat(data: OKChatRequestData) -> AsyncThrowingStream<OKChatResponse, Error> {
AsyncThrowingStream { continuation in
let request = AF.streamRequest(router.chat(data: data)).validate()
var buffer = Data()
do {
let request = try OKRouter.chat(data: data).asURLRequest()

request.responseStream { stream in
switch stream.event {
case .stream(let result):
switch result {
case .success(let data):
buffer.append(data)

while let chunk = extractNextJSON(from: &buffer) {
do {
let response = try decoder.decode(OKChatResponse.self, from: chunk)
continuation.yield(response)
} catch {
continuation.finish(throwing: error)
return
}
}
case .failure(let error):
continuation.finish(throwing: error)
}
case .complete(_):
continuation.finish()
}
return OKHTTPClient.shared.stream(request: request, with: OKChatResponse.self)
} catch {
return AsyncThrowingStream { continuation in
continuation.finish(throwing: error)
}
}
}
Expand All @@ -82,34 +62,12 @@ extension OllamaKit {
/// - Parameter data: The ``OKChatRequestData`` used to initiate the chat streaming from the Ollama API.
/// - Returns: An `AnyPublisher<OKChatResponse, Error>` emitting the live stream of chat responses from the Ollama API.
public func chat(data: OKChatRequestData) -> AnyPublisher<OKChatResponse, Error> {
let subject = PassthroughSubject<OKChatResponse, Error>()
let request = AF.streamRequest(router.chat(data: data)).validate()
var buffer = Data()

request.responseStream { stream in
switch stream.event {
case .stream(let result):
switch result {
case .success(let data):
buffer.append(data)

while let chunk = extractNextJSON(from: &buffer) {
do {
let response = try decoder.decode(OKChatResponse.self, from: chunk)
subject.send(response)
} catch {
subject.send(completion: .failure(error))
return
}
}
case .failure(let error):
subject.send(completion: .failure(error))
}
case .complete(_):
subject.send(completion: .finished)
}
do {
let request = try OKRouter.chat(data: data).asURLRequest()

return OKHTTPClient.shared.stream(request: request, with: OKChatResponse.self)
} catch {
return Fail(error: error).eraseToAnyPublisher()
}

return subject.eraseToAnyPublisher()
}
}
4 changes: 2 additions & 2 deletions Sources/OllamaKit/OllamaKit+CopyModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ extension OllamaKit {
public func copyModel(data: OKCopyModelRequestData) async throws -> Void {
let request = try OKRouter.copyModel(data: data).asURLRequest()

try await OKHTTPClient.shared.sendRequest(for: request)
try await OKHTTPClient.shared.send(request: request)
}

/// Requests the Ollama API to copy a model, returning the result as a Combine publisher.
Expand All @@ -50,7 +50,7 @@ extension OllamaKit {
do {
let request = try OKRouter.copyModel(data: data).asURLRequest()

return OKHTTPClient.shared.sendRequest(for: request)
return OKHTTPClient.shared.send(request: request)
} catch {
return Fail(error: error).eraseToAnyPublisher()
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/OllamaKit/OllamaKit+DeleteModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ extension OllamaKit {
public func deleteModel(data: OKDeleteModelRequestData) async throws -> Void {
let request = try OKRouter.deleteModel(data: data).asURLRequest()

try await OKHTTPClient.shared.sendRequest(for: request)
try await OKHTTPClient.shared.send(request: request)
}

/// Requests the Ollama API to delete a specific model, returning the result as a Combine publisher.
Expand All @@ -50,7 +50,7 @@ extension OllamaKit {
do {
let request = try OKRouter.deleteModel(data: data).asURLRequest()

return OKHTTPClient.shared.sendRequest(for: request)
return OKHTTPClient.shared.send(request: request)
} catch {
return Fail(error: error).eraseToAnyPublisher()
}
Expand Down
6 changes: 3 additions & 3 deletions Sources/OllamaKit/OllamaKit+Embeddings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ extension OllamaKit {
public func embeddings(data: OKEmbeddingsRequestData) async throws -> OKEmbeddingsResponse {
let request = try OKRouter.embeddings(data: data).asURLRequest()

return try await OKHTTPClient.shared.sendRequest(for: request, with: OKEmbeddingsResponse.self)
return try await OKHTTPClient.shared.send(request: request, with: OKEmbeddingsResponse.self)
}

/// Retrieves embeddings from a specific model from the Ollama API as a Combine publisher.
Expand All @@ -46,12 +46,12 @@ extension OllamaKit {
/// ```
///
/// - Parameter data: The ``OKEmbeddingsRequestData`` used to query the API for embeddings from a specific model.
/// - Returns: A `AnyPublisher<OKEmbeddingsResponse, AFError>` that emits embeddings.
/// - Returns: A `AnyPublisher<OKEmbeddingsResponse, Error>` that emits embeddings.
public func embeddings(data: OKEmbeddingsRequestData) -> AnyPublisher<OKEmbeddingsResponse, Error> {
do {
let request = try OKRouter.embeddings(data: data).asURLRequest()

return OKHTTPClient.shared.sendRequest(for: request, with: OKEmbeddingsResponse.self)
return OKHTTPClient.shared.send(request: request, with: OKEmbeddingsResponse.self)
} catch {
return Fail(error: error).eraseToAnyPublisher()
}
Expand Down
66 changes: 12 additions & 54 deletions Sources/OllamaKit/OllamaKit+Generate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
// Created by Kevin Hermawan on 02/01/24.
//

import Alamofire
import Combine
import Foundation

Expand All @@ -32,32 +31,13 @@ extension OllamaKit {
/// - Parameter data: The ``OKGenerateRequestData`` used to initiate the streaming from the Ollama API.
/// - Returns: An `AsyncThrowingStream<OKGenerateResponse, Error>` emitting the live stream of responses from the Ollama API.
public func generate(data: OKGenerateRequestData) -> AsyncThrowingStream<OKGenerateResponse, Error> {
AsyncThrowingStream { continuation in
let request = AF.streamRequest(router.generate(data: data)).validate()
var buffer = Data()
do {
let request = try OKRouter.generate(data: data).asURLRequest()

request.responseStream { stream in
switch stream.event {
case .stream(let result):
switch result {
case .success(let data):
buffer.append(data)

while let chunk = extractNextJSON(from: &buffer) {
do {
let response = try decoder.decode(OKGenerateResponse.self, from: chunk)
continuation.yield(response)
} catch {
continuation.finish(throwing: error)
return
}
}
case .failure(let error):
continuation.finish(throwing: error)
}
case .complete(_):
continuation.finish()
}
return OKHTTPClient.shared.stream(request: request, with: OKGenerateResponse.self)
} catch {
return AsyncThrowingStream { continuation in
continuation.finish(throwing: error)
}
}
}
Expand All @@ -82,34 +62,12 @@ extension OllamaKit {
/// - Parameter data: The ``OKGenerateRequestData`` used to initiate the streaming from the Ollama API.
/// - Returns: An `AnyPublisher<OKGenerateResponse, Error>` emitting the live stream of responses from the Ollama API.
public func generate(data: OKGenerateRequestData) -> AnyPublisher<OKGenerateResponse, Error> {
let subject = PassthroughSubject<OKGenerateResponse, Error>()
let request = AF.streamRequest(router.generate(data: data)).validate()
var buffer = Data()

request.responseStream { stream in
switch stream.event {
case .stream(let result):
switch result {
case .success(let data):
buffer.append(data)

while let chunk = extractNextJSON(from: &buffer) {
do {
let response = try decoder.decode(OKGenerateResponse.self, from: chunk)
subject.send(response)
} catch {
subject.send(completion: .failure(error))
return
}
}
case .failure(let error):
subject.send(completion: .failure(error))
}
case .complete(_):
subject.send(completion: .finished)
}
do {
let request = try OKRouter.generate(data: data).asURLRequest()

return OKHTTPClient.shared.stream(request: request, with: OKGenerateResponse.self)
} catch {
return Fail(error: error).eraseToAnyPublisher()
}

return subject.eraseToAnyPublisher()
}
}
4 changes: 2 additions & 2 deletions Sources/OllamaKit/OllamaKit+ModelInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ extension OllamaKit {
public func modelInfo(data: OKModelInfoRequestData) async throws -> OKModelInfoResponse {
let request = try OKRouter.modelInfo(data: data).asURLRequest()

return try await OKHTTPClient.shared.sendRequest(for: request, with: OKModelInfoResponse.self)
return try await OKHTTPClient.shared.send(request: request, with: OKModelInfoResponse.self)
}

/// Retrieves detailed information for a specific model from the Ollama API as a Combine publisher.
Expand All @@ -51,7 +51,7 @@ extension OllamaKit {
do {
let request = try OKRouter.modelInfo(data: data).asURLRequest()

return OKHTTPClient.shared.sendRequest(for: request, with: OKModelInfoResponse.self)
return OKHTTPClient.shared.send(request: request, with: OKModelInfoResponse.self)
} catch {
return Fail(error: error).eraseToAnyPublisher()
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/OllamaKit/OllamaKit+Models.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ extension OllamaKit {
public func models() async throws -> OKModelResponse {
let request = try OKRouter.models.asURLRequest()

return try await OKHTTPClient.shared.sendRequest(for: request, with: OKModelResponse.self)
return try await OKHTTPClient.shared.send(request: request, with: OKModelResponse.self)
}

/// Retrieves a list of available models from the Ollama API as a Combine publisher.
Expand All @@ -47,7 +47,7 @@ extension OllamaKit {
do {
let request = try OKRouter.models.asURLRequest()

return OKHTTPClient.shared.sendRequest(for: request, with: OKModelResponse.self)
return OKHTTPClient.shared.send(request: request, with: OKModelResponse.self)
} catch {
return Fail(error: error).eraseToAnyPublisher()
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/OllamaKit/OllamaKit+Reachable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ extension OllamaKit {
public func reachable() async -> Bool {
do {
let request = try OKRouter.root.asURLRequest()
try await OKHTTPClient.shared.sendRequest(for: request)
try await OKHTTPClient.shared.send(request: request)

return true
} catch {
Expand All @@ -49,7 +49,7 @@ extension OllamaKit {
do {
let request = try OKRouter.root.asURLRequest()

return OKHTTPClient.shared.sendRequest(for: request)
return OKHTTPClient.shared.send(request: request)
.map { _ in true }
.replaceError(with: false)
.eraseToAnyPublisher()
Expand Down
40 changes: 0 additions & 40 deletions Sources/OllamaKit/OllamaKit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,44 +38,4 @@ public struct OllamaKit {

self.router = router
}

internal func extractNextJSON(from buffer: inout Data) -> Data? {
var isEscaped = false
var isWithinString = false
var nestingDepth = 0
var objectStartIndex = buffer.startIndex

for (index, byte) in buffer.enumerated() {
let character = Character(UnicodeScalar(byte))

if isEscaped {
isEscaped = false
} else if character == "\\" {
isEscaped = true
} else if character == "\"" {
isWithinString.toggle()
} else if !isWithinString {
switch character {
case "{":
nestingDepth += 1
if nestingDepth == 1 {
objectStartIndex = index
}
case "}":
nestingDepth -= 1
if nestingDepth == 0 {
let range = objectStartIndex..<buffer.index(after: index)
let jsonObject = buffer.subdata(in: range)
buffer.removeSubrange(range)

return jsonObject
}
default:
break
}
}
}

return nil
}
}
Loading

0 comments on commit 5bc64cf

Please sign in to comment.