Skip to content

Commit

Permalink
feat: adds reactive implementation for all APIs (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinhermawan authored Jan 2, 2024
1 parent 080f0f4 commit b4d1fc5
Show file tree
Hide file tree
Showing 11 changed files with 413 additions and 217 deletions.
7 changes: 7 additions & 0 deletions Sources/Documentation.docc/Documentation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# ``OllamaKit``

A Swift library for interacting with the Ollama API.

## Overview

``OllamaKit`` is a Swift-based library crafted to streamline interactions with the Ollama API. It encapsulates the complexities of network communication and data processing, providing a simplified and efficient interface for Swift applications to communicate with the Ollama API.
51 changes: 51 additions & 0 deletions Sources/OllamaKit/OllamaKit+Chat.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//
// OllamaKit+Chat.swift
//
//
// Created by Kevin Hermawan on 02/01/24.
//

import Alamofire
import Combine
import Foundation

extension OllamaKit {
/// Establishes a Combine publisher for streaming chat responses from the Ollama API, based on the provided data.
///
/// This method sets up a streaming connection using the Combine framework, facilitating real-time data handling as chat responses are generated by the Ollama API.
///
/// ```swift
/// let ollamaKit = OllamaKit(baseURL: URL(string: "http://localhost:11434")!)
/// let chatData = OKChatRequestData(/* parameters */)
///
/// ollamaKit.chat(data: chatData)
/// .sink(receiveCompletion: { completion in
/// // Handle completion or error
/// }, receiveValue: { chatResponse in
/// // Handle each chat response
/// })
/// .store(in: &cancellables)
/// ```
///
/// - Parameter data: The ``OKChatRequestData`` used to initiate the chat streaming from the Ollama API.
/// - Returns: An `AnyPublisher<OKChatResponse, AFError>` emitting the live stream of chat responses from the Ollama API.
public func chat(data: OKChatRequestData) -> AnyPublisher<OKChatResponse, AFError> {
return Future<OKChatResponse, AFError> { promise in
let request = AF.streamRequest(router.chat(data: data)).validate()

request.responseStreamDecodable(of: OKChatResponse.self, using: decoder) { stream in
switch stream.event {
case .stream(let result):
switch result {
case .success(let response):
promise(.success(response))
case .failure(let error):
promise(.failure(error))
}
case .complete(_):
break
}
}
}.eraseToAnyPublisher()
}
}
56 changes: 56 additions & 0 deletions Sources/OllamaKit/OllamaKit+CopyModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// OllamaKit+CopyModel.swift
//
//
// Created by Kevin Hermawan on 01/01/24.
//

import Alamofire
import Combine
import Foundation

extension OllamaKit {
/// Asynchronously requests the Ollama API to copy a model.
///
/// This method sends a request to the Ollama API to copy a model based on the provided ``OKCopyModelRequestData``.
///
/// ```swift
/// let ollamaKit = OllamaKit(baseURL: URL(string: "http://localhost:11434")!)
/// let requestData = OKCopyModelRequestData(/* parameters */)
/// try await ollamaKit.copyModel(data: requestData)
/// ```
///
/// - Parameter data: The ``OKCopyModelRequestData`` containing the details needed to copy the model.
/// - Throws: An error if the request to copy the model fails.
public func copyModel(data: OKCopyModelRequestData) async throws -> Void {
let request = AF.request(router.copyModel(data: data)).validate()
_ = try await request.serializingData().response.result.get()
}

/// Requests the Ollama API to copy a model, returning the result as a Combine publisher.
///
/// This method provides a reactive approach to request a model copy operation. It accepts ``OKCopyModelRequestData`` and returns a Combine publisher that completes when the copy operation is finished.
///
/// ```swift
/// let ollamaKit = OllamaKit(baseURL: URL(string: "http://localhost:11434")!)
/// let requestData = OKCopyModelRequestData(/* parameters */)
///
/// ollamaKit.copyModel(data: requestData)
/// .sink(receiveCompletion: { completion in
/// // Handle completion
/// }, receiveValue: {
/// // Handle successful completion of the copy operation
/// })
/// .store(in: &cancellables)
/// ```
///
/// - Parameter data: The ``OKCopyModelRequestData`` used to request the model copy.
/// - Returns: A `AnyPublisher<Void, Error>` that completes when the copy operation is done.
public func copyModel(data: OKCopyModelRequestData) -> AnyPublisher<Void, Error> {
let request = AF.request(router.copyModel(data: data)).validate()

return request.publishData()
.tryMap { _ in Void() }
.eraseToAnyPublisher()
}
}
56 changes: 56 additions & 0 deletions Sources/OllamaKit/OllamaKit+DeleteModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// OllamaKit+DeleteModel.swift
//
//
// Created by Kevin Hermawan on 01/01/24.
//

import Alamofire
import Combine
import Foundation

extension OllamaKit {
/// Asynchronously requests the Ollama API to delete a specific model.
///
/// This method sends a request to the Ollama API to delete a model based on the provided ``OKDeleteModelRequestData``.
///
/// ```swift
/// let ollamaKit = OllamaKit(baseURL: URL(string: "http://localhost:11434")!)
/// let requestData = OKDeleteModelRequestData(/* parameters */)
/// try await ollamaKit.deleteModel(data: requestData)
/// ```
///
/// - Parameter data: The ``OKDeleteModelRequestData`` containing the details needed to delete the model.
/// - Throws: An error if the request to delete the model fails.
public func deleteModel(data: OKDeleteModelRequestData) async throws -> Void {
let request = AF.request(router.deleteModel(data: data)).validate()
_ = try await request.serializingData().response.result.get()
}

/// Requests the Ollama API to delete a specific model, returning the result as a Combine publisher.
///
/// This method provides a reactive approach to request a model deletion operation. It accepts ``OKDeleteModelRequestData`` and returns a Combine publisher that completes when the deletion operation is finished.
///
/// ```swift
/// let ollamaKit = OllamaKit(baseURL: URL(string: "http://localhost:11434")!)
/// let requestData = OKDeleteModelRequestData(/* parameters */)
///
/// ollamaKit.deleteModel(data: requestData)
/// .sink(receiveCompletion: { completion in
/// // Handle completion
/// }, receiveValue: {
/// // Handle successful completion of the deletion operation
/// })
/// .store(in: &cancellables)
/// ```
///
/// - Parameter data: The ``OKDeleteModelRequestData`` used to request the model deletion.
/// - Returns: A `AnyPublisher<Void, Error>` that completes when the deletion operation is done.
public func deleteModel(data: OKDeleteModelRequestData) -> AnyPublisher<Void, Error> {
let request = AF.request(router.deleteModel(data: data)).validate()

return request.publishData()
.tryMap { _ in Void() }
.eraseToAnyPublisher()
}
}
51 changes: 51 additions & 0 deletions Sources/OllamaKit/OllamaKit+Generate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//
// OllamaKit+Generate.swift
//
//
// Created by Kevin Hermawan on 02/01/24.
//

import Alamofire
import Combine
import Foundation

extension OllamaKit {
/// Establishes a Combine publisher for streaming responses from the Ollama API, based on the provided data.
///
/// This method sets up a streaming connection using the Combine framework, allowing for real-time data handling as the responses are generated by the Ollama API.
///
/// ```swift
/// let ollamaKit = OllamaKit(baseURL: URL(string: "http://localhost:11434")!)
/// let requestData = OKGenerateRequestData(/* parameters */)
///
/// ollamaKit.generate(data: requestData)
/// .sink(receiveCompletion: { completion in
/// // Handle completion or error
/// }, receiveValue: { generateResponse in
/// // Handle each generated response
/// })
/// .store(in: &cancellables)
/// ```
///
/// - Parameter data: The ``OKGenerateRequestData`` used to initiate the streaming from the Ollama API.
/// - Returns: An `AnyPublisher<OKGenerateResponse, AFError>` emitting the live stream of responses from the Ollama API.
public func generate(data: OKGenerateRequestData) -> AnyPublisher<OKGenerateResponse, AFError> {
return Future<OKGenerateResponse, AFError> { promise in
let request = AF.streamRequest(router.generate(data: data)).validate()

request.responseStreamDecodable(of: OKGenerateResponse.self, using: decoder) { stream in
switch stream.event {
case .stream(let result):
switch result {
case .success(let response):
promise(.success(response))
case .failure(let error):
promise(.failure(error))
}
case .complete(_):
break
}
}
}.eraseToAnyPublisher()
}
}
60 changes: 60 additions & 0 deletions Sources/OllamaKit/OllamaKit+ModelInfo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// OllamaKit+ModelInfo.swift
//
//
// Created by Kevin Hermawan on 01/01/24.
//

import Alamofire
import Combine
import Foundation

extension OllamaKit {
/// Asynchronously retrieves detailed information for a specific model from the Ollama API.
///
/// This method accepts ``OKModelInfoRequestData`` and returns an ``OKModelInfoResponse`` containing detailed information about the requested model.
///
/// ```swift
/// let ollamaKit = OllamaKit(baseURL: URL(string: "http://localhost:11434")!)
/// let requestData = OKModelInfoRequestData(/* parameters */)
/// let modelInfo = try await ollamaKit.modelInfo(data: requestData)
/// ```
///
/// - Parameter data: The ``OKModelInfoRequestData`` used to query the API for specific model information.
/// - Returns: An ``OKModelInfoResponse`` containing detailed information about the model.
/// - Throws: An error if the request fails or the response can't be decoded.
public func modelInfo(data: OKModelInfoRequestData) async throws -> OKModelInfoResponse {
let request = AF.request(router.modelInfo(data: data)).validate()
let response = request.serializingDecodable(OKModelInfoResponse.self, decoder: decoder)
let value = try await response.value

return value
}

/// Retrieves detailed information for a specific model from the Ollama API as a Combine publisher.
///
/// This method provides a reactive approach to fetch detailed model information. It accepts ``OKModelInfoRequestData`` and returns a Combine publisher that emits an ``OKModelInfoResponse`` upon successful retrieval.
///
/// ```swift
/// let ollamaKit = OllamaKit(baseURL: URL(string: "http://localhost:11434")!)
/// let requestData = OKModelInfoRequestData(/* parameters */)
///
/// ollamaKit.modelInfo(data: requestData)
/// .sink(receiveCompletion: { completion in
/// // Handle completion
/// }, receiveValue: { modelInfoResponse in
/// // Handle the received model info response
/// })
/// .store(in: &cancellables)
/// ```
///
/// - Parameter data: The ``OKModelInfoRequestData`` used to query the API for specific model information.
/// - Returns: A `AnyPublisher<OKModelInfoResponse, AFError>` that emits detailed information about the model.
public func modelInfo(data: OKModelInfoRequestData) -> AnyPublisher<OKModelInfoResponse, AFError> {
let request = AF.request(router.modelInfo(data: data)).validate()

return request
.publishDecodable(type: OKModelInfoResponse.self, decoder: decoder).value()
.eraseToAnyPublisher()
}
}
56 changes: 56 additions & 0 deletions Sources/OllamaKit/OllamaKit+Models.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// OllamaKit+Models.swift
//
//
// Created by Kevin Hermawan on 01/01/24.
//

import Alamofire
import Combine
import Foundation

extension OllamaKit {
/// Asynchronously retrieves a list of available models from the Ollama API.
///
/// This method returns an ``OKModelResponse`` containing the details of the available models.
///
/// ```swift
/// let ollamaKit = OllamaKit(baseURL: URL(string: "http://localhost:11434")!)
/// let models = try await ollamaKit.models()
/// ```
///
/// - Returns: An ``OKModelResponse`` object listing the available models.
/// - Throws: An error if the request fails or the response can't be decoded.
public func models() async throws -> OKModelResponse {
let request = AF.request(router.models).validate()
let response = request.serializingDecodable(OKModelResponse.self, decoder: decoder)
let value = try await response.value

return value
}

/// Retrieves a list of available models from the Ollama API as a Combine publisher.
///
/// This method provides a reactive approach to fetch model data, returning a Combine publisher that emits an ``OKModelResponse`` with details of available models.
///
/// ```swift
/// let ollamaKit = OllamaKit(baseURL: URL(string: "http://localhost:11434")!)
///
/// ollamaKit.models()
/// .sink(receiveCompletion: { completion in
/// // Handle completion
/// }, receiveValue: { modelResponse in
/// // Handle the received model response
/// })
/// .store(in: &cancellables)
/// ```
///
/// - Returns: A `AnyPublisher<OKModelResponse, AFError>` that emits the list of available models.
public func models() -> AnyPublisher<OKModelResponse, AFError> {
let request = AF.request(router.models).validate()

return request
.publishDecodable(type: OKModelResponse.self, decoder: decoder).value()
.eraseToAnyPublisher()
}
}
Loading

0 comments on commit b4d1fc5

Please sign in to comment.