atomgit 1.0.0__py3-none-any.whl
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.
- atomgit/__init__.py +36 -0
- atomgit/__main__.py +17 -0
- atomgit/api.py +301 -0
- atomgit/atomgit_hub.py +519 -0
- atomgit/cli.py +290 -0
- atomgit/config.py +67 -0
- atomgit/utils.py +344 -0
- atomgit-1.0.0.dist-info/METADATA +583 -0
- atomgit-1.0.0.dist-info/RECORD +13 -0
- atomgit-1.0.0.dist-info/WHEEL +5 -0
- atomgit-1.0.0.dist-info/entry_points.txt +2 -0
- atomgit-1.0.0.dist-info/top_level.txt +2 -0
- atomgit_hub.py +519 -0
atomgit/__init__.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
AtomGit CLI - 基于Transformers和Hugging Face Hub的模型文件上传下载工具
|
|
6
|
+
|
|
7
|
+
这是一个命令行工具,用于与AtomGit平台交互,
|
|
8
|
+
支持模型和数据集的上传、下载等操作。
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
__version__ = '1.0.0'
|
|
12
|
+
__author__ = 'AtomGit CLI Team'
|
|
13
|
+
__description__ = 'AtomGit模型文件上传下载CLI工具'
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
from .config import config
|
|
17
|
+
from .api import api
|
|
18
|
+
from .cli import cli
|
|
19
|
+
from .atomgit_hub import (
|
|
20
|
+
snapshot_download, hub_download_url, download_file,
|
|
21
|
+
upload_folder, create_repository
|
|
22
|
+
)
|
|
23
|
+
except ImportError:
|
|
24
|
+
from config import config
|
|
25
|
+
from api import api
|
|
26
|
+
from cli import cli
|
|
27
|
+
from atomgit_hub import (
|
|
28
|
+
snapshot_download, hub_download_url, download_file,
|
|
29
|
+
upload_folder, create_repository
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
__all__ = [
|
|
33
|
+
'config', 'api', 'cli',
|
|
34
|
+
'snapshot_download', 'hub_download_url', 'download_file',
|
|
35
|
+
'upload_folder', 'create_repository'
|
|
36
|
+
]
|
atomgit/__main__.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
AtomGit CLI 主入口文件
|
|
6
|
+
|
|
7
|
+
使用方法:
|
|
8
|
+
python -m atomgit [command] [options]
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
try:
|
|
12
|
+
from .cli import cli
|
|
13
|
+
except ImportError:
|
|
14
|
+
from cli import cli
|
|
15
|
+
|
|
16
|
+
if __name__ == '__main__':
|
|
17
|
+
cli()
|
atomgit/api.py
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Optional, Dict, Any
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
import json
|
|
5
|
+
import urllib.request
|
|
6
|
+
import urllib.error
|
|
7
|
+
|
|
8
|
+
# 设置Hugging Face Hub的API端点为AtomGit
|
|
9
|
+
os.environ["HF_ENDPOINT"] = "https://hub.atomgit.com"
|
|
10
|
+
# 设置缓存目录
|
|
11
|
+
cache_dir = os.path.expanduser("~/.cache/atomgit")
|
|
12
|
+
os.makedirs(cache_dir, exist_ok=True)
|
|
13
|
+
os.environ["HF_HOME"] = cache_dir
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
from huggingface_hub import hf_hub_download, upload_folder, create_repo, snapshot_download, whoami
|
|
17
|
+
|
|
18
|
+
try:
|
|
19
|
+
from .config import config
|
|
20
|
+
except ImportError:
|
|
21
|
+
from config import config
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class HuggingFaceAPI:
|
|
25
|
+
"""AtomGit API 客户端,完全基于Hugging Face Hub SDK"""
|
|
26
|
+
|
|
27
|
+
def __init__(self):
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
def _normalize_repo_id(self, repo_id: str) -> str:
|
|
31
|
+
"""标准化仓库ID,处理三层格式转换"""
|
|
32
|
+
parts = repo_id.split('/')
|
|
33
|
+
|
|
34
|
+
# 如果是三层格式(如 hf_mirrors/Qwen/Qwen2.5-Coder-0.5B-Instruct)
|
|
35
|
+
# 转换为特殊格式(如 hf_mirrors-Qwen/Qwen2.5-Coder-0.5B-Instruct)
|
|
36
|
+
if len(parts) >= 3:
|
|
37
|
+
# 只编码第一个斜杠,保留后面的斜杠
|
|
38
|
+
first_part = parts[0]
|
|
39
|
+
second_part = parts[1]
|
|
40
|
+
remaining_parts = parts[2:]
|
|
41
|
+
|
|
42
|
+
# 构建新格式:第一部分-第二部分/其余部分
|
|
43
|
+
normalized = first_part + '-' + second_part
|
|
44
|
+
if remaining_parts:
|
|
45
|
+
normalized += '/' + '/'.join(remaining_parts)
|
|
46
|
+
|
|
47
|
+
print(f"三层仓库名称转换: {repo_id} -> {normalized}")
|
|
48
|
+
return normalized
|
|
49
|
+
|
|
50
|
+
# 二层或单层格式直接返回
|
|
51
|
+
return repo_id
|
|
52
|
+
|
|
53
|
+
def login(self, token: str) -> bool:
|
|
54
|
+
"""登录验证"""
|
|
55
|
+
if not token or len(token) < 10:
|
|
56
|
+
print("❌ Token格式不正确")
|
|
57
|
+
return False
|
|
58
|
+
user_info = self._get_login_user_by_token(token)
|
|
59
|
+
if not user_info:
|
|
60
|
+
print("❌ 获取用户信息失败")
|
|
61
|
+
return False
|
|
62
|
+
config.set_credentials(token)
|
|
63
|
+
print("✅ Token已保存")
|
|
64
|
+
return True
|
|
65
|
+
|
|
66
|
+
def _get_login_user_by_token(self, token: str) -> Optional[Dict[str, Any]]:
|
|
67
|
+
try:
|
|
68
|
+
if not token:
|
|
69
|
+
print("❌ 未找到登录凭证")
|
|
70
|
+
return None
|
|
71
|
+
api_url = 'https://atomgit.com/api/v5/user'
|
|
72
|
+
req = urllib.request.Request(
|
|
73
|
+
api_url,
|
|
74
|
+
headers={
|
|
75
|
+
'Authorization': token,
|
|
76
|
+
'User-Agent': 'atomgit-cli',
|
|
77
|
+
'Accept': 'application/json'
|
|
78
|
+
}
|
|
79
|
+
)
|
|
80
|
+
with urllib.request.urlopen(req, timeout=10) as response:
|
|
81
|
+
if response.status == 200:
|
|
82
|
+
data = json.loads(response.read().decode('utf-8'))
|
|
83
|
+
login = data.get('login')
|
|
84
|
+
if login and login.strip():
|
|
85
|
+
return {
|
|
86
|
+
'login': login,
|
|
87
|
+
'name': data.get('name'),
|
|
88
|
+
'email': data.get('email')
|
|
89
|
+
}
|
|
90
|
+
return None
|
|
91
|
+
except Exception as e:
|
|
92
|
+
return None
|
|
93
|
+
|
|
94
|
+
def get_login_user(self):
|
|
95
|
+
credentials = config.get_credentials()
|
|
96
|
+
if not credentials:
|
|
97
|
+
print("❌ 未找到登录凭证")
|
|
98
|
+
return None
|
|
99
|
+
return self._get_login_user_by_token(credentials['token'])
|
|
100
|
+
|
|
101
|
+
def create_repo(self,
|
|
102
|
+
repo_name: str,
|
|
103
|
+
repo_type: str = "model",
|
|
104
|
+
private: bool = False) -> bool:
|
|
105
|
+
"""创建仓库 - 使用Hugging Face Hub SDK"""
|
|
106
|
+
try:
|
|
107
|
+
credentials = config.get_credentials()
|
|
108
|
+
if not credentials:
|
|
109
|
+
print("❌ 未找到登录凭证")
|
|
110
|
+
return False
|
|
111
|
+
# 使用Hugging Face Hub SDK创建仓库
|
|
112
|
+
create_repo(
|
|
113
|
+
repo_id=repo_name,
|
|
114
|
+
token=credentials['token'],
|
|
115
|
+
repo_type=repo_type,
|
|
116
|
+
private=private,
|
|
117
|
+
exist_ok=True
|
|
118
|
+
)
|
|
119
|
+
return True
|
|
120
|
+
except Exception as e:
|
|
121
|
+
return False
|
|
122
|
+
|
|
123
|
+
def upload_folder(self, file_path: Path, repo_id: str,
|
|
124
|
+
remote_path: str = None, message: str = None) -> bool:
|
|
125
|
+
"""上传文件 - 使用Hugging Face Hub SDK"""
|
|
126
|
+
try:
|
|
127
|
+
if not file_path.exists():
|
|
128
|
+
print(f"文件不存在: {file_path}")
|
|
129
|
+
return False
|
|
130
|
+
|
|
131
|
+
credentials = config.get_credentials()
|
|
132
|
+
if not credentials:
|
|
133
|
+
print("未找到登录凭证")
|
|
134
|
+
return False
|
|
135
|
+
|
|
136
|
+
# 创建一个临时目录在当前工作目录下
|
|
137
|
+
temp_dir = Path.cwd() / ".tmp_upload"
|
|
138
|
+
temp_dir.mkdir(exist_ok=True)
|
|
139
|
+
|
|
140
|
+
try:
|
|
141
|
+
if remote_path:
|
|
142
|
+
# 如果指定了远程路径,创建相应的目录结构
|
|
143
|
+
target_file = temp_dir / remote_path
|
|
144
|
+
target_file.parent.mkdir(parents=True, exist_ok=True)
|
|
145
|
+
else:
|
|
146
|
+
target_file = temp_dir / file_path.name
|
|
147
|
+
# 复制文件到临时目录
|
|
148
|
+
import shutil
|
|
149
|
+
shutil.copy2(file_path, target_file)
|
|
150
|
+
# 使用Hugging Face Hub SDK上传整个目录
|
|
151
|
+
commit_message = message or "Upload folder using atomgit client"
|
|
152
|
+
upload_folder(
|
|
153
|
+
repo_id=repo_id,
|
|
154
|
+
folder_path=str(temp_dir),
|
|
155
|
+
token=credentials['token'],
|
|
156
|
+
commit_message=commit_message
|
|
157
|
+
)
|
|
158
|
+
return True
|
|
159
|
+
finally:
|
|
160
|
+
# 清理临时目录
|
|
161
|
+
import shutil
|
|
162
|
+
if temp_dir.exists():
|
|
163
|
+
shutil.rmtree(temp_dir)
|
|
164
|
+
except Exception as e:
|
|
165
|
+
print(f"上传文件失败: {e}")
|
|
166
|
+
return False
|
|
167
|
+
|
|
168
|
+
def upload_directory(self, dir_path: Path, repo_id: str,
|
|
169
|
+
message: str = None, progress_callback=None) -> bool:
|
|
170
|
+
"""上传目录 - 使用Hugging Face Hub SDK"""
|
|
171
|
+
try:
|
|
172
|
+
if not dir_path.exists() or not dir_path.is_dir():
|
|
173
|
+
print(f"目录不存在: {dir_path}")
|
|
174
|
+
return False
|
|
175
|
+
|
|
176
|
+
credentials = config.get_credentials()
|
|
177
|
+
if not credentials:
|
|
178
|
+
print("未找到登录凭证")
|
|
179
|
+
return False
|
|
180
|
+
|
|
181
|
+
# 直接使用Hugging Face Hub SDK上传目录
|
|
182
|
+
commit_message = message or "Upload folder using atomgit client"
|
|
183
|
+
upload_folder(
|
|
184
|
+
repo_id=repo_id,
|
|
185
|
+
folder_path=str(dir_path),
|
|
186
|
+
token=credentials['token'],
|
|
187
|
+
commit_message=commit_message
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
return True
|
|
191
|
+
|
|
192
|
+
except Exception as e:
|
|
193
|
+
print(f"上传目录失败: {e}")
|
|
194
|
+
return False
|
|
195
|
+
|
|
196
|
+
def download_repo(self, repo_id: str, local_path: Path = None, force_download: bool = False) -> bool:
|
|
197
|
+
"""下载仓库 - 使用Hugging Face Hub SDK,支持公开仓库无需token和断点续传"""
|
|
198
|
+
try:
|
|
199
|
+
# 标准化仓库ID(处理三层格式)
|
|
200
|
+
normalized_repo_id = self._normalize_repo_id(repo_id)
|
|
201
|
+
|
|
202
|
+
if local_path is None:
|
|
203
|
+
local_path = Path.cwd() / repo_id.split('/')[-1]
|
|
204
|
+
|
|
205
|
+
# 创建本地目录
|
|
206
|
+
local_path.mkdir(parents=True, exist_ok=True)
|
|
207
|
+
|
|
208
|
+
# 首先尝试不使用token下载(适用于公开仓库)
|
|
209
|
+
credentials = config.get_credentials()
|
|
210
|
+
try:
|
|
211
|
+
snapshot_download(
|
|
212
|
+
repo_id=normalized_repo_id,
|
|
213
|
+
local_dir=str(local_path),
|
|
214
|
+
force_download=force_download, # 根据用户选择决定是否强制下载
|
|
215
|
+
token=credentials['token'] if credentials and 'token' in credentials else None
|
|
216
|
+
)
|
|
217
|
+
print(f"✅ 仓库下载成功")
|
|
218
|
+
return True
|
|
219
|
+
except Exception as e:
|
|
220
|
+
error_msg = str(e)
|
|
221
|
+
# 其他类型的错误(如仓库不存在)
|
|
222
|
+
print(f"仓库下载失败: {error_msg}")
|
|
223
|
+
return False
|
|
224
|
+
except Exception as e:
|
|
225
|
+
print(f"下载仓库失败: {e}")
|
|
226
|
+
return False
|
|
227
|
+
|
|
228
|
+
def download_file(self, repo_id: str, filename: str, local_path: Path = None, force_download: bool = False) -> bool:
|
|
229
|
+
"""下载单个文件 - 使用Hugging Face Hub SDK,支持公开仓库无需token和断点续传"""
|
|
230
|
+
try:
|
|
231
|
+
# 标准化仓库ID(处理三层格式)
|
|
232
|
+
normalized_repo_id = self._normalize_repo_id(repo_id)
|
|
233
|
+
|
|
234
|
+
if local_path is None:
|
|
235
|
+
local_path = Path.cwd()
|
|
236
|
+
|
|
237
|
+
# 创建本地目录
|
|
238
|
+
local_path.mkdir(parents=True, exist_ok=True)
|
|
239
|
+
|
|
240
|
+
# 首先尝试不使用token下载(适用于公开仓库)
|
|
241
|
+
try:
|
|
242
|
+
hf_hub_download(
|
|
243
|
+
repo_id=normalized_repo_id,
|
|
244
|
+
filename=filename,
|
|
245
|
+
local_dir=str(local_path)
|
|
246
|
+
)
|
|
247
|
+
print(f"✅ 文件下载成功")
|
|
248
|
+
return True
|
|
249
|
+
except Exception as e:
|
|
250
|
+
error_msg = str(e)
|
|
251
|
+
print(f"公开下载失败: {error_msg}")
|
|
252
|
+
|
|
253
|
+
# 检查是否是认证问题
|
|
254
|
+
if "403" in error_msg or "FORBIDDEN" in error_msg or "no scopes" in error_msg:
|
|
255
|
+
print("检测到认证问题,尝试使用token下载...")
|
|
256
|
+
|
|
257
|
+
# 如果公开下载失败,尝试使用token下载
|
|
258
|
+
credentials = config.get_credentials()
|
|
259
|
+
if credentials:
|
|
260
|
+
try:
|
|
261
|
+
hf_hub_download(
|
|
262
|
+
repo_id=normalized_repo_id,
|
|
263
|
+
filename=filename,
|
|
264
|
+
local_dir=str(local_path),
|
|
265
|
+
token=credentials['token']
|
|
266
|
+
)
|
|
267
|
+
print(f"✅ 下载完成")
|
|
268
|
+
return True
|
|
269
|
+
except Exception as token_e:
|
|
270
|
+
print(f"下载失败: {token_e}")
|
|
271
|
+
return False
|
|
272
|
+
else:
|
|
273
|
+
print("未找到登录凭证,无法尝试私有仓库下载")
|
|
274
|
+
print("💡 建议:如果这是私有仓库,请先使用 'atomgit login' 登录")
|
|
275
|
+
return False
|
|
276
|
+
else:
|
|
277
|
+
# 其他类型的错误(如仓库不存在、文件不存在)
|
|
278
|
+
print(f"文件下载失败: {error_msg}")
|
|
279
|
+
return False
|
|
280
|
+
|
|
281
|
+
except Exception as e:
|
|
282
|
+
print(f"下载文件失败: {e}")
|
|
283
|
+
return False
|
|
284
|
+
|
|
285
|
+
def get_repo_info(self, repo_id: str) -> Optional[Dict[str, Any]]:
|
|
286
|
+
"""获取仓库信息 - 此功能需要Hugging Face Hub SDK支持"""
|
|
287
|
+
try:
|
|
288
|
+
# 目前Hugging Face Hub SDK可能不直接支持获取仓库信息
|
|
289
|
+
# 这里返回基础信息
|
|
290
|
+
return {
|
|
291
|
+
"repo_id": repo_id,
|
|
292
|
+
"status": "需要Hugging Face Hub SDK支持"
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
except Exception as e:
|
|
296
|
+
print(f"获取仓库信息失败: {e}")
|
|
297
|
+
return None
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
# 全局API实例
|
|
301
|
+
api = HuggingFaceAPI()
|