durable_huggingface_hub 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.editorconfig +29 -0
- data/.rubocop.yml +108 -0
- data/CHANGELOG.md +127 -0
- data/README.md +547 -0
- data/Rakefile +106 -0
- data/devenv.lock +171 -0
- data/devenv.nix +15 -0
- data/devenv.yaml +8 -0
- data/huggingface_hub.gemspec +63 -0
- data/lib/durable_huggingface_hub/authentication.rb +245 -0
- data/lib/durable_huggingface_hub/cache.rb +508 -0
- data/lib/durable_huggingface_hub/configuration.rb +191 -0
- data/lib/durable_huggingface_hub/constants.rb +145 -0
- data/lib/durable_huggingface_hub/errors.rb +412 -0
- data/lib/durable_huggingface_hub/file_download.rb +831 -0
- data/lib/durable_huggingface_hub/hf_api.rb +1278 -0
- data/lib/durable_huggingface_hub/repo_card.rb +430 -0
- data/lib/durable_huggingface_hub/types/cache_info.rb +298 -0
- data/lib/durable_huggingface_hub/types/commit_info.rb +149 -0
- data/lib/durable_huggingface_hub/types/dataset_info.rb +158 -0
- data/lib/durable_huggingface_hub/types/model_info.rb +154 -0
- data/lib/durable_huggingface_hub/types/space_info.rb +158 -0
- data/lib/durable_huggingface_hub/types/user.rb +179 -0
- data/lib/durable_huggingface_hub/types.rb +205 -0
- data/lib/durable_huggingface_hub/utils/auth.rb +174 -0
- data/lib/durable_huggingface_hub/utils/headers.rb +220 -0
- data/lib/durable_huggingface_hub/utils/http.rb +329 -0
- data/lib/durable_huggingface_hub/utils/paths.rb +230 -0
- data/lib/durable_huggingface_hub/utils/progress.rb +217 -0
- data/lib/durable_huggingface_hub/utils/retry.rb +165 -0
- data/lib/durable_huggingface_hub/utils/validators.rb +236 -0
- data/lib/durable_huggingface_hub/version.rb +8 -0
- data/lib/huggingface_hub.rb +205 -0
- metadata +334 -0
|
@@ -0,0 +1,1278 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "faraday"
|
|
4
|
+
require "faraday/multipart"
|
|
5
|
+
require_relative "constants"
|
|
6
|
+
require_relative "configuration"
|
|
7
|
+
require_relative "utils/http"
|
|
8
|
+
require_relative "utils/auth"
|
|
9
|
+
require_relative "utils/validators"
|
|
10
|
+
require_relative "types"
|
|
11
|
+
|
|
12
|
+
module DurableHuggingfaceHub
|
|
13
|
+
# Main API client for interacting with the HuggingFace Hub
|
|
14
|
+
#
|
|
15
|
+
# This class provides methods for accessing and managing repositories,
|
|
16
|
+
# models, datasets, and spaces on the HuggingFace Hub. It handles
|
|
17
|
+
# authentication, request management, and response parsing.
|
|
18
|
+
#
|
|
19
|
+
# @example Initialize with default configuration
|
|
20
|
+
# api = DurableHuggingfaceHub::HfApi.new
|
|
21
|
+
#
|
|
22
|
+
# @example Initialize with custom token and endpoint
|
|
23
|
+
# api = DurableHuggingfaceHub::HfApi.new(
|
|
24
|
+
# token: "hf_...",
|
|
25
|
+
# endpoint: "https://huggingface.co"
|
|
26
|
+
# )
|
|
27
|
+
#
|
|
28
|
+
# @example Get model information
|
|
29
|
+
# model = api.model_info("bert-base-uncased")
|
|
30
|
+
# puts model.id
|
|
31
|
+
# puts model.downloads
|
|
32
|
+
#
|
|
33
|
+
# @example List models with filtering
|
|
34
|
+
# models = api.list_models(filter: "text-classification", limit: 10)
|
|
35
|
+
# models.each { |m| puts m.id }
|
|
36
|
+
class HfApi
|
|
37
|
+
# @return [String, nil] Authentication token for API requests
|
|
38
|
+
attr_reader :token
|
|
39
|
+
|
|
40
|
+
# @return [String] Base endpoint URL for the HuggingFace Hub
|
|
41
|
+
attr_reader :endpoint
|
|
42
|
+
|
|
43
|
+
# @return [DurableHuggingfaceHub::Utils::HttpClient] HTTP client instance
|
|
44
|
+
attr_reader :http_client
|
|
45
|
+
|
|
46
|
+
# Initialize a new HfApi client
|
|
47
|
+
#
|
|
48
|
+
# @param token [String, nil] HuggingFace authentication token.
|
|
49
|
+
# If nil, will attempt to retrieve from environment or token file.
|
|
50
|
+
# @param endpoint [String, nil] Base URL for the HuggingFace Hub API.
|
|
51
|
+
# Defaults to {DurableHuggingfaceHub::Constants::ENDPOINT}.
|
|
52
|
+
#
|
|
53
|
+
# @example Create client with auto-detected token
|
|
54
|
+
# api = DurableHuggingfaceHub::HfApi.new
|
|
55
|
+
#
|
|
56
|
+
# @example Create client with explicit token
|
|
57
|
+
# api = DurableHuggingfaceHub::HfApi.new(token: "hf_...")
|
|
58
|
+
#
|
|
59
|
+
# @example Create client with custom endpoint
|
|
60
|
+
# api = DurableHuggingfaceHub::HfApi.new(
|
|
61
|
+
# endpoint: "https://custom-hub.example.com"
|
|
62
|
+
# )
|
|
63
|
+
def initialize(token: nil, endpoint: nil)
|
|
64
|
+
@token = token || DurableHuggingfaceHub::Utils::Auth.get_token
|
|
65
|
+
@endpoint = endpoint || DurableHuggingfaceHub.configuration.endpoint
|
|
66
|
+
@http_client = DurableHuggingfaceHub::Utils::HttpClient.new(
|
|
67
|
+
endpoint: @endpoint,
|
|
68
|
+
token: @token
|
|
69
|
+
)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Get comprehensive information about a repository
|
|
73
|
+
#
|
|
74
|
+
# This is a generic method that works for any repository type (model,
|
|
75
|
+
# dataset, or space). For type-specific methods, see {#model_info},
|
|
76
|
+
# {#dataset_info}, or {#space_info}.
|
|
77
|
+
#
|
|
78
|
+
# @param repo_id [String] Repository identifier in the format "namespace/name"
|
|
79
|
+
# or just "name" for repositories in your namespace
|
|
80
|
+
# @param repo_type [String, Symbol] Type of repository: "model", "dataset", or "space"
|
|
81
|
+
# @param revision [String, nil] Git revision (branch, tag, or commit SHA).
|
|
82
|
+
# Defaults to "main"
|
|
83
|
+
# @param timeout [Numeric, nil] Request timeout in seconds
|
|
84
|
+
#
|
|
85
|
+
# @return [DurableHuggingfaceHub::Types::ModelInfo, DurableHuggingfaceHub::Types::DatasetInfo, DurableHuggingfaceHub::Types::SpaceInfo]
|
|
86
|
+
# Repository information object, type depends on repo_type
|
|
87
|
+
#
|
|
88
|
+
# @raise [ArgumentError] If repo_id or repo_type is invalid
|
|
89
|
+
# @raise [DurableHuggingfaceHub::RepositoryNotFoundError] If repository doesn't exist
|
|
90
|
+
# @raise [DurableHuggingfaceHub::RevisionNotFoundError] If revision doesn't exist
|
|
91
|
+
# @raise [DurableHuggingfaceHub::HfHubHTTPError] For other API errors
|
|
92
|
+
#
|
|
93
|
+
# @example Get model information
|
|
94
|
+
# info = api.repo_info("bert-base-uncased", repo_type: "model")
|
|
95
|
+
# puts info.id
|
|
96
|
+
# puts info.downloads
|
|
97
|
+
#
|
|
98
|
+
# @example Get dataset information with specific revision
|
|
99
|
+
# info = api.repo_info("squad", repo_type: "dataset", revision: "v1.0")
|
|
100
|
+
# puts info.id
|
|
101
|
+
#
|
|
102
|
+
# @example Get space information
|
|
103
|
+
# info = api.repo_info("stabilityai/stable-diffusion", repo_type: "space")
|
|
104
|
+
# puts info.id
|
|
105
|
+
def repo_info(repo_id, repo_type: "model", revision: nil, timeout: nil)
|
|
106
|
+
# Validate inputs
|
|
107
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(repo_id)
|
|
108
|
+
repo_type = DurableHuggingfaceHub::Utils::Validators.validate_repo_type(repo_type)
|
|
109
|
+
|
|
110
|
+
if revision
|
|
111
|
+
DurableHuggingfaceHub::Utils::Validators.validate_revision(revision)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Build API path
|
|
115
|
+
path = case repo_type.to_s
|
|
116
|
+
when "model"
|
|
117
|
+
"/api/models/#{repo_id}"
|
|
118
|
+
when "dataset"
|
|
119
|
+
"/api/datasets/#{repo_id}"
|
|
120
|
+
when "space"
|
|
121
|
+
"/api/spaces/#{repo_id}"
|
|
122
|
+
else
|
|
123
|
+
raise ArgumentError, "Invalid repo_type: #{repo_type}"
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Add revision if specified
|
|
127
|
+
params = {}
|
|
128
|
+
params[:revision] = revision if revision
|
|
129
|
+
|
|
130
|
+
# Make request
|
|
131
|
+
response = http_client.get(path, params: params, timeout: timeout)
|
|
132
|
+
|
|
133
|
+
# Parse response based on repo_type
|
|
134
|
+
body = response.body.is_a?(String) ? JSON.parse(response.body) : response.body
|
|
135
|
+
case repo_type.to_s
|
|
136
|
+
when "model"
|
|
137
|
+
DurableHuggingfaceHub::Types::ModelInfo.from_hash(body)
|
|
138
|
+
when "dataset"
|
|
139
|
+
DurableHuggingfaceHub::Types::DatasetInfo.from_hash(body)
|
|
140
|
+
when "space"
|
|
141
|
+
DurableHuggingfaceHub::Types::SpaceInfo.from_hash(body)
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Get information about a specific model
|
|
146
|
+
#
|
|
147
|
+
# This is a convenience method that calls {#repo_info} with
|
|
148
|
+
# repo_type: "model".
|
|
149
|
+
#
|
|
150
|
+
# @param repo_id [String] Model repository identifier
|
|
151
|
+
# @param revision [String, nil] Git revision (branch, tag, or commit SHA).
|
|
152
|
+
# Defaults to "main"
|
|
153
|
+
# @param timeout [Numeric, nil] Request timeout in seconds
|
|
154
|
+
#
|
|
155
|
+
# @return [DurableHuggingfaceHub::Types::ModelInfo] Model information
|
|
156
|
+
#
|
|
157
|
+
# @raise [ArgumentError] If repo_id is invalid
|
|
158
|
+
# @raise [DurableHuggingfaceHub::RepositoryNotFoundError] If model doesn't exist
|
|
159
|
+
# @raise [DurableHuggingfaceHub::RevisionNotFoundError] If revision doesn't exist
|
|
160
|
+
#
|
|
161
|
+
# @example Get basic model info
|
|
162
|
+
# model = api.model_info("bert-base-uncased")
|
|
163
|
+
# puts "Downloads: #{model.downloads}"
|
|
164
|
+
# puts "Likes: #{model.likes}"
|
|
165
|
+
#
|
|
166
|
+
# @example Get model info for specific revision
|
|
167
|
+
# model = api.model_info("gpt2", revision: "main")
|
|
168
|
+
# puts "SHA: #{model.sha}"
|
|
169
|
+
def model_info(repo_id, revision: nil, timeout: nil)
|
|
170
|
+
repo_info(repo_id, repo_type: "model", revision: revision, timeout: timeout)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Get information about a specific dataset
|
|
174
|
+
#
|
|
175
|
+
# This is a convenience method that calls {#repo_info} with
|
|
176
|
+
# repo_type: "dataset".
|
|
177
|
+
#
|
|
178
|
+
# @param repo_id [String] Dataset repository identifier
|
|
179
|
+
# @param revision [String, nil] Git revision (branch, tag, or commit SHA).
|
|
180
|
+
# Defaults to "main"
|
|
181
|
+
# @param timeout [Numeric, nil] Request timeout in seconds
|
|
182
|
+
#
|
|
183
|
+
# @return [DurableHuggingfaceHub::Types::DatasetInfo] Dataset information
|
|
184
|
+
#
|
|
185
|
+
# @raise [ArgumentError] If repo_id is invalid
|
|
186
|
+
# @raise [DurableHuggingfaceHub::RepositoryNotFoundError] If dataset doesn't exist
|
|
187
|
+
# @raise [DurableHuggingfaceHub::RevisionNotFoundError] If revision doesn't exist
|
|
188
|
+
#
|
|
189
|
+
# @example Get dataset info
|
|
190
|
+
# dataset = api.dataset_info("squad")
|
|
191
|
+
# puts "Downloads: #{dataset.downloads}"
|
|
192
|
+
# puts "Tags: #{dataset.tags}"
|
|
193
|
+
def dataset_info(repo_id, revision: nil, timeout: nil)
|
|
194
|
+
repo_info(repo_id, repo_type: "dataset", revision: revision, timeout: timeout)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Get information about a specific space
|
|
198
|
+
#
|
|
199
|
+
# This is a convenience method that calls {#repo_info} with
|
|
200
|
+
# repo_type: "space".
|
|
201
|
+
#
|
|
202
|
+
# @param repo_id [String] Space repository identifier
|
|
203
|
+
# @param revision [String, nil] Git revision (branch, tag, or commit SHA).
|
|
204
|
+
# Defaults to "main"
|
|
205
|
+
# @param timeout [Numeric, nil] Request timeout in seconds
|
|
206
|
+
#
|
|
207
|
+
# @return [DurableHuggingfaceHub::Types::SpaceInfo] Space information
|
|
208
|
+
#
|
|
209
|
+
# @raise [ArgumentError] If repo_id is invalid
|
|
210
|
+
# @raise [DurableHuggingfaceHub::RepositoryNotFoundError] If space doesn't exist
|
|
211
|
+
# @raise [DurableHuggingfaceHub::RevisionNotFoundError] If revision doesn't exist
|
|
212
|
+
#
|
|
213
|
+
# @example Get space info
|
|
214
|
+
# space = api.space_info("stabilityai/stable-diffusion")
|
|
215
|
+
# puts "Runtime: #{space.runtime}"
|
|
216
|
+
# puts "SDK: #{space.sdk}"
|
|
217
|
+
def space_info(repo_id, revision: nil, timeout: nil)
|
|
218
|
+
repo_info(repo_id, repo_type: "space", revision: revision, timeout: timeout)
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# List models from the HuggingFace Hub with optional filtering
|
|
222
|
+
#
|
|
223
|
+
# Returns a list of models matching the specified criteria. Results can be
|
|
224
|
+
# filtered by tags, author, search query, and sorted by various metrics.
|
|
225
|
+
#
|
|
226
|
+
# @param filter [String, Hash, nil] Filter criteria:
|
|
227
|
+
# - String: Search query or single tag
|
|
228
|
+
# - Hash: Structured filters (e.g., {author: "google", task: "text-classification"})
|
|
229
|
+
# @param author [String, nil] Filter by author/organization
|
|
230
|
+
# @param search [String, nil] Search query for model names and descriptions
|
|
231
|
+
# @param sort [String, Symbol, nil] Sort criterion:
|
|
232
|
+
# "downloads", "likes", "updated", "created", "trending"
|
|
233
|
+
# @param direction [Integer, nil] Sort direction: -1 for descending, 1 for ascending
|
|
234
|
+
# @param limit [Integer, nil] Maximum number of results to return
|
|
235
|
+
# @param full [Boolean] If true, fetch full model information (slower)
|
|
236
|
+
# @param timeout [Numeric, nil] Request timeout in seconds
|
|
237
|
+
#
|
|
238
|
+
# @return [Array<DurableHuggingfaceHub::Types::ModelInfo>] List of models
|
|
239
|
+
#
|
|
240
|
+
# @raise [DurableHuggingfaceHub::HfHubHTTPError] For API errors
|
|
241
|
+
#
|
|
242
|
+
# @example List all models
|
|
243
|
+
# models = api.list_models
|
|
244
|
+
#
|
|
245
|
+
# @example List models by author
|
|
246
|
+
# models = api.list_models(author: "google")
|
|
247
|
+
#
|
|
248
|
+
# @example Search for specific models
|
|
249
|
+
# models = api.list_models(search: "bert")
|
|
250
|
+
#
|
|
251
|
+
# @example Filter by task and sort by downloads
|
|
252
|
+
# models = api.list_models(
|
|
253
|
+
# filter: {task: "text-classification"},
|
|
254
|
+
# sort: "downloads",
|
|
255
|
+
# direction: -1,
|
|
256
|
+
# limit: 10
|
|
257
|
+
# )
|
|
258
|
+
#
|
|
259
|
+
# @example Filter by multiple criteria
|
|
260
|
+
# models = api.list_models(
|
|
261
|
+
# filter: {
|
|
262
|
+
# author: "facebook",
|
|
263
|
+
# library: "pytorch",
|
|
264
|
+
# language: "en"
|
|
265
|
+
# },
|
|
266
|
+
# limit: 20
|
|
267
|
+
# )
|
|
268
|
+
def list_models(filter: nil, author: nil, search: nil, sort: nil,
|
|
269
|
+
direction: nil, limit: nil, full: false, timeout: nil)
|
|
270
|
+
path = "/api/models"
|
|
271
|
+
params = build_list_params(
|
|
272
|
+
filter: filter,
|
|
273
|
+
author: author,
|
|
274
|
+
search: search,
|
|
275
|
+
sort: sort,
|
|
276
|
+
direction: direction,
|
|
277
|
+
limit: limit,
|
|
278
|
+
full: full
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
response = http_client.get(path, params: params, timeout: timeout)
|
|
282
|
+
|
|
283
|
+
# Response is an array of model objects
|
|
284
|
+
body = response.body.is_a?(String) ? JSON.parse(response.body) : response.body
|
|
285
|
+
body.map { |model_data| DurableHuggingfaceHub::Types::ModelInfo.from_hash(model_data) }
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
# List datasets from the HuggingFace Hub with optional filtering
|
|
289
|
+
#
|
|
290
|
+
# Returns a list of datasets matching the specified criteria.
|
|
291
|
+
#
|
|
292
|
+
# @param filter [String, Hash, nil] Filter criteria
|
|
293
|
+
# @param author [String, nil] Filter by author/organization
|
|
294
|
+
# @param search [String, nil] Search query
|
|
295
|
+
# @param sort [String, Symbol, nil] Sort criterion
|
|
296
|
+
# @param direction [Integer, nil] Sort direction: -1 for descending, 1 for ascending
|
|
297
|
+
# @param limit [Integer, nil] Maximum number of results
|
|
298
|
+
# @param full [Boolean] Fetch full dataset information
|
|
299
|
+
# @param timeout [Numeric, nil] Request timeout in seconds
|
|
300
|
+
#
|
|
301
|
+
# @return [Array<DurableHuggingfaceHub::Types::DatasetInfo>] List of datasets
|
|
302
|
+
#
|
|
303
|
+
# @example List popular datasets
|
|
304
|
+
# datasets = api.list_datasets(sort: "downloads", limit: 10)
|
|
305
|
+
def list_datasets(filter: nil, author: nil, search: nil, sort: nil,
|
|
306
|
+
direction: nil, limit: nil, full: false, timeout: nil)
|
|
307
|
+
path = "/api/datasets"
|
|
308
|
+
params = build_list_params(
|
|
309
|
+
filter: filter,
|
|
310
|
+
author: author,
|
|
311
|
+
search: search,
|
|
312
|
+
sort: sort,
|
|
313
|
+
direction: direction,
|
|
314
|
+
limit: limit,
|
|
315
|
+
full: full
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
response = http_client.get(path, params: params, timeout: timeout)
|
|
319
|
+
body = response.body.is_a?(String) ? JSON.parse(response.body) : response.body
|
|
320
|
+
body.map { |dataset_data| DurableHuggingfaceHub::Types::DatasetInfo.from_hash(dataset_data) }
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
# List spaces from the HuggingFace Hub with optional filtering
|
|
324
|
+
#
|
|
325
|
+
# Returns a list of spaces matching the specified criteria.
|
|
326
|
+
#
|
|
327
|
+
# @param filter [String, Hash, nil] Filter criteria
|
|
328
|
+
# @param author [String, nil] Filter by author/organization
|
|
329
|
+
# @param search [String, nil] Search query
|
|
330
|
+
# @param sort [String, Symbol, nil] Sort criterion
|
|
331
|
+
# @param direction [Integer, nil] Sort direction: -1 for descending, 1 for ascending
|
|
332
|
+
# @param limit [Integer, nil] Maximum number of results
|
|
333
|
+
# @param full [Boolean] Fetch full space information
|
|
334
|
+
# @param timeout [Numeric, nil] Request timeout in seconds
|
|
335
|
+
#
|
|
336
|
+
# @return [Array<DurableHuggingfaceHub::Types::SpaceInfo>] List of spaces
|
|
337
|
+
#
|
|
338
|
+
# @example List trending spaces
|
|
339
|
+
# spaces = api.list_spaces(sort: "trending", limit: 10)
|
|
340
|
+
def list_spaces(filter: nil, author: nil, search: nil, sort: nil,
|
|
341
|
+
direction: nil, limit: nil, full: false, timeout: nil)
|
|
342
|
+
path = "/api/spaces"
|
|
343
|
+
params = build_list_params(
|
|
344
|
+
filter: filter,
|
|
345
|
+
author: author,
|
|
346
|
+
search: search,
|
|
347
|
+
sort: sort,
|
|
348
|
+
direction: direction,
|
|
349
|
+
limit: limit,
|
|
350
|
+
full: full
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
response = http_client.get(path, params: params, timeout: timeout)
|
|
354
|
+
body = response.body.is_a?(String) ? JSON.parse(response.body) : response.body
|
|
355
|
+
body.map { |space_data| DurableHuggingfaceHub::Types::SpaceInfo.from_hash(space_data) }
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
# Check if a repository exists on the HuggingFace Hub
|
|
359
|
+
#
|
|
360
|
+
# @param repo_id [String] Repository identifier
|
|
361
|
+
# @param repo_type [String, Symbol] Type of repository: "model", "dataset", or "space"
|
|
362
|
+
# @param timeout [Numeric, nil] Request timeout in seconds
|
|
363
|
+
#
|
|
364
|
+
# @return [Boolean] True if repository exists, false otherwise
|
|
365
|
+
#
|
|
366
|
+
# @example Check if model exists
|
|
367
|
+
# if api.repo_exists("bert-base-uncased")
|
|
368
|
+
# puts "Model exists!"
|
|
369
|
+
# end
|
|
370
|
+
def repo_exists(repo_id, repo_type: "model", timeout: nil)
|
|
371
|
+
repo_info(repo_id, repo_type: repo_type, timeout: timeout)
|
|
372
|
+
true
|
|
373
|
+
rescue DurableHuggingfaceHub::RepositoryNotFoundError
|
|
374
|
+
false
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
# Get current user information (requires authentication)
|
|
378
|
+
#
|
|
379
|
+
# Returns information about the authenticated user. Requires a valid
|
|
380
|
+
# authentication token.
|
|
381
|
+
#
|
|
382
|
+
# @param timeout [Numeric, nil] Request timeout in seconds
|
|
383
|
+
#
|
|
384
|
+
# @return [DurableHuggingfaceHub::Types::User] User information
|
|
385
|
+
#
|
|
386
|
+
# @raise [DurableHuggingfaceHub::HfHubHTTPError] If not authenticated or token is invalid
|
|
387
|
+
#
|
|
388
|
+
# @example Get current user info
|
|
389
|
+
# user = api.whoami
|
|
390
|
+
# puts "Logged in as: #{user.name}"
|
|
391
|
+
# puts "Type: #{user.type}"
|
|
392
|
+
def whoami(timeout: nil)
|
|
393
|
+
path = "/api/whoami-v2"
|
|
394
|
+
response = http_client.get(path, timeout: timeout)
|
|
395
|
+
body = response.body.is_a?(String) ? JSON.parse(response.body) : response.body
|
|
396
|
+
DurableHuggingfaceHub::Types::User.from_hash(body)
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
# List files in a repository.
|
|
400
|
+
#
|
|
401
|
+
# @param repo_id [String] Repository ID
|
|
402
|
+
# @param repo_type [String, Symbol] Type of repository ("model", "dataset", or "space")
|
|
403
|
+
# @param revision [String, nil] Git revision (branch, tag, or commit SHA). Defaults to "main"
|
|
404
|
+
# @param timeout [Numeric, nil] Request timeout in seconds
|
|
405
|
+
# @return [Array<String>] List of file paths in the repository
|
|
406
|
+
# @raise [RepositoryNotFoundError] If repository doesn't exist
|
|
407
|
+
# @raise [RevisionNotFoundError] If revision doesn't exist
|
|
408
|
+
def list_repo_files(repo_id:, repo_type: "model", revision: nil, timeout: nil)
|
|
409
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(repo_id)
|
|
410
|
+
repo_type = DurableHuggingfaceHub::Utils::Validators.validate_repo_type(repo_type)
|
|
411
|
+
revision = DurableHuggingfaceHub::Utils::Validators.validate_revision(revision) if revision
|
|
412
|
+
|
|
413
|
+
path = "/api/#{repo_type}s/#{repo_id}/tree"
|
|
414
|
+
params = { recursive: true }
|
|
415
|
+
params[:revision] = revision if revision
|
|
416
|
+
|
|
417
|
+
response = http_client.get(path, params: params, timeout: timeout)
|
|
418
|
+
body = response.body.is_a?(String) ? JSON.parse(response.body) : response.body
|
|
419
|
+
body.map { |file_data| file_data["path"] }
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
# List repository contents in a hierarchical tree structure.
|
|
423
|
+
#
|
|
424
|
+
# This method provides a tree-like view of the repository contents,
|
|
425
|
+
# organized by directories and files with their metadata.
|
|
426
|
+
#
|
|
427
|
+
# @param repo_id [String] Repository ID
|
|
428
|
+
# @param repo_type [String, Symbol] Type of repository ("model", "dataset", or "space")
|
|
429
|
+
# @param revision [String, nil] Git revision (branch, tag, or commit SHA). Defaults to "main"
|
|
430
|
+
# @param path [String, nil] Path within repository to list (for subdirectories)
|
|
431
|
+
# @param recursive [Boolean] Whether to recursively list subdirectories. Defaults to false
|
|
432
|
+
# @param timeout [Numeric, nil] Request timeout in seconds
|
|
433
|
+
# @return [Hash] Tree structure with directories and files
|
|
434
|
+
# @raise [RepositoryNotFoundError] If repository doesn't exist
|
|
435
|
+
# @raise [RevisionNotFoundError] If revision doesn't exist
|
|
436
|
+
#
|
|
437
|
+
# @example Get repository tree
|
|
438
|
+
# tree = api.list_repo_tree(repo_id: "bert-base-uncased")
|
|
439
|
+
# puts tree.keys # ["config.json", "pytorch_model.bin", "tokenizer.json", ...]
|
|
440
|
+
#
|
|
441
|
+
# @example Get tree for a subdirectory
|
|
442
|
+
# subtree = api.list_repo_tree(
|
|
443
|
+
# repo_id: "my-model",
|
|
444
|
+
# path: "checkpoints"
|
|
445
|
+
# )
|
|
446
|
+
def list_repo_tree(repo_id:, repo_type: "model", revision: nil, path: nil, recursive: false, timeout: nil)
|
|
447
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(repo_id)
|
|
448
|
+
repo_type = DurableHuggingfaceHub::Utils::Validators.validate_repo_type(repo_type)
|
|
449
|
+
revision = DurableHuggingfaceHub::Utils::Validators.validate_revision(revision) if revision
|
|
450
|
+
revision ||= "main"
|
|
451
|
+
|
|
452
|
+
# Build the API path
|
|
453
|
+
api_path = "/api/#{repo_type}s/#{repo_id}/tree"
|
|
454
|
+
api_path += "/#{path}" if path
|
|
455
|
+
|
|
456
|
+
params = { recursive: recursive }
|
|
457
|
+
params[:revision] = revision if revision
|
|
458
|
+
|
|
459
|
+
response = http_client.get(api_path, params: params, timeout: timeout)
|
|
460
|
+
|
|
461
|
+
# Organize the response into a tree structure
|
|
462
|
+
body = response.body.is_a?(String) ? JSON.parse(response.body) : response.body
|
|
463
|
+
build_tree_structure(body)
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
# Get metadata about a file in a repository without downloading it.
|
|
467
|
+
#
|
|
468
|
+
# This method retrieves file metadata including size, ETag, and other information
|
|
469
|
+
# from the HuggingFace Hub API without downloading the actual file content.
|
|
470
|
+
#
|
|
471
|
+
# @param repo_id [String] The ID of the repository.
|
|
472
|
+
# @param filename [String] The path to the file within the repository.
|
|
473
|
+
# @param repo_type [String, Symbol] The type of the repository. Defaults to "model".
|
|
474
|
+
# @param revision [String, nil] The Git revision (branch, tag, or commit SHA). Defaults to "main".
|
|
475
|
+
# @param timeout [Numeric, nil] Request timeout in seconds.
|
|
476
|
+
# @return [Hash] File metadata including :size, :etag, :commit_hash, :last_modified, etc.
|
|
477
|
+
# @raise [ArgumentError] If repo_id, filename, or repo_type is invalid.
|
|
478
|
+
# @raise [DurableHuggingfaceHub::RepositoryNotFoundError] If the repository does not exist.
|
|
479
|
+
# @raise [DurableHuggingfaceHub::EntryNotFoundError] If the file does not exist.
|
|
480
|
+
# @raise [DurableHuggingfaceHub::RevisionNotFoundError] If the revision does not exist.
|
|
481
|
+
# @raise [DurableHuggingfaceHub::HfHubHTTPError] For other API errors.
|
|
482
|
+
#
|
|
483
|
+
# @example Get metadata for a model file
|
|
484
|
+
# metadata = api.get_hf_file_metadata(
|
|
485
|
+
# repo_id: "bert-base-uncased",
|
|
486
|
+
# filename: "config.json"
|
|
487
|
+
# )
|
|
488
|
+
# puts "Size: #{metadata[:size]} bytes"
|
|
489
|
+
# puts "ETag: #{metadata[:etag]}"
|
|
490
|
+
def get_hf_file_metadata(repo_id:, filename:, repo_type: "model", revision: nil, timeout: nil)
|
|
491
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(repo_id)
|
|
492
|
+
DurableHuggingfaceHub::Utils::Validators.validate_filename(filename)
|
|
493
|
+
repo_type = DurableHuggingfaceHub::Utils::Validators.validate_repo_type(repo_type)
|
|
494
|
+
revision = DurableHuggingfaceHub::Utils::Validators.validate_revision(revision) if revision
|
|
495
|
+
revision ||= "main"
|
|
496
|
+
|
|
497
|
+
path = "/api/#{repo_type}s/#{repo_id}/resolve/#{revision}/#{filename}"
|
|
498
|
+
|
|
499
|
+
begin
|
|
500
|
+
response = http_client.head(path, timeout: timeout)
|
|
501
|
+
|
|
502
|
+
# Extract metadata from response headers
|
|
503
|
+
headers = response.headers
|
|
504
|
+
{
|
|
505
|
+
size: headers["x-linked-size"]&.to_i,
|
|
506
|
+
etag: DurableHuggingfaceHub::FileDownload.extract_etag(headers["etag"] || headers["x-linked-etag"]),
|
|
507
|
+
commit_hash: headers["x-repo-commit"],
|
|
508
|
+
last_modified: headers["last-modified"] ? Time.parse(headers["last-modified"]) : nil,
|
|
509
|
+
content_type: headers["content-type"],
|
|
510
|
+
filename: filename,
|
|
511
|
+
repo_id: repo_id,
|
|
512
|
+
repo_type: repo_type,
|
|
513
|
+
revision: revision
|
|
514
|
+
}.compact
|
|
515
|
+
rescue DurableHuggingfaceHub::EntryNotFoundError
|
|
516
|
+
raise
|
|
517
|
+
rescue DurableHuggingfaceHub::HfHubHTTPError => e
|
|
518
|
+
# Convert 404 to EntryNotFoundError for consistency
|
|
519
|
+
if e.status_code == 404
|
|
520
|
+
raise DurableHuggingfaceHub::EntryNotFoundError.new(
|
|
521
|
+
"File #{filename} not found in #{repo_id}@#{revision}"
|
|
522
|
+
)
|
|
523
|
+
end
|
|
524
|
+
raise
|
|
525
|
+
end
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
# Get metadata for multiple paths in a repository.
|
|
529
|
+
#
|
|
530
|
+
# This method efficiently retrieves metadata for multiple files or paths
|
|
531
|
+
# in a repository using batch requests where possible.
|
|
532
|
+
#
|
|
533
|
+
# @param repo_id [String] The ID of the repository.
|
|
534
|
+
# @param paths [Array<String>] Array of file paths within the repository.
|
|
535
|
+
# @param repo_type [String, Symbol] The type of the repository. Defaults to "model".
|
|
536
|
+
# @param revision [String, nil] The Git revision (branch, tag, or commit SHA). Defaults to "main".
|
|
537
|
+
# @param timeout [Numeric, nil] Request timeout in seconds.
|
|
538
|
+
# @return [Array<Hash>] Array of metadata hashes, one for each path. Missing files return nil.
|
|
539
|
+
# @raise [ArgumentError] If repo_id, paths, or repo_type is invalid.
|
|
540
|
+
# @raise [DurableHuggingfaceHub::RepositoryNotFoundError] If the repository does not exist.
|
|
541
|
+
# @raise [DurableHuggingfaceHub::RevisionNotFoundError] If the revision does not exist.
|
|
542
|
+
# @raise [DurableHuggingfaceHub::HfHubHTTPError] For other API errors.
|
|
543
|
+
#
|
|
544
|
+
# @example Get metadata for multiple files
|
|
545
|
+
# paths = ["config.json", "pytorch_model.bin", "tokenizer.json"]
|
|
546
|
+
# metadata_list = api.get_paths_info(
|
|
547
|
+
# repo_id: "bert-base-uncased",
|
|
548
|
+
# paths: paths
|
|
549
|
+
# )
|
|
550
|
+
# metadata_list.each_with_index do |metadata, i|
|
|
551
|
+
# if metadata
|
|
552
|
+
# puts "#{paths[i]}: #{metadata[:size]} bytes"
|
|
553
|
+
# else
|
|
554
|
+
# puts "#{paths[i]}: not found"
|
|
555
|
+
# end
|
|
556
|
+
# end
|
|
557
|
+
def get_paths_info(repo_id:, paths:, repo_type: "model", revision: nil, timeout: nil)
|
|
558
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(repo_id)
|
|
559
|
+
raise ArgumentError, "paths must be an array" unless paths.is_a?(Array)
|
|
560
|
+
paths.each { |path| DurableHuggingfaceHub::Utils::Validators.validate_filename(path) }
|
|
561
|
+
repo_type = DurableHuggingfaceHub::Utils::Validators.validate_repo_type(repo_type)
|
|
562
|
+
revision = DurableHuggingfaceHub::Utils::Validators.validate_revision(revision) if revision
|
|
563
|
+
revision ||= "main"
|
|
564
|
+
|
|
565
|
+
# For now, implement sequentially. In the future, this could be optimized
|
|
566
|
+
# with concurrent requests or batch API calls if available.
|
|
567
|
+
paths.map do |path|
|
|
568
|
+
begin
|
|
569
|
+
get_hf_file_metadata(
|
|
570
|
+
repo_id: repo_id,
|
|
571
|
+
filename: path,
|
|
572
|
+
repo_type: repo_type,
|
|
573
|
+
revision: revision,
|
|
574
|
+
timeout: timeout
|
|
575
|
+
)
|
|
576
|
+
rescue DurableHuggingfaceHub::EntryNotFoundError
|
|
577
|
+
nil # Return nil for missing files
|
|
578
|
+
end
|
|
579
|
+
end
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
# Build a tree structure from the API response.
|
|
583
|
+
#
|
|
584
|
+
# @param items [Array<Hash>] Raw API response items
|
|
585
|
+
# @return [Hash] Organized tree structure
|
|
586
|
+
def build_tree_structure(items)
|
|
587
|
+
tree = {}
|
|
588
|
+
|
|
589
|
+
items.each do |item|
|
|
590
|
+
path = item["path"]
|
|
591
|
+
path_parts = path.split("/")
|
|
592
|
+
|
|
593
|
+
# Navigate/create nested structure
|
|
594
|
+
current = tree
|
|
595
|
+
path_parts.each_with_index do |part, index|
|
|
596
|
+
is_last = index == path_parts.length - 1
|
|
597
|
+
|
|
598
|
+
if is_last
|
|
599
|
+
# This is a file
|
|
600
|
+
current[part] = {
|
|
601
|
+
type: "file",
|
|
602
|
+
size: item["size"],
|
|
603
|
+
oid: item["oid"], # SHA for Git LFS files
|
|
604
|
+
lfs: item["lfs"] # LFS information if applicable
|
|
605
|
+
}.compact
|
|
606
|
+
else
|
|
607
|
+
# This is a directory
|
|
608
|
+
current[part] ||= { type: "directory", children: {} }
|
|
609
|
+
current = current[part][:children]
|
|
610
|
+
end
|
|
611
|
+
end
|
|
612
|
+
end
|
|
613
|
+
|
|
614
|
+
tree
|
|
615
|
+
end
|
|
616
|
+
|
|
617
|
+
# Create a new repository on the HuggingFace Hub.
|
|
618
|
+
#
|
|
619
|
+
# @param repo_id [String] The ID of the repository to create (e.g., "my-username/my-repo").
|
|
620
|
+
# @param repo_type [String, Symbol] The type of the repository ("model", "dataset", or "space"). Defaults to "model".
|
|
621
|
+
# @param private [Boolean] Whether the repository should be private. Defaults to false.
|
|
622
|
+
# @param organization [String, nil] The organization namespace to create the repository under.
|
|
623
|
+
# If nil, the repository is created under the authenticated user's namespace.
|
|
624
|
+
# @param timeout [Numeric, nil] Request timeout in seconds.
|
|
625
|
+
# @return [String] The URL of the newly created repository.
|
|
626
|
+
# @raise [ArgumentError] If repo_id or repo_type is invalid.
|
|
627
|
+
# @raise [DurableHuggingfaceHub::HfHubHTTPError] For API errors (e.g., repository already exists, authentication error).
|
|
628
|
+
def create_repo(repo_id:, repo_type: "model", private: false, organization: nil, timeout: nil)
|
|
629
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(repo_id)
|
|
630
|
+
repo_type = DurableHuggingfaceHub::Utils::Validators.validate_repo_type(repo_type)
|
|
631
|
+
|
|
632
|
+
path = "/api/#{repo_type}s"
|
|
633
|
+
payload = {
|
|
634
|
+
name: repo_id.split("/").last,
|
|
635
|
+
private: private,
|
|
636
|
+
organization: organization
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
response = http_client.post(path, body: payload, timeout: timeout)
|
|
640
|
+
body = response.body.is_a?(String) ? JSON.parse(response.body) : response.body
|
|
641
|
+
body["url"]
|
|
642
|
+
end
|
|
643
|
+
|
|
644
|
+
# Delete a repository from the HuggingFace Hub.
|
|
645
|
+
#
|
|
646
|
+
# @param repo_id [String] The ID of the repository to delete (e.g., "my-username/my-repo").
|
|
647
|
+
# @param repo_type [String, Symbol] The type of the repository ("model", "dataset", or "space"). Defaults to "model".
|
|
648
|
+
# @param token [String, nil] HuggingFace API token. If nil, will attempt to retrieve from environment or token file.
|
|
649
|
+
# @param timeout [Numeric, nil] Request timeout in seconds.
|
|
650
|
+
# @return [Boolean] True if the repository was successfully deleted.
|
|
651
|
+
# @raise [ArgumentError] If repo_id or repo_type is invalid.
|
|
652
|
+
# @raise [DurableHuggingfaceHub::RepositoryNotFoundError] If the repository does not exist.
|
|
653
|
+
# @raise [DurableHuggingfaceHub::HfHubHTTPError] For other API errors (e.g., authentication error).
|
|
654
|
+
def delete_repo(repo_id:, repo_type: "model", token: nil, timeout: nil)
|
|
655
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(repo_id)
|
|
656
|
+
repo_type = DurableHuggingfaceHub::Utils::Validators.validate_repo_type(repo_type)
|
|
657
|
+
|
|
658
|
+
path = "/api/#{repo_type}s/#{repo_id}"
|
|
659
|
+
http_client.delete(path)
|
|
660
|
+
true
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
# Update the visibility of a repository (public/private).
|
|
664
|
+
#
|
|
665
|
+
# @param repo_id [String] The ID of the repository to update.
|
|
666
|
+
# @param repo_type [String, Symbol] The type of the repository. Defaults to "model".
|
|
667
|
+
# @param private [Boolean] The new visibility status (true for private, false for public).
|
|
668
|
+
# @param timeout [Numeric, nil] Request timeout in seconds.
|
|
669
|
+
# @return [Boolean] True if the visibility was successfully updated.
|
|
670
|
+
# @raise [ArgumentError] If repo_id or repo_type is invalid.
|
|
671
|
+
# @raise [DurableHuggingfaceHub::RepositoryNotFoundError] If the repository does not exist.
|
|
672
|
+
# @raise [DurableHuggingfaceHub::HfHubHTTPError] For other API errors.
|
|
673
|
+
def update_repo_visibility(repo_id:, repo_type: "model", private:, timeout: nil)
|
|
674
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(repo_id)
|
|
675
|
+
repo_type = DurableHuggingfaceHub::Utils::Validators.validate_repo_type(repo_type)
|
|
676
|
+
|
|
677
|
+
path = "/api/#{repo_type}s/#{repo_id}/settings"
|
|
678
|
+
payload = { private: private }
|
|
679
|
+
|
|
680
|
+
http_client.post(path, body: payload, timeout: timeout)
|
|
681
|
+
true
|
|
682
|
+
end
|
|
683
|
+
|
|
684
|
+
# Update various settings for a repository.
|
|
685
|
+
#
|
|
686
|
+
# @param repo_id [String] The ID of the repository to update.
|
|
687
|
+
# @param repo_type [String, Symbol] The type of the repository. Defaults to "model".
|
|
688
|
+
# @param git_lfs_enabled [Boolean, nil] Whether Git LFS should be enabled for the repository.
|
|
689
|
+
# @param protected [Boolean, nil] Whether the repository should be protected.
|
|
690
|
+
# @param unlisted [Boolean, nil] Whether the repository should be unlisted.
|
|
691
|
+
# @param tags [Array<String>, nil] A list of tags to apply to the repository.
|
|
692
|
+
# @param default_branch [String, nil] The new default branch for the repository.
|
|
693
|
+
# @param timeout [Numeric, nil] Request timeout in seconds.
|
|
694
|
+
# @return [Boolean] True if the settings were successfully updated.
|
|
695
|
+
# @raise [ArgumentError] If repo_id or repo_type is invalid.
|
|
696
|
+
# @raise [DurableHuggingfaceHub::RepositoryNotFoundError] If the repository does not exist.
|
|
697
|
+
# @raise [DurableHuggingfaceHub::HfHubHTTPError] For other API errors.
|
|
698
|
+
def update_repo_settings(
|
|
699
|
+
repo_id:,
|
|
700
|
+
repo_type: "model",
|
|
701
|
+
git_lfs_enabled: nil,
|
|
702
|
+
protected: nil,
|
|
703
|
+
unlisted: nil,
|
|
704
|
+
tags: nil,
|
|
705
|
+
default_branch: nil,
|
|
706
|
+
timeout: nil
|
|
707
|
+
)
|
|
708
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(repo_id)
|
|
709
|
+
repo_type = DurableHuggingfaceHub::Utils::Validators.validate_repo_type(repo_type)
|
|
710
|
+
|
|
711
|
+
path = "/api/#{repo_type}s/#{repo_id}/settings"
|
|
712
|
+
payload = {}
|
|
713
|
+
payload[:git_lfs_enabled] = git_lfs_enabled unless git_lfs_enabled.nil?
|
|
714
|
+
payload[:protected] = protected unless protected.nil?
|
|
715
|
+
payload[:unlisted] = unlisted unless unlisted.nil?
|
|
716
|
+
payload[:tags] = tags unless tags.nil?
|
|
717
|
+
payload[:default_branch] = default_branch unless default_branch.nil?
|
|
718
|
+
|
|
719
|
+
http_client.post(path, body: payload, timeout: timeout)
|
|
720
|
+
true
|
|
721
|
+
end
|
|
722
|
+
|
|
723
|
+
# Move or rename a repository.
|
|
724
|
+
#
|
|
725
|
+
# @param from_repo_id [String] The current ID of the repository.
|
|
726
|
+
# @param to_repo_id [String] The new ID for the repository.
|
|
727
|
+
# @param repo_type [String, Symbol] The type of the repository. Defaults to "model".
|
|
728
|
+
# @param timeout [Numeric, nil] Request timeout in seconds.
|
|
729
|
+
# @return [Boolean] True if the repository was successfully moved/renamed.
|
|
730
|
+
# @raise [ArgumentError] If repo_ids or repo_type is invalid.
|
|
731
|
+
# @raise [DurableHuggingfaceHub::RepositoryNotFoundError] If the source repository does not exist.
|
|
732
|
+
# @raise [DurableHuggingfaceHub::HfHubHTTPError] For other API errors.
|
|
733
|
+
def move_repo(from_repo_id:, to_repo_id:, repo_type: "model", timeout: nil)
|
|
734
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(from_repo_id)
|
|
735
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(to_repo_id)
|
|
736
|
+
repo_type = DurableHuggingfaceHub::Utils::Validators.validate_repo_type(repo_type)
|
|
737
|
+
|
|
738
|
+
path = "/api/#{repo_type}s/#{from_repo_id}/move"
|
|
739
|
+
payload = { newPath: to_repo_id }
|
|
740
|
+
|
|
741
|
+
http_client.post(path, body: payload, timeout: timeout)
|
|
742
|
+
true
|
|
743
|
+
end
|
|
744
|
+
|
|
745
|
+
# Duplicate a Space repository.
|
|
746
|
+
#
|
|
747
|
+
# @param from_repo_id [String] The ID of the Space to duplicate.
|
|
748
|
+
# @param to_repo_id [String] The ID for the new duplicated Space.
|
|
749
|
+
# @param private [Boolean, nil] Whether the new Space should be private. Defaults to the original Space's visibility.
|
|
750
|
+
# @param organization [String, nil] The organization namespace to create the new Space under.
|
|
751
|
+
# @param timeout [Numeric, nil] Request timeout in seconds.
|
|
752
|
+
# @return [String] The URL of the newly duplicated Space.
|
|
753
|
+
# @raise [ArgumentError] If repo_ids are invalid.
|
|
754
|
+
# @raise [DurableHuggingfaceHub::RepositoryNotFoundError] If the source Space does not exist.
|
|
755
|
+
# @raise [DurableHuggingfaceHub::HfHubHTTPError] For other API errors.
|
|
756
|
+
def duplicate_space(from_repo_id:, to_repo_id:, private: nil, organization: nil, timeout: nil)
|
|
757
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(from_repo_id)
|
|
758
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(to_repo_id)
|
|
759
|
+
|
|
760
|
+
path = "/api/spaces/#{from_repo_id}/duplicate"
|
|
761
|
+
payload = { newPath: to_repo_id }
|
|
762
|
+
payload[:private] = private unless private.nil?
|
|
763
|
+
payload[:organization] = organization unless organization.nil?
|
|
764
|
+
|
|
765
|
+
response = http_client.post(path, body: payload, timeout: timeout)
|
|
766
|
+
body = response.body.is_a?(String) ? JSON.parse(response.body) : response.body
|
|
767
|
+
body["url"]
|
|
768
|
+
end
|
|
769
|
+
|
|
770
|
+
# Upload a file to a repository on the HuggingFace Hub.
|
|
771
|
+
#
|
|
772
|
+
# @param repo_id [String] The ID of the repository.
|
|
773
|
+
# @param path_or_fileobj [String, Pathname, IO] The path to the file on the local filesystem, or an IO object.
|
|
774
|
+
# @param path_in_repo [String] The path to the file within the repository.
|
|
775
|
+
# @param repo_type [String, Symbol] The type of the repository. Defaults to "model".
|
|
776
|
+
# @param revision [String, nil] The Git revision (branch, tag, or commit SHA) to upload to. Defaults to "main".
|
|
777
|
+
# @param commit_message [String, nil] A custom commit message for the upload.
|
|
778
|
+
# @param commit_description [String, nil] A custom commit description.
|
|
779
|
+
# @param timeout [Numeric, nil] Request timeout in seconds.
|
|
780
|
+
# @return [String] The URL of the uploaded file.
|
|
781
|
+
# @raise [ArgumentError] If parameters are invalid.
|
|
782
|
+
# @raise [DurableHuggingfaceHub::RepositoryNotFoundError] If the repository does not exist.
|
|
783
|
+
# @raise [DurableHuggingfaceHub::HfHubHTTPError] For other API errors.
|
|
784
|
+
def upload_file(
|
|
785
|
+
repo_id:,
|
|
786
|
+
path_or_fileobj:,
|
|
787
|
+
path_in_repo:,
|
|
788
|
+
repo_type: "model",
|
|
789
|
+
revision: nil,
|
|
790
|
+
commit_message: nil,
|
|
791
|
+
commit_description: nil,
|
|
792
|
+
timeout: nil
|
|
793
|
+
)
|
|
794
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(repo_id)
|
|
795
|
+
repo_type = DurableHuggingfaceHub::Utils::Validators.validate_repo_type(repo_type)
|
|
796
|
+
revision = DurableHuggingfaceHub::Utils::Validators.validate_revision(revision) if revision
|
|
797
|
+
revision ||= "main"
|
|
798
|
+
|
|
799
|
+
path = "/api/#{repo_type}s/#{repo_id}/upload/#{path_in_repo}"
|
|
800
|
+
params = {
|
|
801
|
+
commit_message: commit_message || "Upload #{path_in_repo}",
|
|
802
|
+
commit_description: commit_description,
|
|
803
|
+
revision: revision
|
|
804
|
+
}.compact
|
|
805
|
+
|
|
806
|
+
file_content = if path_or_fileobj.is_a?(String) || path_or_fileobj.is_a?(Pathname)
|
|
807
|
+
Faraday::Multipart::FilePart.new(path_or_fileobj, "application/octet-stream", Pathname(path_or_fileobj).basename.to_s)
|
|
808
|
+
else # Assume IO object
|
|
809
|
+
Faraday::Multipart::FilePart.new(path_or_fileobj, "application/octet-stream")
|
|
810
|
+
end
|
|
811
|
+
|
|
812
|
+
payload = {
|
|
813
|
+
file: file_content
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
response = http_client.post(path, params: params, body: payload, timeout: timeout)
|
|
817
|
+
body = response.body.is_a?(String) ? JSON.parse(response.body) : response.body
|
|
818
|
+
body["url"]
|
|
819
|
+
end
|
|
820
|
+
|
|
821
|
+
# Upload an entire folder to a repository on the HuggingFace Hub.
|
|
822
|
+
#
|
|
823
|
+
# This method iterates through all files in a local folder and uploads them
|
|
824
|
+
# to the specified repository, maintaining the folder structure.
|
|
825
|
+
#
|
|
826
|
+
# @param repo_id [String] The ID of the repository.
|
|
827
|
+
# @param folder_path [String, Pathname] The path to the local folder to upload.
|
|
828
|
+
# @param repo_type [String, Symbol] The type of the repository. Defaults to "model".
|
|
829
|
+
# @param revision [String, nil] The Git revision (branch, tag, or commit SHA) to upload to. Defaults to "main".
|
|
830
|
+
# @param commit_message [String, nil] A custom commit message for the upload.
|
|
831
|
+
# @param commit_description [String, nil] A custom commit description.
|
|
832
|
+
# @param timeout [Numeric, nil] Request timeout in seconds.
|
|
833
|
+
# @return [Array<String>] A list of URLs of the uploaded files.
|
|
834
|
+
# @raise [ArgumentError] If parameters are invalid or folder_path does not exist.
|
|
835
|
+
# @raise [DurableHuggingfaceHub::RepositoryNotFoundError] If the repository does not exist.
|
|
836
|
+
# @raise [DurableHuggingfaceHub::HfHubHTTPError] For other API errors.
|
|
837
|
+
def upload_folder(
|
|
838
|
+
repo_id:,
|
|
839
|
+
folder_path:,
|
|
840
|
+
repo_type: "model",
|
|
841
|
+
revision: nil,
|
|
842
|
+
commit_message: nil,
|
|
843
|
+
commit_description: nil,
|
|
844
|
+
timeout: nil
|
|
845
|
+
)
|
|
846
|
+
folder_path = Pathname(folder_path)
|
|
847
|
+
raise ArgumentError, "Folder not found: #{folder_path}" unless folder_path.directory?
|
|
848
|
+
|
|
849
|
+
uploaded_urls = []
|
|
850
|
+
Dir.glob(File.join(folder_path, "**", "*")).each do |file_path_str|
|
|
851
|
+
file_path = Pathname(file_path_str)
|
|
852
|
+
next if file_path.directory?
|
|
853
|
+
|
|
854
|
+
relative_path = file_path.relative_path_from(folder_path).to_s
|
|
855
|
+
|
|
856
|
+
uploaded_urls << upload_file(
|
|
857
|
+
repo_id: repo_id,
|
|
858
|
+
path_or_fileobj: file_path,
|
|
859
|
+
path_in_repo: relative_path,
|
|
860
|
+
repo_type: repo_type,
|
|
861
|
+
revision: revision,
|
|
862
|
+
commit_message: commit_message,
|
|
863
|
+
commit_description: commit_description,
|
|
864
|
+
timeout: timeout
|
|
865
|
+
)
|
|
866
|
+
end
|
|
867
|
+
uploaded_urls
|
|
868
|
+
end
|
|
869
|
+
|
|
870
|
+
# Delete a file from a repository on the HuggingFace Hub.
|
|
871
|
+
#
|
|
872
|
+
# @param repo_id [String] The ID of the repository.
|
|
873
|
+
# @param path_in_repo [String] The path to the file within the repository to delete.
|
|
874
|
+
# @param repo_type [String, Symbol] The type of the repository. Defaults to "model".
|
|
875
|
+
# @param revision [String, nil] The Git revision (branch, tag, or commit SHA) to delete from. Defaults to "main".
|
|
876
|
+
# @param commit_message [String, nil] A custom commit message for the deletion.
|
|
877
|
+
# @param commit_description [String, nil] A custom commit description.
|
|
878
|
+
# @param timeout [Numeric, nil] Request timeout in seconds.
|
|
879
|
+
# @return [Boolean] True if the file was successfully deleted.
|
|
880
|
+
# @raise [ArgumentError] If parameters are invalid.
|
|
881
|
+
# @raise [DurableHuggingfaceHub::RepositoryNotFoundError] If the repository does not exist.
|
|
882
|
+
# @raise [DurableHuggingfaceHub::EntryNotFoundError] If the file does not exist in the repository.
|
|
883
|
+
# @raise [DurableHuggingfaceHub::HfHubHTTPError] For other API errors.
|
|
884
|
+
def delete_file(
|
|
885
|
+
repo_id:,
|
|
886
|
+
path_in_repo:,
|
|
887
|
+
repo_type: "model",
|
|
888
|
+
revision: nil,
|
|
889
|
+
commit_message: nil,
|
|
890
|
+
commit_description: nil,
|
|
891
|
+
timeout: nil
|
|
892
|
+
)
|
|
893
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(repo_id)
|
|
894
|
+
repo_type = DurableHuggingfaceHub::Utils::Validators.validate_repo_type(repo_type)
|
|
895
|
+
revision = DurableHuggingfaceHub::Utils::Validators.validate_revision(revision) if revision
|
|
896
|
+
revision ||= "main"
|
|
897
|
+
|
|
898
|
+
path = "/api/#{repo_type}s/#{repo_id}/upload/#{path_in_repo}"
|
|
899
|
+
params = {
|
|
900
|
+
commit_message: commit_message || "Delete #{path_in_repo}",
|
|
901
|
+
commit_description: commit_description,
|
|
902
|
+
revision: revision
|
|
903
|
+
}.compact
|
|
904
|
+
|
|
905
|
+
http_client.delete(path, params: params)
|
|
906
|
+
true
|
|
907
|
+
end
|
|
908
|
+
|
|
909
|
+
# Delete an entire folder from a repository on the HuggingFace Hub.
|
|
910
|
+
#
|
|
911
|
+
# This method lists all files within the specified folder in the repository
|
|
912
|
+
# and deletes them one by one.
|
|
913
|
+
#
|
|
914
|
+
# @param repo_id [String] The ID of the repository.
|
|
915
|
+
# @param folder_path_in_repo [String] The path to the folder within the repository to delete.
|
|
916
|
+
# @param repo_type [String, Symbol] The type of the repository. Defaults to "model".
|
|
917
|
+
# @param revision [String, nil] The Git revision (branch, tag, or commit SHA) to delete from. Defaults to "main".
|
|
918
|
+
# @param commit_message [String, nil] A custom commit message for the deletion.
|
|
919
|
+
# @param commit_description [String, nil] A custom commit description.
|
|
920
|
+
# @param timeout [Numeric, nil] Request timeout in seconds.
|
|
921
|
+
# @return [Boolean] True if the folder and its contents were successfully deleted.
|
|
922
|
+
# @raise [ArgumentError] If parameters are invalid.
|
|
923
|
+
# @raise [DurableHuggingfaceHub::RepositoryNotFoundError] If the repository does not exist.
|
|
924
|
+
# @raise [DurableHuggingfaceHub::HfHubHTTPError] For other API errors.
|
|
925
|
+
def delete_folder(
|
|
926
|
+
repo_id:,
|
|
927
|
+
folder_path_in_repo:,
|
|
928
|
+
repo_type: "model",
|
|
929
|
+
revision: nil,
|
|
930
|
+
commit_message: nil,
|
|
931
|
+
commit_description: nil,
|
|
932
|
+
timeout: nil
|
|
933
|
+
)
|
|
934
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(repo_id)
|
|
935
|
+
repo_type = DurableHuggingfaceHub::Utils::Validators.validate_repo_type(repo_type)
|
|
936
|
+
revision = DurableHuggingfaceHub::Utils::Validators.validate_revision(revision) if revision
|
|
937
|
+
revision ||= "main"
|
|
938
|
+
|
|
939
|
+
# List all files in the folder
|
|
940
|
+
files_to_delete = list_repo_files(
|
|
941
|
+
repo_id: repo_id,
|
|
942
|
+
repo_type: repo_type,
|
|
943
|
+
revision: revision,
|
|
944
|
+
timeout: timeout
|
|
945
|
+
).select { |file_path| file_path.start_with?(folder_path_in_repo) }
|
|
946
|
+
|
|
947
|
+
# Delete each file
|
|
948
|
+
files_to_delete.each do |file_path|
|
|
949
|
+
delete_file(
|
|
950
|
+
repo_id: repo_id,
|
|
951
|
+
path_in_repo: file_path,
|
|
952
|
+
repo_type: repo_type,
|
|
953
|
+
revision: revision,
|
|
954
|
+
commit_message: commit_message || "Delete #{file_path} from #{folder_path_in_repo}",
|
|
955
|
+
commit_description: commit_description,
|
|
956
|
+
timeout: timeout
|
|
957
|
+
)
|
|
958
|
+
end
|
|
959
|
+
true
|
|
960
|
+
end
|
|
961
|
+
|
|
962
|
+
# Check if a file exists in a repository on the HuggingFace Hub.
|
|
963
|
+
#
|
|
964
|
+
# @param repo_id [String] The ID of the repository.
|
|
965
|
+
# @param path_in_repo [String] The path to the file within the repository to check.
|
|
966
|
+
# @param repo_type [String, Symbol] The type of the repository. Defaults to "model".
|
|
967
|
+
# @param revision [String, nil] The Git revision (branch, tag, or commit SHA) to check. Defaults to "main".
|
|
968
|
+
# @param timeout [Numeric, nil] Request timeout in seconds.
|
|
969
|
+
# @return [Boolean] True if the file exists, false otherwise.
|
|
970
|
+
# @raise [ArgumentError] If parameters are invalid.
|
|
971
|
+
# @raise [DurableHuggingfaceHub::RepositoryNotFoundError] If the repository does not exist.
|
|
972
|
+
# @raise [DurableHuggingfaceHub::HfHubHTTPError] For other API errors.
|
|
973
|
+
def file_exists(repo_id:, path_in_repo:, repo_type: "model", revision: nil, timeout: nil)
|
|
974
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(repo_id)
|
|
975
|
+
repo_type = DurableHuggingfaceHub::Utils::Validators.validate_repo_type(repo_type)
|
|
976
|
+
revision = DurableHuggingfaceHub::Utils::Validators.validate_revision(revision) if revision
|
|
977
|
+
revision ||= "main"
|
|
978
|
+
|
|
979
|
+
path = "/api/#{repo_type}s/#{repo_id}/resolve/#{revision}/#{path_in_repo}"
|
|
980
|
+
begin
|
|
981
|
+
http_client.head(path, timeout: timeout)
|
|
982
|
+
true
|
|
983
|
+
rescue DurableHuggingfaceHub::RepositoryNotFoundError, DurableHuggingfaceHub::EntryNotFoundError
|
|
984
|
+
false
|
|
985
|
+
end
|
|
986
|
+
end
|
|
987
|
+
|
|
988
|
+
# Create a new commit with multiple file operations.
|
|
989
|
+
#
|
|
990
|
+
# @param repo_id [String] The ID of the repository.
|
|
991
|
+
# @param operations [Array<Hash>] An array of file operations (add, delete, update).
|
|
992
|
+
# Each operation is a hash with at least a `:path` and `:operation` key.
|
|
993
|
+
# Example: [{ path: "file.txt", operation: "add", content: "new content" }]
|
|
994
|
+
# @param repo_type [String, Symbol] The type of the repository. Defaults to "model".
|
|
995
|
+
# @param revision [String, nil] The Git revision (branch, tag, or commit SHA) to commit to. Defaults to "main".
|
|
996
|
+
# @param commit_message [String, nil] A custom commit message for the upload.
|
|
997
|
+
# @param commit_description [String, nil] A custom commit description.
|
|
998
|
+
# @param parent_commit [String, nil] The SHA of the parent commit.
|
|
999
|
+
# @param timeout [Numeric, nil] Request timeout in seconds.
|
|
1000
|
+
# @return [String] The SHA of the newly created commit.
|
|
1001
|
+
# @raise [ArgumentError] If parameters are invalid.
|
|
1002
|
+
# @raise [DurableHuggingfaceHub::RepositoryNotFoundError] If the repository does not exist.
|
|
1003
|
+
# @raise [DurableHuggingfaceHub::HfHubHTTPError] For other API errors.
|
|
1004
|
+
def create_commit(
|
|
1005
|
+
repo_id:,
|
|
1006
|
+
operations:,
|
|
1007
|
+
repo_type: "model",
|
|
1008
|
+
revision: nil,
|
|
1009
|
+
commit_message: nil,
|
|
1010
|
+
commit_description: nil,
|
|
1011
|
+
parent_commit: nil,
|
|
1012
|
+
timeout: nil
|
|
1013
|
+
)
|
|
1014
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(repo_id)
|
|
1015
|
+
repo_type = DurableHuggingfaceHub::Utils::Validators.validate_repo_type(repo_type)
|
|
1016
|
+
revision = DurableHuggingfaceHub::Utils::Validators.validate_revision(revision) if revision
|
|
1017
|
+
revision ||= "main"
|
|
1018
|
+
|
|
1019
|
+
path = "/api/#{repo_type}s/#{repo_id}/commits/#{revision}"
|
|
1020
|
+
payload = {
|
|
1021
|
+
operations: operations,
|
|
1022
|
+
commit_message: commit_message || "Commit from Ruby client",
|
|
1023
|
+
commit_description: commit_description,
|
|
1024
|
+
parent_commit: parent_commit
|
|
1025
|
+
}.compact
|
|
1026
|
+
|
|
1027
|
+
response = http_client.post(path, body: payload, timeout: timeout)
|
|
1028
|
+
body = response.body.is_a?(String) ? JSON.parse(response.body) : response.body
|
|
1029
|
+
body["commit_id"]
|
|
1030
|
+
end
|
|
1031
|
+
|
|
1032
|
+
# Create a new branch in a repository.
|
|
1033
|
+
#
|
|
1034
|
+
# @param repo_id [String] The ID of the repository.
|
|
1035
|
+
# @param branch_name [String] The name of the new branch.
|
|
1036
|
+
# @param repo_type [String, Symbol] The type of the repository. Defaults to "model".
|
|
1037
|
+
# @param revision [String, nil] The Git revision (branch, tag, or commit SHA) to branch from. Defaults to "main".
|
|
1038
|
+
# @param timeout [Numeric, nil] Request timeout in seconds.
|
|
1039
|
+
# @return [String] The name of the newly created branch.
|
|
1040
|
+
# @raise [ArgumentError] If parameters are invalid.
|
|
1041
|
+
# @raise [DurableHuggingfaceHub::RepositoryNotFoundError] If the repository does not exist.
|
|
1042
|
+
# @raise [DurableHuggingfaceHub::HfHubHTTPError] For other API errors (e.g., branch already exists).
|
|
1043
|
+
def create_branch(repo_id:, branch_name:, repo_type: "model", revision: nil, timeout: nil)
|
|
1044
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(repo_id)
|
|
1045
|
+
repo_type = DurableHuggingfaceHub::Utils::Validators.validate_repo_type(repo_type)
|
|
1046
|
+
revision = DurableHuggingfaceHub::Utils::Validators.validate_revision(revision) if revision
|
|
1047
|
+
revision ||= "main"
|
|
1048
|
+
|
|
1049
|
+
path = "/api/#{repo_type}s/#{repo_id}/branches"
|
|
1050
|
+
payload = {
|
|
1051
|
+
name: branch_name,
|
|
1052
|
+
revision: revision
|
|
1053
|
+
}.compact
|
|
1054
|
+
|
|
1055
|
+
response = http_client.post(path, body: payload, timeout: timeout)
|
|
1056
|
+
body = response.body.is_a?(String) ? JSON.parse(response.body) : response.body
|
|
1057
|
+
body["name"]
|
|
1058
|
+
end
|
|
1059
|
+
|
|
1060
|
+
# Delete a branch from a repository.
|
|
1061
|
+
#
|
|
1062
|
+
# @param repo_id [String] The ID of the repository.
|
|
1063
|
+
# @param branch_name [String] The name of the branch to delete.
|
|
1064
|
+
# @param repo_type [String, Symbol] The type of the repository. Defaults to "model".
|
|
1065
|
+
# @param timeout [Numeric, nil] Request timeout in seconds.
|
|
1066
|
+
# @return [Boolean] True if the branch was successfully deleted.
|
|
1067
|
+
# @raise [ArgumentError] If parameters are invalid.
|
|
1068
|
+
# @raise [DurableHuggingfaceHub::RepositoryNotFoundError] If the repository does not exist.
|
|
1069
|
+
# @raise [DurableHuggingfaceHub::RevisionNotFoundError] If the branch does not exist.
|
|
1070
|
+
# @raise [DurableHuggingfaceHub::HfHubHTTPError] For other API errors.
|
|
1071
|
+
def delete_branch(repo_id:, branch_name:, repo_type: "model", timeout: nil)
|
|
1072
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(repo_id)
|
|
1073
|
+
repo_type = DurableHuggingfaceHub::Utils::Validators.validate_repo_type(repo_type)
|
|
1074
|
+
|
|
1075
|
+
path = "/api/#{repo_type}s/#{repo_id}/branches/#{branch_name}"
|
|
1076
|
+
http_client.delete(path)
|
|
1077
|
+
true
|
|
1078
|
+
end
|
|
1079
|
+
|
|
1080
|
+
# Create a new tag in a repository.
|
|
1081
|
+
#
|
|
1082
|
+
# @param repo_id [String] The ID of the repository.
|
|
1083
|
+
# @param tag_name [String] The name of the new tag.
|
|
1084
|
+
# @param repo_type [String, Symbol] The type of the repository. Defaults to "model".
|
|
1085
|
+
# @param revision [String, nil] The Git revision (branch, tag, or commit SHA) to tag from. Defaults to "main".
|
|
1086
|
+
# @param message [String, nil] An optional message for the tag.
|
|
1087
|
+
# @param timeout [Numeric, nil] Request timeout in seconds.
|
|
1088
|
+
# @return [String] The name of the newly created tag.
|
|
1089
|
+
# @raise [ArgumentError] If parameters are invalid.
|
|
1090
|
+
# @raise [DurableHuggingfaceHub::RepositoryNotFoundError] If the repository does not exist.
|
|
1091
|
+
# @raise [DurableHuggingfaceHub::HfHubHTTPError] For other API errors (e.g., tag already exists).
|
|
1092
|
+
def create_tag(repo_id:, tag_name:, repo_type: "model", revision: nil, message: nil, timeout: nil)
|
|
1093
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(repo_id)
|
|
1094
|
+
repo_type = DurableHuggingfaceHub::Utils::Validators.validate_repo_type(repo_type)
|
|
1095
|
+
revision = DurableHuggingfaceHub::Utils::Validators.validate_revision(revision) if revision
|
|
1096
|
+
revision ||= "main"
|
|
1097
|
+
|
|
1098
|
+
path = "/api/#{repo_type}s/#{repo_id}/tags"
|
|
1099
|
+
payload = {
|
|
1100
|
+
name: tag_name,
|
|
1101
|
+
revision: revision,
|
|
1102
|
+
message: message
|
|
1103
|
+
}.compact
|
|
1104
|
+
|
|
1105
|
+
response = http_client.post(path, body: payload, timeout: timeout)
|
|
1106
|
+
body = response.body.is_a?(String) ? JSON.parse(response.body) : response.body
|
|
1107
|
+
body["name"]
|
|
1108
|
+
end
|
|
1109
|
+
|
|
1110
|
+
# Delete a tag from a repository.
|
|
1111
|
+
#
|
|
1112
|
+
# @param repo_id [String] The ID of the repository.
|
|
1113
|
+
# @param tag_name [String] The name of the tag to delete.
|
|
1114
|
+
# @param repo_type [String, Symbol] The type of the repository. Defaults to "model".
|
|
1115
|
+
# @param timeout [Numeric, nil] Request timeout in seconds.
|
|
1116
|
+
# @return [Boolean] True if the tag was successfully deleted.
|
|
1117
|
+
# @raise [ArgumentError] If parameters are invalid.
|
|
1118
|
+
# @raise [DurableHuggingfaceHub::RepositoryNotFoundError] If the repository does not exist.
|
|
1119
|
+
# @raise [DurableHuggingfaceHub::RevisionNotFoundError] If the tag does not exist.
|
|
1120
|
+
# @raise [DurableHuggingfaceHub::HfHubHTTPError] For other API errors.
|
|
1121
|
+
def delete_tag(repo_id:, tag_name:, repo_type: "model", timeout: nil)
|
|
1122
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(repo_id)
|
|
1123
|
+
repo_type = DurableHuggingfaceHub::Utils::Validators.validate_repo_type(repo_type)
|
|
1124
|
+
|
|
1125
|
+
path = "/api/#{repo_type}s/#{repo_id}/tags/#{tag_name}"
|
|
1126
|
+
http_client.delete(path)
|
|
1127
|
+
true
|
|
1128
|
+
end
|
|
1129
|
+
|
|
1130
|
+
# List branches and tags (refs) for a repository.
|
|
1131
|
+
#
|
|
1132
|
+
# @param repo_id [String] The ID of the repository.
|
|
1133
|
+
# @param repo_type [String, Symbol] The type of the repository. Defaults to "model".
|
|
1134
|
+
# @param timeout [Numeric, nil] Request timeout in seconds.
|
|
1135
|
+
# @return [Hash] A hash containing arrays of "branches" and "tags".
|
|
1136
|
+
# @raise [ArgumentError] If repo_id or repo_type is invalid.
|
|
1137
|
+
# @raise [DurableHuggingfaceHub::RepositoryNotFoundError] If the repository does not exist.
|
|
1138
|
+
# @raise [DurableHuggingfaceHub::HfHubHTTPError] For other API errors.
|
|
1139
|
+
def list_repo_refs(repo_id:, repo_type: "model", timeout: nil)
|
|
1140
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(repo_id)
|
|
1141
|
+
repo_type = DurableHuggingfaceHub::Utils::Validators.validate_repo_type(repo_type)
|
|
1142
|
+
|
|
1143
|
+
path = "/api/#{repo_type}s/#{repo_id}/refs"
|
|
1144
|
+
response = http_client.get(path, timeout: timeout)
|
|
1145
|
+
|
|
1146
|
+
body = response.body.is_a?(String) ? JSON.parse(response.body) : response.body
|
|
1147
|
+
branches = body["branches"].map { |branch_data| DurableHuggingfaceHub::Types::GitRefInfo.from_hash(branch_data) }
|
|
1148
|
+
tags = body["tags"].map { |tag_data| DurableHuggingfaceHub::Types::GitRefInfo.from_hash(tag_data) }
|
|
1149
|
+
|
|
1150
|
+
{ branches: branches, tags: tags }
|
|
1151
|
+
end
|
|
1152
|
+
|
|
1153
|
+
# List commit history for a repository.
|
|
1154
|
+
#
|
|
1155
|
+
# @param repo_id [String] The ID of the repository.
|
|
1156
|
+
# @param repo_type [String, Symbol] The type of the repository. Defaults to "model".
|
|
1157
|
+
# @param revision [String, nil] The Git revision (branch, tag, or commit SHA) to list commits from. Defaults to "main".
|
|
1158
|
+
# @param limit [Integer, nil] The maximum number of commits to return.
|
|
1159
|
+
# @param timeout [Numeric, nil] Request timeout in seconds.
|
|
1160
|
+
# @return [Array<DurableHuggingfaceHub::Types::CommitInfo>] A list of commit information objects.
|
|
1161
|
+
# @raise [ArgumentError] If repo_id or repo_type is invalid.
|
|
1162
|
+
# @raise [DurableHuggingfaceHub::RepositoryNotFoundError] If the repository does not exist.
|
|
1163
|
+
# @raise [DurableHuggingfaceHub::RevisionNotFoundError] If the revision does not exist.
|
|
1164
|
+
# @raise [DurableHuggingfaceHub::HfHubHTTPError] For other API errors.
|
|
1165
|
+
def list_repo_commits(repo_id:, repo_type: "model", revision: nil, limit: nil, timeout: nil)
|
|
1166
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(repo_id)
|
|
1167
|
+
repo_type = DurableHuggingfaceHub::Utils::Validators.validate_repo_type(repo_type)
|
|
1168
|
+
revision = DurableHuggingfaceHub::Utils::Validators.validate_revision(revision) if revision
|
|
1169
|
+
revision ||= "main"
|
|
1170
|
+
|
|
1171
|
+
path = "/api/#{repo_type}s/#{repo_id}/commits"
|
|
1172
|
+
params = {
|
|
1173
|
+
revision: revision,
|
|
1174
|
+
limit: limit
|
|
1175
|
+
}.compact
|
|
1176
|
+
|
|
1177
|
+
response = http_client.get(path, params: params, timeout: timeout)
|
|
1178
|
+
body = response.body.is_a?(String) ? JSON.parse(response.body) : response.body
|
|
1179
|
+
body.map do |commit_data|
|
|
1180
|
+
# Flatten the nested commit structure
|
|
1181
|
+
commit = commit_data["commit"]
|
|
1182
|
+
author = commit["author"]
|
|
1183
|
+
{
|
|
1184
|
+
oid: commit["id"],
|
|
1185
|
+
title: commit["message"]&.split("\n")&.first, # First line as title
|
|
1186
|
+
message: commit["message"],
|
|
1187
|
+
date: author ? Time.parse(author["date"]) : nil,
|
|
1188
|
+
authors: author ? [author["name"]] : nil
|
|
1189
|
+
}.compact
|
|
1190
|
+
end.map { |data| DurableHuggingfaceHub::Types::CommitInfo.from_hash(data) }
|
|
1191
|
+
end
|
|
1192
|
+
|
|
1193
|
+
# List Git LFS files in a repository.
|
|
1194
|
+
#
|
|
1195
|
+
# @param repo_id [String] The ID of the repository.
|
|
1196
|
+
# @param repo_type [String, Symbol] The type of the repository. Defaults to "model".
|
|
1197
|
+
# @param revision [String, nil] The Git revision (branch, tag, or commit SHA) to list LFS files from. Defaults to "main".
|
|
1198
|
+
# @param timeout [Numeric, nil] Request timeout in seconds.
|
|
1199
|
+
# @return [Array<Hash>] A list of LFS file information hashes.
|
|
1200
|
+
# @raise [ArgumentError] If repo_id or repo_type is invalid.
|
|
1201
|
+
# @raise [DurableHuggingfaceHub::RepositoryNotFoundError] If the repository does not exist.
|
|
1202
|
+
# @raise [DurableHuggingfaceHub::RevisionNotFoundError] If the revision does not exist.
|
|
1203
|
+
# @raise [DurableHuggingfaceHub::HfHubHTTPError] For other API errors.
|
|
1204
|
+
def list_lfs_files(repo_id:, repo_type: "model", revision: nil, timeout: nil)
|
|
1205
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(repo_id)
|
|
1206
|
+
repo_type = DurableHuggingfaceHub::Utils::Validators.validate_repo_type(repo_type)
|
|
1207
|
+
revision = DurableHuggingfaceHub::Utils::Validators.validate_revision(revision) if revision
|
|
1208
|
+
revision ||= "main"
|
|
1209
|
+
|
|
1210
|
+
path = "/api/#{repo_type}s/#{repo_id}/lfs/objects"
|
|
1211
|
+
params = { revision: revision }.compact
|
|
1212
|
+
|
|
1213
|
+
response = http_client.get(path, params: params, timeout: timeout)
|
|
1214
|
+
response.body.is_a?(String) ? JSON.parse(response.body) : response.body
|
|
1215
|
+
end
|
|
1216
|
+
|
|
1217
|
+
# Permanently delete LFS files from a repository.
|
|
1218
|
+
#
|
|
1219
|
+
# @param repo_id [String] The ID of the repository.
|
|
1220
|
+
# @param lfs_oids [Array<String>] A list of LFS object IDs (OIDs) to delete.
|
|
1221
|
+
# @param repo_type [String, Symbol] The type of the repository. Defaults to "model".
|
|
1222
|
+
# @param timeout [Numeric, nil] Request timeout in seconds.
|
|
1223
|
+
# @return [Boolean] True if the LFS files were successfully deleted.
|
|
1224
|
+
# @raise [ArgumentError] If parameters are invalid.
|
|
1225
|
+
# @raise [DurableHuggingfaceHub::RepositoryNotFoundError] If the repository does not exist.
|
|
1226
|
+
# @raise [DurableHuggingfaceHub::HfHubHTTPError] For other API errors.
|
|
1227
|
+
def permanently_delete_lfs_files(repo_id:, lfs_oids:, repo_type: "model", timeout: nil)
|
|
1228
|
+
DurableHuggingfaceHub::Utils::Validators.validate_repo_id(repo_id)
|
|
1229
|
+
repo_type = DurableHuggingfaceHub::Utils::Validators.validate_repo_type(repo_type)
|
|
1230
|
+
|
|
1231
|
+
path = "/api/#{repo_type}s/#{repo_id}/lfs/delete"
|
|
1232
|
+
payload = { oids: lfs_oids }
|
|
1233
|
+
|
|
1234
|
+
http_client.post(path, body: payload, timeout: timeout)
|
|
1235
|
+
true
|
|
1236
|
+
end
|
|
1237
|
+
|
|
1238
|
+
private
|
|
1239
|
+
|
|
1240
|
+
# Build query parameters for list endpoints
|
|
1241
|
+
#
|
|
1242
|
+
# @param filter [String, Hash, nil] Filter criteria
|
|
1243
|
+
# @param author [String, nil] Author filter
|
|
1244
|
+
# @param search [String, nil] Search query
|
|
1245
|
+
# @param sort [String, Symbol, nil] Sort criterion
|
|
1246
|
+
# @param direction [Integer, nil] Sort direction
|
|
1247
|
+
# @param limit [Integer, nil] Result limit
|
|
1248
|
+
# @param full [Boolean] Fetch full information
|
|
1249
|
+
#
|
|
1250
|
+
# @return [Hash] Query parameters
|
|
1251
|
+
def build_list_params(filter:, author:, search:, sort:, direction:, limit:, full:)
|
|
1252
|
+
params = {}
|
|
1253
|
+
|
|
1254
|
+
# Handle filter parameter
|
|
1255
|
+
if filter
|
|
1256
|
+
case filter
|
|
1257
|
+
when String
|
|
1258
|
+
# Single tag or search term
|
|
1259
|
+
params[:filter] = filter
|
|
1260
|
+
when Hash
|
|
1261
|
+
# Structured filters - convert to Hub API format
|
|
1262
|
+
filter.each do |key, value|
|
|
1263
|
+
params[key.to_s] = value
|
|
1264
|
+
end
|
|
1265
|
+
end
|
|
1266
|
+
end
|
|
1267
|
+
|
|
1268
|
+
params[:author] = author if author
|
|
1269
|
+
params[:search] = search if search
|
|
1270
|
+
params[:sort] = sort.to_s if sort
|
|
1271
|
+
params[:direction] = direction if direction
|
|
1272
|
+
params[:limit] = limit if limit
|
|
1273
|
+
params[:full] = full if full
|
|
1274
|
+
|
|
1275
|
+
params
|
|
1276
|
+
end
|
|
1277
|
+
end
|
|
1278
|
+
end
|