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 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()