xiaoshiai-hub 1.1.1__py3-none-any.whl → 1.1.3__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.
xiaoshiai_hub/__init__.py CHANGED
@@ -28,6 +28,10 @@ from .auth import (
28
28
  load_token,
29
29
  delete_token,
30
30
  )
31
+ from .envelope_crypto import (
32
+ Algorithm,
33
+ envelope_enc_file,
34
+ )
31
35
 
32
36
  # Upload functionality (requires GitPython)
33
37
  try:
@@ -58,6 +62,9 @@ __all__ = [
58
62
  "save_token",
59
63
  "load_token",
60
64
  "delete_token",
65
+ # Encryption
66
+ "Algorithm",
67
+ "envelope_enc_file",
61
68
  # Exceptions
62
69
  "HubException",
63
70
  "RepositoryNotFoundError",
xiaoshiai_hub/cli.py CHANGED
@@ -1,5 +1,5 @@
1
1
  """
2
- 小时 AI Hub SDK 命令行工具
2
+ XiaoShi AI Hub SDK 命令行工具
3
3
  """
4
4
 
5
5
  import argparse
@@ -62,6 +62,9 @@ def cmd_upload_folder(args):
62
62
  "请设置 MOHA_ENCRYPTION_PASSWORD 环境变量或使用 --encryption-password 参数", file=sys.stderr)
63
63
  return 1
64
64
 
65
+ # 获取加密算法
66
+ algorithm = args.algorithm if encryption_password else None
67
+
65
68
  try:
66
69
  upload_folder(
67
70
  folder_path=args.folder,
@@ -76,6 +79,7 @@ def cmd_upload_folder(args):
76
79
  encryption_password=encryption_password,
77
80
  ignore_patterns=ignore_patterns,
78
81
  temp_dir=args.temp_dir,
82
+ algorithm=algorithm,
79
83
  )
80
84
  print("上传成功!")
81
85
  return 0
@@ -102,6 +106,9 @@ def cmd_upload_file(args):
102
106
  # 确定仓库中的路径
103
107
  path_in_repo = args.path_in_repo if args.path_in_repo else os.path.basename(args.file)
104
108
 
109
+ # 获取加密算法
110
+ algorithm = args.algorithm if encryption_password else None
111
+
105
112
  try:
106
113
  upload_file(
107
114
  path_file=args.file,
@@ -115,6 +122,7 @@ def cmd_upload_file(args):
115
122
  password=password,
116
123
  token=token,
117
124
  encryption_password=encryption_password,
125
+ algorithm=algorithm,
118
126
  )
119
127
  print(f"上传成功: {path_in_repo}")
120
128
  return 0
@@ -255,6 +263,248 @@ def cmd_whoami(args):
255
263
  return 1
256
264
 
257
265
 
