Skip to content

Commit

Permalink
Add support to pull model from library (#39)
Browse files Browse the repository at this point in the history
* add pullModel method to download model from ollama library

* add details to `OKModelResponse`
  • Loading branch information
lukepistrol authored Nov 25, 2024
1 parent f947524 commit 4620016
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 0 deletions.
78 changes: 78 additions & 0 deletions Sources/OllamaKit/OllamaKit+PullModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//
// OllamaKit+PullModel.swift
//
//
// Created by Lukas Pistrol on 25.11.24.
//

import Combine
import Foundation

extension OllamaKit {
/// Establishes an asynchronous stream for pulling a model from the ollama library.
///
/// This method will periodically yield ``OKPullModelResponse`` structures as the model is being pulled.
/// Depending on the size of the model and the speed of the internet connection, this process may take a while.
/// The stream will complete once the model has been fully pulled.
///
/// ```swift
/// let ollamaKit = OllamaKit()
/// let reqData = OKPullModelRequestData(model: "llama3.2")
///
/// for try await response in ollamaKit.pullModel(data: reqData) {
/// print(response.status)
/// if let progress = response.completed, let total = response.total {
/// print("Progress: \(progress)/\(total) bytes")
/// }
/// }
/// ```
///
/// - Parameter data: The ``OKPullModelRequestData`` used to initiate the chat streaming from the ollama library.
/// - Returns: An asynchronous stream that emits ``OKPullModelResponse``.
public func pullModel(data: OKPullModelRequestData) -> AsyncThrowingStream<OKPullModelResponse, Error> {
do {
let request = try OKRouter.pullModel(data: data).asURLRequest()

return OKHTTPClient.shared.stream(request: request, with: OKPullModelResponse.self)
} catch {
return AsyncThrowingStream { continuation in
continuation.finish(throwing: error)
}
}
}

/// Establishes a Combine publisher for pulling a model from the ollama library.
///
/// This method will periodically yield ``OKPullModelResponse`` structures as the model is being pulled.
/// Depending on the size of the model and the speed of the internet connection, this process may take a while.
/// The stream will complete once the model has been fully pulled.
///
/// ```swift
/// let ollamaKit = OllamaKit()
/// let reqData = OKPullModelRequestData(model: "llama3.2")
///
/// ollamaKit.pullModel(data: reqData)
/// .sink { completion in
/// // Handle completion
/// } receiveValue: { response in
/// print(response.status)
/// if let progress = response.completed, let total = response.total {
/// print("Progress: \(progress)/\(total) bytes")
/// }
/// }
/// }
/// ```
///
/// - Parameter data: The ``OKPullModelRequestData`` used to initiate the chat streaming from the ollama library.
/// - Returns: A combine publisher that emits ``OKPullModelResponse``.
public func pullModel(data: OKPullModelRequestData) -> AnyPublisher<OKPullModelResponse, Error> {
do {
let request = try OKRouter.pullModel(data: data).asURLRequest()

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

}
22 changes: 22 additions & 0 deletions Sources/OllamaKit/RequestData/OKPullModelRequestData.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// OKPullModelRequestData.swift
//
//
// Created by Lukas Pistrol on 25.11.24.
//

import Foundation

/// A structure that encapsulates the data necessary for pulling a new model from the ollama library using the Ollama API.
public struct OKPullModelRequestData: Encodable {
private let stream: Bool

/// A string representing the identifier of the model for which information is requested.
public let model: String

public init(model: String) {
self.stream = true
self.model = model
}
}

21 changes: 21 additions & 0 deletions Sources/OllamaKit/Responses/OKModelResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,26 @@ public struct OKModelResponse: Decodable {

/// A `Date` representing the last modification date of the model.
public let modifiedAt: Date

/// The details about the model.
public let details: ModelDetails

/// A structure that represents the details of the model.
public struct ModelDetails: Decodable {
/// The format of the model. E.g. "gguf".
public let format: String

/// The family of the model. E.g. "llama".
public let family: String

/// The parameter size of the model. E.g. "8.0B".
public let parameterSize: String

/// The quantization level of the model. E.g. "Q4_0".
public let quantizationLevel: String

/// All the families of the model. E.g. ["llama", "phi3"].
public let families: [String]?
}
}
}
23 changes: 23 additions & 0 deletions Sources/OllamaKit/Responses/OKPullModelResponse.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// OKPullModelResponse.swift
//
//
// Created by Lukas Pistrol on 25.11.24.
//

import Foundation

/// The response model for pulling a new model from the ollama library.
public struct OKPullModelResponse: Decodable {
/// The current status.
public let status: String

/// The digest hash of the current file.
public let digest: String?

/// The size of the current file.
public let total: Int?

/// The number of bytes that have been completed.
public let completed: Int?
}
7 changes: 7 additions & 0 deletions Sources/OllamaKit/Utils/OKRouter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ internal enum OKRouter {
case chat(data: OKChatRequestData)
case copyModel(data: OKCopyModelRequestData)
case deleteModel(data: OKDeleteModelRequestData)
case pullModel(data: OKPullModelRequestData)
case embeddings(data: OKEmbeddingsRequestData)

internal var path: String {
Expand All @@ -35,6 +36,8 @@ internal enum OKRouter {
return "/api/copy"
case .deleteModel:
return "/api/delete"
case .pullModel:
return "/api/pull"
case .embeddings:
return "/api/embeddings"
}
Expand All @@ -56,6 +59,8 @@ internal enum OKRouter {
return "POST"
case .deleteModel:
return "DELETE"
case .pullModel:
return "POST"
case .embeddings:
return "POST"
}
Expand Down Expand Up @@ -85,6 +90,8 @@ extension OKRouter {
request.httpBody = try JSONEncoder.default.encode(data)
case .deleteModel(let data):
request.httpBody = try JSONEncoder.default.encode(data)
case .pullModel(let data):
request.httpBody = try JSONEncoder.default.encode(data)
case .embeddings(let data):
request.httpBody = try JSONEncoder.default.encode(data)
default:
Expand Down

0 comments on commit 4620016

Please sign in to comment.