From 97a535fc78c37fee956ad3fc79061480d51e07e8 Mon Sep 17 00:00:00 2001 From: Buseong Kim Date: Sun, 16 Nov 2025 22:05:10 +0900 Subject: [PATCH 1/6] Remove Unused Combine Remove unused combine dependency --- Sources/Hub/Downloader.swift | 3 +-- Sources/Hub/HubApi.swift | 5 ++--- Tests/HubTests/DownloaderTests.swift | 1 - 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Sources/Hub/Downloader.swift b/Sources/Hub/Downloader.swift index 173c2dca..40087a64 100644 --- a/Sources/Hub/Downloader.swift +++ b/Sources/Hub/Downloader.swift @@ -6,7 +6,6 @@ // See LICENSE at https://github.com/huggingface/swift-coreml-diffusers/LICENSE // -import Combine import Foundation /// A robust file downloader with support for resumable downloads and progress reporting. @@ -14,7 +13,7 @@ import Foundation /// The Downloader class handles file downloads from remote URLs with features including /// automatic resume capability, progress tracking, speed monitoring, and retry mechanisms. /// It supports both foreground and background download sessions for different use cases. -final class Downloader: NSObject, Sendable, ObservableObject { +final class Downloader: NSObject, Sendable { private let destination: URL private let incompleteDestination: URL private let downloadResumeState: DownloadResumeState = .init() diff --git a/Sources/Hub/HubApi.swift b/Sources/Hub/HubApi.swift index 7fd54baa..27a27d79 100644 --- a/Sources/Hub/HubApi.swift +++ b/Sources/Hub/HubApi.swift @@ -491,9 +491,8 @@ public extension HubApi { } } - /// Note we go from Combine in Downloader to callback-based progress reporting - /// We'll probably need to support Combine as well to play well with Swift UI - /// (See for example PipelineLoader in swift-coreml-diffusers) + /// Downloader emits progress over AsyncStream which we bridge here to a simple callback. + /// A Combine wrapper can be layered on top when needed for SwiftUI-style progress reporting. @discardableResult func download(progressHandler: @escaping (Double, Double?) -> Void) async throws -> URL { let localMetadata = try hub.readDownloadMetadata(metadataPath: metadataDestination) diff --git a/Tests/HubTests/DownloaderTests.swift b/Tests/HubTests/DownloaderTests.swift index 552fbf3e..eed64ae4 100644 --- a/Tests/HubTests/DownloaderTests.swift +++ b/Tests/HubTests/DownloaderTests.swift @@ -5,7 +5,6 @@ // Created by Arda Atahan Ibis on 1/28/25. // -import Combine import XCTest @testable import Hub From 75afcce60b590742956876c4edeba07cf75eb098 Mon Sep 17 00:00:00 2001 From: Buseong Kim Date: Sun, 16 Nov 2025 22:22:17 +0900 Subject: [PATCH 2/6] Replace CryptoKit to swift-crypto --- Package.swift | 13 +++++++++++-- Sources/Hub/HubApi.swift | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Package.swift b/Package.swift index fb69f9f3..cd3249f1 100644 --- a/Package.swift +++ b/Package.swift @@ -17,11 +17,20 @@ let package = Package( .library(name: "Transformers", targets: ["Tokenizers", "Generation", "Models"]), ], dependencies: [ - .package(url: "https://github.com/huggingface/swift-jinja.git", from: "2.0.0") + .package(url: "https://github.com/huggingface/swift-jinja.git", from: "2.0.0"), + .package(url: "https://github.com/apple/swift-crypto.git", from: "4.1.0") ], targets: [ .target(name: "Generation", dependencies: ["Tokenizers"]), - .target(name: "Hub", dependencies: [.product(name: "Jinja", package: "swift-jinja")], resources: [.process("Resources")], swiftSettings: swiftSettings), + .target( + name: "Hub", + dependencies: [ + .product(name: "Jinja", package: "swift-jinja"), + .product(name: "Crypto", package: "swift-crypto") + ], + resources: [.process("Resources")], + swiftSettings: swiftSettings + ), .target(name: "Models", dependencies: ["Tokenizers", "Generation"]), .target(name: "Tokenizers", dependencies: ["Hub", .product(name: "Jinja", package: "swift-jinja")]), .testTarget(name: "GenerationTests", dependencies: ["Generation"]), diff --git a/Sources/Hub/HubApi.swift b/Sources/Hub/HubApi.swift index 27a27d79..81100c44 100644 --- a/Sources/Hub/HubApi.swift +++ b/Sources/Hub/HubApi.swift @@ -5,7 +5,7 @@ // Created by Pedro Cuenca on 20231230. // -import CryptoKit +import Crypto import Foundation import Network import os From c0d20741393d5f52f85a95d373efefe6414ba47c Mon Sep 17 00:00:00 2001 From: Buseong Kim Date: Sun, 16 Nov 2025 22:41:01 +0900 Subject: [PATCH 3/6] Update commnet Co-authored-by: Mattt --- Sources/Hub/HubApi.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Sources/Hub/HubApi.swift b/Sources/Hub/HubApi.swift index 81100c44..ead8f736 100644 --- a/Sources/Hub/HubApi.swift +++ b/Sources/Hub/HubApi.swift @@ -491,8 +491,9 @@ public extension HubApi { } } - /// Downloader emits progress over AsyncStream which we bridge here to a simple callback. - /// A Combine wrapper can be layered on top when needed for SwiftUI-style progress reporting. + /// Downloads the file with progress tracking. + /// - Parameter progressHandler: Closure called periodically with completion percentage (0.0-1.0) and optional download speed in bytes/sec. + /// - Returns: Local file URL. Returns cached file immediately if already downloaded and up-to-date. @discardableResult func download(progressHandler: @escaping (Double, Double?) -> Void) async throws -> URL { let localMetadata = try hub.readDownloadMetadata(metadataPath: metadataDestination) From 60fd9048c92e1a000651497e8c64677b3c1262ed Mon Sep 17 00:00:00 2001 From: Buseong Kim Date: Sun, 16 Nov 2025 22:42:15 +0900 Subject: [PATCH 4/6] Revert commit to separate PR Replace CryptoKit --- Package.swift | 13 ++----------- Sources/Hub/HubApi.swift | 2 +- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/Package.swift b/Package.swift index cd3249f1..fb69f9f3 100644 --- a/Package.swift +++ b/Package.swift @@ -17,20 +17,11 @@ let package = Package( .library(name: "Transformers", targets: ["Tokenizers", "Generation", "Models"]), ], dependencies: [ - .package(url: "https://github.com/huggingface/swift-jinja.git", from: "2.0.0"), - .package(url: "https://github.com/apple/swift-crypto.git", from: "4.1.0") + .package(url: "https://github.com/huggingface/swift-jinja.git", from: "2.0.0") ], targets: [ .target(name: "Generation", dependencies: ["Tokenizers"]), - .target( - name: "Hub", - dependencies: [ - .product(name: "Jinja", package: "swift-jinja"), - .product(name: "Crypto", package: "swift-crypto") - ], - resources: [.process("Resources")], - swiftSettings: swiftSettings - ), + .target(name: "Hub", dependencies: [.product(name: "Jinja", package: "swift-jinja")], resources: [.process("Resources")], swiftSettings: swiftSettings), .target(name: "Models", dependencies: ["Tokenizers", "Generation"]), .target(name: "Tokenizers", dependencies: ["Hub", .product(name: "Jinja", package: "swift-jinja")]), .testTarget(name: "GenerationTests", dependencies: ["Generation"]), diff --git a/Sources/Hub/HubApi.swift b/Sources/Hub/HubApi.swift index ead8f736..0cd5f560 100644 --- a/Sources/Hub/HubApi.swift +++ b/Sources/Hub/HubApi.swift @@ -5,7 +5,7 @@ // Created by Pedro Cuenca on 20231230. // -import Crypto +import CryptoKit import Foundation import Network import os From 6a74e1f57e06532392a332de94ef6575be95aece Mon Sep 17 00:00:00 2001 From: Buseong Kim Date: Sun, 16 Nov 2025 22:44:58 +0900 Subject: [PATCH 5/6] Update comment to pass Lint --- Sources/Hub/HubApi.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Sources/Hub/HubApi.swift b/Sources/Hub/HubApi.swift index 0cd5f560..5b0436f3 100644 --- a/Sources/Hub/HubApi.swift +++ b/Sources/Hub/HubApi.swift @@ -494,6 +494,8 @@ public extension HubApi { /// Downloads the file with progress tracking. /// - Parameter progressHandler: Closure called periodically with completion percentage (0.0-1.0) and optional download speed in bytes/sec. /// - Returns: Local file URL. Returns cached file immediately if already downloaded and up-to-date. + /// - Throws: ``EnvironmentError`` when metadata validation fails or the download cannot start, and any error + /// bubbled up from ``Downloader`` during transfer (including cancellation). @discardableResult func download(progressHandler: @escaping (Double, Double?) -> Void) async throws -> URL { let localMetadata = try hub.readDownloadMetadata(metadataPath: metadataDestination) From 7edf3acb98d8e6a5b0d44c9afb8360c74f24eb43 Mon Sep 17 00:00:00 2001 From: Buseong Kim Date: Sun, 16 Nov 2025 23:11:25 +0900 Subject: [PATCH 6/6] Update comments for details Co-authored-by: Mattt --- Sources/Hub/HubApi.swift | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Sources/Hub/HubApi.swift b/Sources/Hub/HubApi.swift index 5b0436f3..3a4d8a04 100644 --- a/Sources/Hub/HubApi.swift +++ b/Sources/Hub/HubApi.swift @@ -492,10 +492,9 @@ public extension HubApi { } /// Downloads the file with progress tracking. - /// - Parameter progressHandler: Closure called periodically with completion percentage (0.0-1.0) and optional download speed in bytes/sec. - /// - Returns: Local file URL. Returns cached file immediately if already downloaded and up-to-date. - /// - Throws: ``EnvironmentError`` when metadata validation fails or the download cannot start, and any error - /// bubbled up from ``Downloader`` during transfer (including cancellation). + /// - Parameter progressHandler: Called with download progress (0.0-1.0) and speed in bytes/sec, if available. + /// - Returns: Local file URL (uses cached file if commit hash matches). + /// - Throws: ``EnvironmentError`` errors for file and metadata validation failures, ``Downloader.DownloadError`` errors during transfer, or ``CancellationError`` if the task is cancelled. @discardableResult func download(progressHandler: @escaping (Double, Double?) -> Void) async throws -> URL { let localMetadata = try hub.readDownloadMetadata(metadataPath: metadataDestination)