266
+ def _parse_repo_id(repo_id: str):
267
+ """解析仓库 ID,返回 (organization, repo_name)"""
268
+ parts = repo_id.split("/")
269
+ if len(parts) != 2:
270
+ raise ValueError(f"无效的仓库 ID: {repo_id},格式应为: 组织/仓库名")
271
+ return parts[0], parts[1]
272
+
273
+
274
+ def _get_client(args):
275
+ """创建 HubClient 实例"""
276
+ from xiaoshiai_hub.client import HubClient
277
+ token, username, password = get_auth(args)
278
+ return HubClient(
279
+ base_url=args.base_url,
280
+ username=username,
281
+ password=password,
282
+ token=token,
283
+ )
284
+
285
+
286
+ def cmd_repo_create(args):
287
+ """处理 repo-create 命令"""
288
+ try:
289
+ org, repo_name = _parse_repo_id(args.repo_id)
290
+ client = _get_client(args)
291
+
292
+ # 解析 metadata
293
+ metadata = {}
294
+ if args.license:
295
+ metadata["license"] = args.license
296
+ if args.tasks:
297
+ metadata["tasks"] = args.tasks
298
+ if args.languages:
299
+ metadata["languages"] = args.languages
300
+ if args.tags:
301
+ metadata["tags"] = args.tags
302
+ if args.frameworks:
303
+ metadata["frameworks"] = args.frameworks
304
+
305
+ client.create_repository(
306
+ organization=org,
307
+ repo_type=args.repo_type,
308
+ repo_name=repo_name,
309
+ description=args.description,
310
+ visibility=args.visibility,
311
+ metadata=metadata if metadata else None,
312
+ base_model=args.base_model,
313
+ relationship=args.relationship,
314
+ )
315
+ print(f"仓库创建成功: {org}/{repo_name}")
316
+ return 0
317
+ except Exception as e:
318
+ print(f"错误: {e}", file=sys.stderr)
319
+ return 1
320
+
321
+
322
+ def cmd_repo_update(args):
323
+ """处理 repo-update 命令"""
324
+ try:
325
+ org, repo_name = _parse_repo_id(args.repo_id)
326
+ client = _get_client(args)
327
+
328
+ # 先获取仓库当前信息
329
+ repo = client.get_repository_info(
330
+ organization=org,
331
+ repo_type=args.repo_type,
332
+ repo_name=repo_name,
333
+ )
334
+
335
+ # 使用现有值作为默认值,只更新用户指定的字段
336
+ description = args.description if args.description is not None else repo.description
337
+ visibility = args.visibility if args.visibility is not None else repo.visibility
338
+
339
+ # 合并 metadata:用户指定的覆盖现有的
340
+ metadata = dict(repo.metadata) if repo.metadata else {}
341
+ if args.license:
342
+ metadata["license"] = args.license
343
+ if args.tasks:
344
+ metadata["tasks"] = args.tasks
345
+ if args.languages:
346
+ metadata["languages"] = args.languages
347
+ if args.tags:
348
+ metadata["tags"] = args.tags
349
+ if args.frameworks:
350
+ metadata["frameworks"] = args.frameworks
351
+
352
+ # 处理 genealogy:用户指定的覆盖现有的
353
+ base_model = args.base_model
354
+ relationship = args.relationship
355
+ if repo.genealogy:
356
+ if base_model is None and 'baseModel' in repo.genealogy:
357
+ base_model = repo.genealogy['baseModel']
358
+ if relationship is None and 'relationship' in repo.genealogy:
359
+ relationship = repo.genealogy['relationship']
360
+
361
+ client.update_repository(
362
+ organization=org,
363
+ repo_type=args.repo_type,
364
+ repo_name=repo_name,
365
+ description=description,
366
+ visibility=visibility,
367
+ metadata=metadata if metadata else None,
368
+ annotations=repo.annotations,
369
+ base_model=base_model,
370
+ relationship=relationship,
371
+ )
372
+ print(f"仓库更新成功: {org}/{repo_name}")
373
+ return 0
374
+ except Exception as e:
375
+ print(f"错误: {e}", file=sys.stderr)
376
+ return 1
377
+
378
+
379
+ def cmd_repo_delete(args):
380
+ """处理 repo-delete 命令"""
381
+ try:
382
+ org, repo_name = _parse_repo_id(args.repo_id)
383
+ client = _get_client(args)
384
+
385
+ # 确认删除
386
+ if not args.yes:
387
+ confirm = input(f"确定要删除仓库 {org}/{repo_name} 吗?此操作不可恢复![y/N]: ")
388
+ if confirm.lower() != 'y':
389
+ print("已取消删除")
390
+ return 0
391
+
392
+ client.delete_repository(
393
+ organization=org,
394
+ repo_type=args.repo_type,
395
+ repo_name=repo_name,
396
+ )
397
+ print(f"仓库删除成功: {org}/{repo_name}")
398
+ return 0
399
+ except Exception as e:
400
+ print(f"错误: {e}", file=sys.stderr)
401
+ return 1
402
+
403
+
404
+ def cmd_repo_info(args):
405
+ """处理 repo-info 命令"""
406
+ try:
407
+ org, repo_name = _parse_repo_id(args.repo_id)
408
+ client = _get_client(args)
409
+
410
+ repo = client.get_repository_info(
411
+ organization=org,
412
+ repo_type=args.repo_type,
413
+ repo_name=repo_name,
414
+ )
415
+ print(f"仓库名称: {repo.name}")
416
+ print(f"组织: {repo.organization}")
417
+ print(f"所有者: {repo.owner}")
418
+ print(f"创建者: {repo.creator}")
419
+ print(f"类型: {repo.type}")
420
+ print(f"可见性: {repo.visibility}")
421
+ if repo.description:
422
+ print(f"描述: {repo.description}")
423
+ if repo.genealogy:
424
+ print(f"模型血缘: {repo.genealogy}")
425
+ if repo.metadata:
426
+ print(f"元数据: {repo.metadata}")
427
+ if repo.annotations:
428
+ print(f"注解: {repo.annotations}")
429
+ return 0
430
+ except Exception as e:
431
+ print(f"错误: {e}", file=sys.stderr)
432
+ return 1
433
+
434
+
435
+ def cmd_branch_create(args):
436
+ """处理 branch-create 命令"""
437
+ try:
438
+ org, repo_name = _parse_repo_id(args.repo_id)
439
+ client = _get_client(args)
440
+
441
+ client.create_branch(
442
+ organization=org,
443
+ repo_type=args.repo_type,
444
+ repo_name=repo_name,
445
+ branch_name=args.branch,
446
+ from_branch=args.from_branch,
447
+ )
448
+ print(f"分支创建成功: {args.branch}")
449
+ return 0
450
+ except Exception as e:
451
+ print(f"错误: {e}", file=sys.stderr)
452
+ return 1
453
+
454
+
455
+ def cmd_branch_delete(args):
456
+ """处理 branch-delete 命令"""
457
+ try:
458
+ org, repo_name = _parse_repo_id(args.repo_id)
459
+ client = _get_client(args)
460
+
461
+ # 确认删除
462
+ if not args.yes:
463
+ confirm = input(f"确定要删除分支 {args.branch} 吗?[y/N]: ")
464
+ if confirm.lower() != 'y':
465
+ print("已取消删除")
466
+ return 0
467
+
468
+ client.delete_branch(
469
+ organization=org,
470
+ repo_type=args.repo_type,
471
+ repo_name=repo_name,
472
+ branch_name=args.branch,
473
+ )
474
+ print(f"分支删除成功: {args.branch}")
475
+ return 0
476
+ except Exception as e:
477
+ print(f"错误: {e}", file=sys.stderr)
478
+ return 1
479
+
480
+
481
+ def cmd_branch_list(args):
482
+ """处理 branch-list 命令"""
483
+ try:
484
+ org, repo_name = _parse_repo_id(args.repo_id)
485
+ client = _get_client(args)
486
+
487
+ refs = client.get_repository_refs(
488
+ organization=org,
489
+ repo_type=args.repo_type,
490
+ repo_name=repo_name,
491
+ )
492
+
493
+ if not refs:
494
+ print("没有找到分支")
495
+ return 0
496
+
497
+ print(f"仓库 {org}/{repo_name} 的分支列表:")
498
+ for ref in refs:
499
+ commit_hash = ref.hash[:8] if ref.hash else 'N/A'
500
+ default_mark = " (默认)" if ref.is_default else ""
501
+ print(f" - {ref.name} [{ref.type}] (commit: {commit_hash}){default_mark}")
502
+ return 0
503
+ except Exception as e:
504
+ print(f"错误: {e}", file=sys.stderr)
505
+ return 1
506
+
507
+
258
508
  def _add_common_args(parser):
