intellif-aihub 0.1.1__py3-none-any.whl → 0.1.2__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.

Potentially problematic release.


This version of intellif-aihub might be problematic. Click here for more details.

aihub/__init__.py CHANGED
@@ -1,4 +1 @@
1
- from .stop import is_pre_stopped, on_pre_stop
2
- from ._version import __version__
3
-
4
- __all__ = ["is_pre_stopped", "on_pre_stop", "__version__"]
1
+ __version__ = "0.1.2"
aihub/client.py ADDED
@@ -0,0 +1,87 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+
5
+ import httpx
6
+
7
+ from .exceptions import APIError
8
+ from .services import artifact
9
+ from .services import dataset_management
10
+ from .services import document_center
11
+ from .services import labelfree
12
+ from .services import tag_management
13
+ from .services import task_center
14
+ from .services.artifact import ArtifactService
15
+ from .services.dataset_management import DatasetManagementService
16
+ from .services.document_center import DocumentCenterService
17
+ from .services.labelfree import LabelfreeService
18
+ from .services.tag_management import TagManagementService
19
+ from .services.task_center import TaskCenterService
20
+
21
+
22
+ class Client:
23
+ """AI-HUB python SDK 客户端
24
+
25
+ Attributes:
26
+ dataset_management (DatasetManagementService): 数据集管理服务
27
+ labelfree (LabelfreeService): 标注服务
28
+ task_center (TaskCenterService): 任务中心
29
+ artifact (ArtifactService): 制品管理
30
+
31
+ """
32
+
33
+ labelfree: LabelfreeService = None
34
+ tag_management: TagManagementService = None
35
+ document_center: DocumentCenterService = None
36
+ task_center: TaskCenterService = None
37
+ dataset_management: DatasetManagementService = None
38
+ artifact: ArtifactService = None
39
+
40
+ def __init__(
41
+ self, *, base_url: str, token: str | None = None, timeout: float = 60.0
42
+ ):
43
+ """AI-HUB python SDK 客户端
44
+
45
+ Args:
46
+ base_url (str): 服务地址
47
+ token (str): 密钥,显式传入,或在环境变量AI_HUB_TOKEN中设置
48
+
49
+ Examples:
50
+ >>> from aihub.client import Client
51
+ >>> client = Client(base_url="xxx", token="xxxx")
52
+
53
+ """
54
+ if not base_url:
55
+ raise ValueError("base_url必须填写")
56
+
57
+ token = token or os.getenv("AI_HUB_TOKEN")
58
+ if not token:
59
+ raise ValueError("缺少token:请显式传入,或在环境变量AI_HUB_TOKEN中设置")
60
+
61
+ self._http = httpx.Client(
62
+ base_url=base_url.rstrip("/"),
63
+ timeout=timeout,
64
+ headers={"Authorization": f"Bearer {token}"},
65
+ # event_hooks={"response": [self._raise_for_status]},
66
+ )
67
+ self.dataset_management = dataset_management.DatasetManagementService(
68
+ self._http
69
+ )
70
+ self.labelfree = labelfree.LabelfreeService(self._http)
71
+ self.tag_management = tag_management.TagManagementService(self._http)
72
+ self.document_center = document_center.DocumentCenterService(self._http)
73
+ self.task_center = task_center.TaskCenterService(self._http)
74
+ self.artifact = artifact.ArtifactService(self._http)
75
+
76
+ @staticmethod
77
+ def _raise_for_status(r: httpx.Response):
78
+ try:
79
+ r.raise_for_status()
80
+ except httpx.HTTPStatusError as e:
81
+ raise APIError(f"{e.response.status_code}: {e.response.text}") from e
82
+
83
+ def __enter__(self):
84
+ return self
85
+
86
+ def __exit__(self, *a):
87
+ self._http.close()
aihub/exceptions.py ADDED
@@ -0,0 +1,18 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Optional
4
+
5
+
6
+ class SDKError(Exception):
7
+ pass
8
+
9
+
10
+ class APIError(SDKError):
11
+ def __init__(self, message: str, *, status: Optional[int] = None, detail: Any = None) -> None:
12
+ super().__init__(message)
13
+ self.message: str = message
14
+ self.status: Optional[int] = status
15
+ self.detail: Any = detail
16
+
17
+ def __str__(self) -> str:
18
+ return f"[HTTP {self.status}] {self.message}" if self.status else self.message
File without changes
@@ -0,0 +1,137 @@
1
+ # !/usr/bin/env python
2
+ # -*-coding:utf-8 -*-
3
+ """制品管理模型模块
4
+
5
+ 该模块定义了制品管理相关的数据模型,包括制品类型、创建制品请求、制品响应等。
6
+ """
7
+ from __future__ import annotations
8
+
9
+ from enum import Enum
10
+ from typing import List, Optional
11
+
12
+ from pydantic import BaseModel
13
+
14
+
15
+ class ArtifactType(str, Enum):
16
+ """制品类型枚举
17
+
18
+ 定义了系统支持的各种制品类型。
19
+ """
20
+
21
+ dataset = "dataset" # 数据集类型
22
+ model = "model" # 模型类型
23
+ metrics = "metrics" # 指标类型
24
+ log = "log" # 日志类型
25
+ checkpoint = "checkpoint" # 检查点类型
26
+ image = "image" # 图像类型
27
+ prediction = "prediction" # 预测结果类型
28
+ other = "other" # 其他类型
29
+
30
+
31
+ class CreateArtifactsReq(BaseModel):
32
+ """创建制品请求模型
33
+
34
+ 用于向服务器发送创建制品的请求。
35
+ """
36
+
37
+ entity_id: str
38
+ """实体ID,通常是运行ID,用于关联制品与特定运行"""
39
+
40
+ entity_type: ArtifactType = ArtifactType.other
41
+ """制品类型,指定制品的类型,默认为other"""
42
+
43
+ src_path: str
44
+ """源路径,制品在系统中的路径标识"""
45
+
46
+ is_dir: bool = False
47
+ """是否为目录,True表示制品是一个目录,False表示是单个文件"""
48
+
49
+
50
+ class CreateArtifactsResponseData(BaseModel):
51
+ """创建制品响应数据模型
52
+
53
+ 服务器创建制品后返回的数据。
54
+ """
55
+
56
+ id: int # 制品ID
57
+ s3_path: str # S3存储路径
58
+
59
+
60
+ class CreateArtifactsResponseModel(BaseModel):
61
+ """创建制品响应模型
62
+
63
+ 服务器对创建制品请求的完整响应。
64
+ """
65
+
66
+ code: int # 响应码,0表示成功
67
+ msg: str = "" # 响应消息
68
+ data: CreateArtifactsResponseData | None = None # 响应数据
69
+
70
+
71
+ class CreatEvalReq(BaseModel):
72
+ """创建评估请求模型
73
+
74
+ 用于创建模型评估的请求。
75
+ """
76
+
77
+ dataset_id: int # 数据集ID
78
+ dataset_version_id: int # 数据集版本ID
79
+ prediction_artifact_path: str # 预测结果制品路径
80
+ evaled_artifact_path: str # 评估结果制品路径
81
+ run_id: str # 运行ID
82
+ user_id: int # 用户ID
83
+ report: dict = {} # 评估报告
84
+
85
+
86
+ class ArtifactResp(BaseModel):
87
+ """制品响应模型
88
+
89
+ 表示一个制品的详细信息。
90
+ """
91
+
92
+ id: int # 制品ID
93
+ entity_type: str # 实体类型
94
+ entity_id: str # 实体ID
95
+ src_path: str # 源路径
96
+ s3_path: str # S3存储路径
97
+ is_dir: bool # 是否为目录
98
+
99
+
100
+ class ArtifactRespData(BaseModel):
101
+ """制品响应数据模型
102
+
103
+ 包含分页信息和制品列表的响应数据。
104
+ """
105
+
106
+ total: int # 总记录数
107
+ page_size: int # 每页大小
108
+ page_num: int # 页码
109
+ data: List[ArtifactResp] # 制品列表
110
+
111
+
112
+ class ArtifactRespModel(BaseModel):
113
+ """制品响应模型
114
+
115
+ 服务器对获取制品请求的完整响应。
116
+ """
117
+
118
+ code: int # 响应码,0表示成功
119
+ msg: str = "" # 响应消息
120
+ data: ArtifactRespData # 响应数据
121
+
122
+
123
+ # 无限大的页面大小,用于一次性获取所有制品
124
+ InfinityPageSize = 10000 * 100
125
+
126
+
127
+ class StsResp(BaseModel):
128
+ """STS临时凭证响应模型
129
+
130
+ 包含访问S3存储所需的临时凭证信息。
131
+ """
132
+
133
+ access_key_id: Optional[str] = None # 访问密钥ID
134
+ secret_access_key: Optional[str] = None # 秘密访问密钥
135
+ session_token: Optional[str] = None # 会话令牌
136
+ expiration: Optional[int] = None # 过期时间
137
+ endpoint: Optional[str] = None # 端点URL
aihub/models/common.py ADDED
@@ -0,0 +1,13 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Generic, Optional, TypeVar
4
+
5
+ from pydantic import BaseModel
6
+
7
+ T = TypeVar("T")
8
+
9
+
10
+ class APIWrapper(BaseModel, Generic[T]):
11
+ code: int
12
+ msg: Optional[str] = None
13
+ data: Optional[T]
@@ -0,0 +1,99 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import List, Optional
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+
8
+ class CreateDatasetRequest(BaseModel):
9
+ name: str
10
+ description: str
11
+ tags: List[int]
12
+ cover_img: Optional[str] = Field(None, alias="cover_img")
13
+ create_by: Optional[int] = Field(None, alias="create_by")
14
+ is_private: Optional[bool] = Field(None, alias="is_private")
15
+ access_user_ids: Optional[List[int]] = Field(None, alias="access_user_ids")
16
+
17
+
18
+ class CreateDatasetResponse(BaseModel):
19
+ id: int = Field(alias="id")
20
+
21
+
22
+ class DatasetVersionBase(BaseModel):
23
+ id: int
24
+ version: int
25
+ status: int
26
+ parquet_index_path: Optional[str] = Field(None, alias="parquet_index_path")
27
+ data_count: int = Field(alias="data_count")
28
+
29
+
30
+ class DatasetDetail(BaseModel):
31
+ id: int
32
+ name: str
33
+ description: str
34
+ cover_img: Optional[str] = Field(None, alias="cover_img")
35
+ created_at: int = Field(alias="created_at")
36
+ updated_at: int = Field(alias="update_at")
37
+ user_id: int = Field(alias="user_id")
38
+ username: str
39
+ tags: List[int]
40
+ access_user_ids: Optional[List[int]] = Field(None, alias="access_user_ids")
41
+ is_private: Optional[bool] = Field(None, alias="is_private")
42
+ versions: List[DatasetVersionBase]
43
+
44
+
45
+ class ExtInfo(BaseModel):
46
+ rec_file_path: Optional[str] = Field(None, alias="rec_file_path")
47
+ idx_file_path: Optional[str] = Field(None, alias="idx_file_path")
48
+ json_file_path: Optional[str] = Field(None, alias="json_file_path")
49
+ image_dir_path: Optional[str] = Field(None, alias="image_dir_path")
50
+
51
+
52
+ class CreateDatasetVersionRequest(BaseModel):
53
+ upload_path: str = Field(alias="upload_path")
54
+ description: Optional[str] = None
55
+ dataset_id: int = Field(alias="dataset_id")
56
+ object_cnt: Optional[int] = Field(None, alias="object_cnt")
57
+ data_size: Optional[int] = Field(None, alias="data_size")
58
+ create_by: Optional[int] = Field(None, alias="create_by")
59
+ upload_type: Optional[int] = Field(4, alias="upload_type")
60
+ ext_info: Optional[ExtInfo] = Field(None, alias="ext_info")
61
+
62
+
63
+ class CreateDatasetVersionResponse(BaseModel):
64
+ id: int = Field(alias="id")
65
+
66
+
67
+ class UploadDatasetVersionRequest(BaseModel):
68
+ upload_path: str = Field(alias="upload_path")
69
+ upload_type: int = Field(alias="upload_type")
70
+ dataset_id: int = Field(alias="dataset_id")
71
+ parent_version_id: Optional[int] = Field(None, alias="parent_version_id")
72
+ description: Optional[str] = Field(None, alias="description")
73
+
74
+
75
+ class UploadDatasetVersionResponse(BaseModel):
76
+ id: int = Field(alias="id")
77
+
78
+
79
+ class DatasetVersionDetail(BaseModel):
80
+ id: int
81
+ version: int
82
+ dataset_id: int = Field(alias="dataset_id")
83
+ upload_path: str = Field(alias="upload_path")
84
+ upload_type: int = Field(alias="upload_type")
85
+ parent_version_id: Optional[int] = Field(None, alias="parent_version_id")
86
+ description: Optional[str] = None
87
+ status: int
88
+ message: Optional[str] = None
89
+ created_at: int = Field(alias="created_at")
90
+ user_id: int = Field(alias="user_id")
91
+ data_size: Optional[int] = Field(None, alias="data_size")
92
+ data_count: Optional[int] = Field(None, alias="data_count")
93
+ parquet_index_path: Optional[str] = Field(None, alias="parquet_index_path")
94
+ ext_info: Optional[ExtInfo] = Field(None, alias="ext_info")
95
+
96
+
97
+ class FileUploadData(BaseModel):
98
+ path: str
99
+ url: str
@@ -0,0 +1,28 @@
1
+ # !/usr/bin/env python
2
+ # -*-coding:utf-8 -*-
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import List, Optional, Any
7
+
8
+ from pydantic import BaseModel
9
+
10
+
11
+ class Document(BaseModel):
12
+ id: int
13
+ title: str
14
+ type: int
15
+ edit_time: int
16
+ need_update: bool
17
+ content: str
18
+ username: str
19
+ user_id: int
20
+ created_at: int
21
+ comments: Optional[Any] = None
22
+
23
+
24
+ class GetDocumentsResponse(BaseModel):
25
+ total: int
26
+ page_size: int
27
+ page_num: int
28
+ data: List[Document]
@@ -0,0 +1,31 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Optional
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+
8
+ class Stats(BaseModel):
9
+ """标注统计信息"""
10
+
11
+ total_annotations: int = Field(alias="total_annotations")
12
+ labeled_annotations: int = Field(alias="labeled_annotations")
13
+ total_labels: int = Field(alias="total_labels")
14
+ total_reviews: Optional[int] = Field(None, alias="total_reviews")
15
+ unlabeled_reviews: Optional[int] = Field(None, alias="unlabeled_reviews")
16
+ labeled_reviews: Optional[int] = Field(None, alias="labeled_reviews")
17
+ accepted_count: Optional[int] = Field(None, alias="accepted_count")
18
+ rejected_count: Optional[int] = Field(None, alias="rejected_count")
19
+
20
+
21
+ class GetGlobalStatsResponse(BaseModel):
22
+ """
23
+ 标注统计概况
24
+ """
25
+
26
+ global_stats: Stats = Field(alias="global_stats")
27
+ valid_ten_percent: bool = Field(alias="valid_ten_percent")
28
+ valid_fifty_percent: bool = Field(alias="valid_fifty_percent")
29
+ valid_hundred_percent: bool = Field(alias="valid_hundred_percent")
30
+ data_exported_count: int = Field(alias="data_exported_count")
31
+ exported_dataset_name: str = Field(alias="exported_dataset_name")
File without changes
@@ -0,0 +1,21 @@
1
+ # !/usr/bin/env python
2
+ # -*-coding:utf-8 -*-
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import List
7
+
8
+ from pydantic import BaseModel
9
+
10
+
11
+ class Project(BaseModel):
12
+ id: int
13
+ name: str
14
+
15
+
16
+ class ProjectListData(BaseModel):
17
+ data: List[Project]
18
+
19
+
20
+ class SelectProjectsResponse(BaseModel):
21
+ data: List[Project]
@@ -0,0 +1,117 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from enum import Enum
5
+ from typing import Optional, List
6
+
7
+ from pydantic import BaseModel, Field, field_serializer, field_validator
8
+
9
+
10
+ class TaskCenterPriorityEnum(Enum):
11
+ """
12
+ 任务优先级枚举
13
+ """
14
+
15
+ low = "low"
16
+ medium = "medium"
17
+ high = "high"
18
+
19
+
20
+ class LabelProjectTypeEnum(Enum):
21
+ """
22
+ 任务类型枚举
23
+ """
24
+
25
+ IMAGE_CLASSIFICATION = 1
26
+ OBJECT_DETECTION = 2
27
+ SEMANTIC_SEGMENTATION = 3
28
+ TEXT_CLASSIFICATION = 4
29
+ TEXT_SEGMENTATION = 5
30
+ TEXT_RECOGNITION = 6
31
+ IMAGE_CAPTIONING = 7
32
+ IMAGE_STYLE_TRANSFER = 8
33
+ IMAGE_COLORIZATION = 9
34
+ IMAGE_RESTORATION = 10
35
+
36
+
37
+ class CreateTaskOtherInfo(BaseModel):
38
+ label_project_type: LabelProjectTypeEnum = LabelProjectTypeEnum.IMAGE_CLASSIFICATION
39
+ dataset_id: int = Field(alias="dataset_id")
40
+ dataset_version_id: int = Field(alias="dataset_version_id")
41
+ doc_id: int = Field(alias="doc_id")
42
+ doc_type: str = Field(alias="doc_type", default="doc_center")
43
+
44
+
45
+ class ProjectInfo(BaseModel):
46
+ label_project_id: int = Field(alias="label_project_id")
47
+ label_project_name: str = Field(alias="label_project_name")
48
+
49
+
50
+ class TaskDetailOtherInfo(BaseModel):
51
+ label_project_type: LabelProjectTypeEnum = LabelProjectTypeEnum.IMAGE_CLASSIFICATION
52
+ dataset_id: int = Field(alias="dataset_id")
53
+ dataset_version_id: int = Field(alias="dataset_version_id")
54
+ doc_id: int = Field(alias="doc_id")
55
+ doc_type: str = Field(alias="doc_type", default="doc_center")
56
+ label_projects: Optional[List[ProjectInfo]] = Field(alias="label_projects")
57
+
58
+
59
+ class CreateTaskReq(BaseModel):
60
+ name: str
61
+ description: Optional[str] = None
62
+ task_priority: Optional[str] = None
63
+ type: Optional[str] = None
64
+ receiver_id: Optional[int] = None
65
+ project_id: Optional[int] = None
66
+ other_info: CreateTaskOtherInfo = Field(alias="other_info")
67
+ estimated_delivery_at: Optional[int] = None
68
+
69
+ @field_serializer("other_info")
70
+ def serialize_other_info(self, value: CreateTaskOtherInfo) -> str:
71
+ """将 other_info 序列化为 JSON 字符串"""
72
+ return value.model_dump_json()
73
+
74
+
75
+ class CreateTaskResp(BaseModel):
76
+ id: int = Field(alias="id")
77
+
78
+
79
+ class LabelTaskDetail(BaseModel):
80
+ """任务详情"""
81
+
82
+ name: str
83
+ description: Optional[str] = Field(alias="description")
84
+ task_priority: Optional[str] = Field(alias="task_priority")
85
+ type: Optional[str] = Field(alias="type")
86
+ receiver_id: Optional[int] = Field(alias="receiver_id")
87
+ project_id: Optional[int] = None
88
+ other_info: TaskDetailOtherInfo = Field(alias="other_info")
89
+ estimated_delivery_at: Optional[int] = None
90
+
91
+ @field_serializer("other_info")
92
+ def serialize_other_info(self, value: TaskDetailOtherInfo) -> str:
93
+ """将 other_info 序列化为 JSON 字符串"""
94
+ return value.model_dump_json()
95
+
96
+ @field_validator("other_info", mode="before")
97
+ @classmethod
98
+ def parse_other_info(cls, value):
99
+ """将字符串解析为 TaskDetailOtherInfo 对象"""
100
+ if isinstance(value, str):
101
+ try:
102
+ # 解析 JSON 字符串为字典
103
+ data = json.loads(value)
104
+ # 创建 TaskDetailOtherInfo 对象
105
+ return TaskDetailOtherInfo(**data)
106
+ except (json.JSONDecodeError, TypeError, ValueError) as e:
107
+ raise ValueError(f"无法解析 other_info 字符串: {e}")
108
+ elif isinstance(value, dict):
109
+ # 如果传入的是字典,直接创建对象
110
+ return TaskDetailOtherInfo(**value)
111
+ elif isinstance(value, TaskDetailOtherInfo):
112
+ # 如果已经是对象,直接返回
113
+ return value
114
+ else:
115
+ raise ValueError(
116
+ f"other_info 必须是字符串、字典或 TaskDetailOtherInfo 对象,得到: {type(value)}"
117
+ )
aihub/models/user.py ADDED
@@ -0,0 +1,46 @@
1
+ # !/usr/bin/env python
2
+ # -*-coding:utf-8 -*-
3
+
4
+
5
+ from __future__ import annotations
6
+
7
+ from typing import List, Optional
8
+
9
+ from pydantic import BaseModel
10
+
11
+
12
+ class UserSearchReq(BaseModel):
13
+ page_size: int = 1000000
14
+ page_num: int = 1
15
+ username: str = ""
16
+ nickname: str = ""
17
+ email: str = ""
18
+ user_ids: List[int] = []
19
+ role_ids: List[int] = []
20
+ role_names: List[str] = []
21
+ status: int = 1
22
+
23
+
24
+ class Role(BaseModel):
25
+ id: Optional[int] = None
26
+ name: Optional[str] = None
27
+ role_type: Optional[int] = None
28
+ menu_ids: Optional[List[int]] = None
29
+
30
+
31
+ class UserSearchDatum(BaseModel):
32
+ id: Optional[int] = 0
33
+ username: Optional[str] = None
34
+ nickname: Optional[str] = None
35
+ email: Optional[str] = None
36
+ status: Optional[int] = None
37
+ created_at: Optional[int] = None
38
+ roles: Optional[List[Role]] = None
39
+ tags: Optional[List[int]] = None
40
+
41
+
42
+ class UserSearchListData(BaseModel):
43
+ total: int
44
+ page_size: int
45
+ page_num: int
46
+ data: List[UserSearchDatum]
File without changes