259
509
  """添加通用参数"""
260
510
  parser.add_argument(
@@ -286,21 +536,26 @@ def _add_encryption_args(parser):
286
536
  "--encryption-password",
287
537
  help="加密密码(或设置 MOHA_ENCRYPTION_PASSWORD 环境变量)",
288
538
  )
539
+ parser.add_argument(
540
+ "--algorithm", "-a",
541
+ choices=["AES", "SM4"],
542
+ default="AES",
543
+ help="加密算法(默认: AES)",
544
+ )
289
545
 
290
546
 
291
547
  def create_parser():
292
548
  """创建命令行参数解析器"""
293
549
  parser = argparse.ArgumentParser(
294
550
  prog="moha",
295
- description="小时 AI Hub 命令行工具 - 上传和下载模型及数据集",
551
+ description="晓石 AI Hub 命令行工具 - 模型及数据集管理",
296
552
  )
297
553
 
298
554
  subparsers = parser.add_subparsers(dest="command", help="可用命令")
299
555
 
300
556
  # ========== 上传文件夹命令 ==========
301
557
  upload_folder_parser = subparsers.add_parser(
302
- "upload-folder",
303
- aliases=["upload"],
558
+ "upload",
304
559
  help="上传文件夹到仓库",
305
560
  )
306
561
  upload_folder_parser.add_argument("folder", help="要上传的文件夹路径")
@@ -366,7 +621,6 @@ def create_parser():
366
621
  # ========== 下载仓库命令 ==========
367
622
  download_repo_parser = subparsers.add_parser(
368
623
  "download",
369
- aliases=["download-repo"],
370
624
  help="下载整个仓库",
371
625
  )
372
626
  download_repo_parser.add_argument("repo_id", help="仓库 ID(格式: 组织/仓库名)")
@@ -476,6 +730,218 @@ def create_parser():
476
730
  )
477
731
  whoami_parser.set_defaults(func=cmd_whoami)
478
732
 
733
+ # ========== 创建仓库命令 ==========
734
+ repo_create_parser = subparsers.add_parser(
735
+ "repo-create",
736
+ help="创建仓库",
737
+ )
738
+ repo_create_parser.add_argument("repo_id", help="仓库 ID(格式: 组织/仓库名)")
739
+ repo_create_parser.add_argument(
740
+ "--repo-type", "-t",
741
+ default="models",
742
+ choices=["models", "datasets"],
743
+ help="仓库类型(默认: models)",
744
+ )
745
+ repo_create_parser.add_argument(
746
+ "--description", "-d",
747
+ help="仓库描述",
748
+ )
749
+ repo_create_parser.add_argument(
750
+ "--visibility", "-v",
751
+ default="internal",
752
+ choices=["public", "internal", "private"],
753
+ help="可见性(默认: internal)",
754
+ )
755
+ repo_create_parser.add_argument(
756
+ "--license",
757
+ action="append",
758
+ help="许可证(可多次指定)",
759
+ )
760
+ repo_create_parser.add_argument(
761
+ "--tasks",
762
+ action="append",
763
+ help="任务类型(可多次指定)",
764
+ )
765
+ repo_create_parser.add_argument(
766
+ "--languages",
767
+ action="append",
768
+ help="语言(可多次指定)",
769
+ )
770
+ repo_create_parser.add_argument(
771
+ "--tags",
772
+ action="append",
773
+ help="标签(可多次指定)",
774
+ )
775
+ repo_create_parser.add_argument(
776
+ "--frameworks",
777
+ action="append",
778
+ help="框架(可多次指定)",
779
+ )
780
+ repo_create_parser.add_argument(
781
+ "--base-model",
782
+ action="append",
783
+ help="基础模型(可多次指定,格式: 组织/模型名)",
784
+ )
785
+ repo_create_parser.add_argument(
786
+ "--relationship",
787
+ choices=["adapter", "finetune", "quantized", "merge", "repackage"],
788
+ help="与基础模型的关系",
789
+ )
790
+ _add_common_args(repo_create_parser)
791
+ repo_create_parser.set_defaults(func=cmd_repo_create)
792
+
793
+ # ========== 更新仓库命令 ==========
794
+ repo_update_parser = subparsers.add_parser(
795
+ "repo-update",
796
+ help="更新仓库",
797
+ )
798
+ repo_update_parser.add_argument("repo_id", help="仓库 ID(格式: 组织/仓库名)")
799
+ repo_update_parser.add_argument(
800
+ "--repo-type", "-t",
801
+ default="models",
802
+ choices=["models", "datasets"],
803
+ help="仓库类型(默认: models)",
804
+ )
805
+ repo_update_parser.add_argument(
806
+ "--description", "-d",
807
+ help="仓库描述",
808
+ )
809
+ repo_update_parser.add_argument(
810
+ "--visibility", "-v",
811
+ choices=["public", "internal", "private"],
812
+ help="可见性",
813
+ )
814
+ repo_update_parser.add_argument(
815
+ "--license",
816
+ action="append",
817
+ help="许可证(可多次指定)",
818
+ )
819
+ repo_update_parser.add_argument(
820
+ "--tasks",
821
+ action="append",
822
+ help="任务类型(可多次指定)",
823
+ )
824
+ repo_update_parser.add_argument(
825
+ "--languages",
826
+ action="append",
827
+ help="语言(可多次指定)",
828
+ )
829
+ repo_update_parser.add_argument(
830
+ "--tags",
831
+ action="append",
832
+ help="标签(可多次指定)",
833
+ )
834
+ repo_update_parser.add_argument(
835
+ "--frameworks",
836
+ action="append",
837
+ help="框架(可多次指定)",
838
+ )
839
+ repo_update_parser.add_argument(
840
+ "--base-model",
841
+ action="append",
842
+ help="基础模型(可多次指定,格式: 组织/模型名)",
843
+ )
844
+ repo_update_parser.add_argument(
845
+ "--relationship",
846
+ choices=["adapter", "finetune", "quantized", "merge", "repackage"],
847
+ help="与基础模型的关系",
848
+ )
849
+ _add_common_args(repo_update_parser)
850
+ repo_update_parser.set_defaults(func=cmd_repo_update)
851
+
852
+ # ========== 删除仓库命令 ==========
853
+ repo_delete_parser = subparsers.add_parser(
854
+ "repo-delete",
855
+ help="删除仓库",
856
+ )
857
+ repo_delete_parser.add_argument("repo_id", help="仓库 ID(格式: 组织/仓库名)")
858
+ repo_delete_parser.add_argument(
859
+ "--repo-type", "-t",
860
+ default="models",
861
+ choices=["models", "datasets"],
862
+ help="仓库类型(默认: models)",
863
+ )
864
+ repo_delete_parser.add_argument(
865
+ "--yes", "-y",
866
+ action="store_true",
867
+ help="跳过确认提示",
868
+ )
869
+ _add_common_args(repo_delete_parser)
870
+ repo_delete_parser.set_defaults(func=cmd_repo_delete)
871
+
872
+ # ========== 查看仓库信息命令 ==========
873
+ repo_info_parser = subparsers.add_parser(
874
+ "repo-info",
875
+ help="查看仓库信息",
876
+ )
877
+ repo_info_parser.add_argument("repo_id", help="仓库 ID(格式: 组织/仓库名)")
878
+ repo_info_parser.add_argument(
879
+ "--repo-type", "-t",
880
+ default="models",
881
+ choices=["models", "datasets"],
882
+ help="仓库类型(默认: models)",
883
+ )
884
+ _add_common_args(repo_info_parser)
885
+ repo_info_parser.set_defaults(func=cmd_repo_info)
886
+
887
+ # ========== 创建分支命令 ==========
888
+ branch_create_parser = subparsers.add_parser(
889
+ "branch-create",
890
+ help="创建分支",
891
+ )
892
+ branch_create_parser.add_argument("repo_id", help="仓库 ID(格式: 组织/仓库名)")
893
+ branch_create_parser.add_argument("branch", help="要创建的分支名称")
894
+ branch_create_parser.add_argument(
895
+ "--from", "-f",
896
+ dest="from_branch",
897
+ default="main",
898
+ help="基于哪个分支创建(默认: main)",
899
+ )
900
+ branch_create_parser.add_argument(
901
+ "--repo-type", "-t",
902
+ default="models",
903
+ choices=["models", "datasets"],
904
+ help="仓库类型(默认: models)",
905
+ )
906
+ _add_common_args(branch_create_parser)
907
+ branch_create_parser.set_defaults(func=cmd_branch_create)
908
+
909
+ # ========== 删除分支命令 ==========
910
+ branch_delete_parser = subparsers.add_parser(
911
+ "branch-delete",
912
+ help="删除分支",
913
+ )
914
+ branch_delete_parser.add_argument("repo_id", help="仓库 ID(格式: 组织/仓库名)")
915
+ branch_delete_parser.add_argument("branch", help="要删除的分支名称")
916
+ branch_delete_parser.add_argument(
917
+ "--repo-type", "-t",
918
+ default="models",
919
+ choices=["models", "datasets"],
920
+ help="仓库类型(默认: models)",
921
+ )
922
+ branch_delete_parser.add_argument(
923
+ "--yes", "-y",
924
+ action="store_true",
925
+ help="跳过确认提示",
926
+ )
927
+ _add_common_args(branch_delete_parser)
928
+ branch_delete_parser.set_defaults(func=cmd_branch_delete)
929
+
930
+ # ========== 列出分支命令 ==========
931
+ branch_list_parser = subparsers.add_parser(
932
+ "branch-list",
933
+ help="列出仓库的所有分支",
934
+ )
935
+ branch_list_parser.add_argument("repo_id", help="仓库 ID(格式: 组织/仓库名)")
936
+ branch_list_parser.add_argument(
937
+ "--repo-type", "-t",
938
+ default="models",
939
+ choices=["models", "datasets"],
940
+ help="仓库类型(默认: models)",
941
+ )
942
+ _add_common_args(branch_list_parser)
943
+ branch_list_parser.set_defaults(func=cmd_branch_list)
944
+
479
945
  return parser
480
946
 
481
947