tamar-file-hub-client 0.1.3__py3-none-any.whl → 0.1.4__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.
@@ -1,160 +1,171 @@
1
- """
2
- 用户上下文和请求上下文相关的Schema定义
3
- """
4
- from dataclasses import dataclass, field
5
- from typing import Optional, Dict, Any
6
- from datetime import datetime
7
-
8
- from file_hub_client.enums import Role
9
-
10
-
11
- @dataclass
12
- class UserContext:
13
- """
14
- 用户上下文信息
15
-
16
- 包含两大类信息:
17
- 1. ownership(所有权): org_id, user_id - 表示资源归属
18
- 2. operator(操作者): actor_id, role - 表示实际操作者(可能是用户、agent或系统)
19
- """
20
- # Ownership - 资源所有权信息
21
- org_id: str # 组织ID
22
- user_id: str # 用户ID
23
-
24
- # Operator - 操作者信息
25
- actor_id: Optional[str] = None # 实际操作者ID(如果为空,默认使用user_id)
26
- role: Role = Role.ACCOUNT # 操作者角色(ACCOUNT, AGENT, SYSTEM等)
27
-
28
- def __post_init__(self):
29
- """初始化后处理,如果actor_id为空,默认使用user_id"""
30
- if self.actor_id is None:
31
- self.actor_id = self.user_id
32
-
33
- def to_metadata(self) -> Dict[str, str]:
34
- """转换为gRPC metadata格式"""
35
- return {
36
- 'x-org-id': self.org_id,
37
- 'x-user-id': self.user_id,
38
- 'x-actor-id': self.actor_id,
39
- 'x-role': self.role,
40
- }
41
-
42
- @classmethod
43
- def from_metadata(cls, metadata: Dict[str, str]) -> Optional['UserContext']:
44
- """从metadata中解析用户上下文"""
45
- org_id = metadata.get('x-org-id')
46
- user_id = metadata.get('x-user-id')
47
-
48
- if not org_id or not user_id:
49
- return None
50
-
51
- return cls(
52
- org_id=org_id,
53
- user_id=user_id,
54
- actor_id=metadata.get('x-actor-id'),
55
- role=Role(metadata.get('x-role', Role.ACCOUNT))
56
- )
57
-
58
-
59
- @dataclass
60
- class RequestContext:
61
- """
62
- 请求上下文信息
63
-
64
- 包含请求相关的元数据,如客户端信息、请求追踪等
65
- """
66
- request_id: Optional[str] = None # 请求ID,用于追踪
67
- client_ip: Optional[str] = None # 客户端IP地址
68
- client_version: Optional[str] = None # 客户端版本
69
- client_type: Optional[str] = None # 客户端类型(web, mobile, desktop, cli等)
70
- user_agent: Optional[str] = None # User-Agent信息
71
- timestamp: Optional[datetime] = field(default_factory=datetime.now) # 请求时间戳
72
- extra: Dict[str, Any] = field(default_factory=dict) # 其他扩展信息
73
-
74
- def to_metadata(self) -> Dict[str, str]:
75
- """转换为gRPC metadata格式"""
76
- metadata = {}
77
-
78
- if self.request_id:
79
- metadata['x-request-id'] = self.request_id
80
- if self.client_ip:
81
- metadata['x-client-ip'] = self.client_ip
82
- if self.client_version:
83
- metadata['x-client-version'] = self.client_version
84
- if self.client_type:
85
- metadata['x-client-type'] = self.client_type
86
- if self.user_agent:
87
- metadata['x-user-agent'] = self.user_agent
88
- if self.timestamp:
89
- metadata['x-timestamp'] = self.timestamp.isoformat()
90
-
91
- # 添加扩展信息
92
- for key, value in self.extra.items():
93
- metadata[f'x-{key}'] = str(value)
94
-
95
- return metadata
96
-
97
- @classmethod
98
- def from_metadata(cls, metadata: Dict[str, str]) -> 'RequestContext':
99
- """从metadata中解析请求上下文"""
100
- # 提取标准字段
101
- request_id = metadata.get('x-request-id')
102
- client_ip = metadata.get('x-client-ip')
103
- client_version = metadata.get('x-client-version')
104
- client_type = metadata.get('x-client-type')
105
- user_agent = metadata.get('x-user-agent')
106
-
107
- # 解析时间戳
108
- timestamp = None
109
- if 'x-timestamp' in metadata:
110
- try:
111
- timestamp = datetime.fromisoformat(metadata['x-timestamp'])
112
- except:
113
- pass
114
-
115
- # 提取扩展字段
116
- extra = {}
117
- for key, value in metadata.items():
118
- if key.startswith('x-') and key not in [
119
- 'x-request-id', 'x-client-ip', 'x-client-version',
120
- 'x-client-type', 'x-user-agent', 'x-timestamp',
121
- 'x-org-id', 'x-user-id', 'x-actor-id', 'x-role'
122
- ]:
123
- extra[key[2:]] = value # 去掉 'x-' 前缀
124
-
125
- return cls(
126
- request_id=request_id,
127
- client_ip=client_ip,
128
- client_version=client_version,
129
- client_type=client_type,
130
- user_agent=user_agent,
131
- timestamp=timestamp,
132
- extra=extra
133
- )
134
-
135
-
136
- @dataclass
137
- class FullContext:
138
- """完整的上下文信息,包含用户上下文和请求上下文"""
139
- user_context: Optional[UserContext] = None
140
- request_context: Optional[RequestContext] = None
141
-
142
- def to_metadata(self) -> Dict[str, str]:
143
- """转换为gRPC metadata格式"""
144
- metadata = {}
145
-
146
- if self.user_context:
147
- metadata.update(self.user_context.to_metadata())
148
-
149
- if self.request_context:
150
- metadata.update(self.request_context.to_metadata())
151
-
152
- return metadata
153
-
154
- @classmethod
155
- def from_metadata(cls, metadata: Dict[str, str]) -> 'FullContext':
156
- """从metadata中解析完整上下文"""
157
- return cls(
158
- user_context=UserContext.from_metadata(metadata),
159
- request_context=RequestContext.from_metadata(metadata)
160
- )
1
+ """
2
+ 用户上下文和请求上下文相关的Schema定义
3
+ """
4
+ from dataclasses import dataclass, field
5
+ from typing import Optional, Dict, Any
6
+ from datetime import datetime
7
+
8
+ from file_hub_client.enums import Role
9
+
10
+
11
+ @dataclass
12
+ class UserContext:
13
+ """
14
+ 用户上下文信息
15
+
16
+ 包含两大类信息:
17
+ 1. ownership(所有权): org_id, user_id - 表示资源归属
18
+ 2. operator(操作者): actor_id, role - 表示实际操作者(可能是用户、agent或系统)
19
+ 3. request info(请求信息): user_ip - 表示请求来源IP(用于审计和安全)
20
+ """
21
+ # Ownership - 资源所有权信息
22
+ org_id: str # 组织ID
23
+ user_id: str # 用户ID
24
+
25
+ # Operator - 操作者信息
26
+ actor_id: Optional[str] = None # 实际操作者ID(如果为空,默认使用user_id)
27
+ role: Role = Role.ACCOUNT # 操作者角色(ACCOUNT, AGENT, SYSTEM等)
28
+
29
+ # Request info - 请求信息
30
+ user_ip: Optional[str] = None # 用户IP地址(请求来源IP)
31
+
32
+ def __post_init__(self):
33
+ """初始化后处理,如果actor_id为空,默认使用user_id"""
34
+ if self.actor_id is None:
35
+ self.actor_id = self.user_id
36
+
37
+ def to_metadata(self) -> Dict[str, str]:
38
+ """转换为gRPC metadata格式"""
39
+ metadata = {
40
+ 'x-org-id': self.org_id,
41
+ 'x-user-id': self.user_id,
42
+ 'x-actor-id': self.actor_id,
43
+ 'x-role': self.role,
44
+ }
45
+
46
+ # 只有当user_ip不为None时才添加x-user-ip
47
+ if self.user_ip is not None:
48
+ metadata['x-user-ip'] = self.user_ip
49
+
50
+ return metadata
51
+
52
+ @classmethod
53
+ def from_metadata(cls, metadata: Dict[str, str]) -> Optional['UserContext']:
54
+ """从metadata中解析用户上下文"""
55
+ org_id = metadata.get('x-org-id')
56
+ user_id = metadata.get('x-user-id')
57
+
58
+ if not org_id or not user_id:
59
+ return None
60
+
61
+ return cls(
62
+ org_id=org_id,
63
+ user_id=user_id,
64
+ actor_id=metadata.get('x-actor-id'),
65
+ role=Role(metadata.get('x-role', Role.ACCOUNT)),
66
+ user_ip=metadata.get('x-user-ip')
67
+ )
68
+
69
+
70
+ @dataclass
71
+ class RequestContext:
72
+ """
73
+ 请求上下文信息
74
+
75
+ 包含请求相关的元数据,如客户端信息、请求追踪等
76
+ """
77
+ request_id: Optional[str] = None # 请求ID,用于追踪
78
+ client_ip: Optional[str] = None # 客户端IP地址
79
+ client_version: Optional[str] = None # 客户端版本
80
+ client_type: Optional[str] = None # 客户端类型(web, mobile, desktop, cli等)
81
+ user_agent: Optional[str] = None # User-Agent信息
82
+ timestamp: Optional[datetime] = field(default_factory=datetime.now) # 请求时间戳
83
+ extra: Dict[str, Any] = field(default_factory=dict) # 其他扩展信息
84
+
85
+ def to_metadata(self) -> Dict[str, str]:
86
+ """转换为gRPC metadata格式"""
87
+ metadata = {}
88
+
89
+ if self.request_id:
90
+ metadata['x-request-id'] = self.request_id
91
+ if self.client_ip:
92
+ metadata['x-client-ip'] = self.client_ip
93
+ if self.client_version:
94
+ metadata['x-client-version'] = self.client_version
95
+ if self.client_type:
96
+ metadata['x-client-type'] = self.client_type
97
+ if self.user_agent:
98
+ metadata['x-user-agent'] = self.user_agent
99
+ if self.timestamp:
100
+ metadata['x-timestamp'] = self.timestamp.isoformat()
101
+
102
+ # 添加扩展信息
103
+ for key, value in self.extra.items():
104
+ metadata[f'x-{key}'] = str(value)
105
+
106
+ return metadata
107
+
108
+ @classmethod
109
+ def from_metadata(cls, metadata: Dict[str, str]) -> 'RequestContext':
110
+ """从metadata中解析请求上下文"""
111
+ # 提取标准字段
112
+ request_id = metadata.get('x-request-id')
113
+ client_ip = metadata.get('x-client-ip')
114
+ client_version = metadata.get('x-client-version')
115
+ client_type = metadata.get('x-client-type')
116
+ user_agent = metadata.get('x-user-agent')
117
+
118
+ # 解析时间戳
119
+ timestamp = None
120
+ if 'x-timestamp' in metadata:
121
+ try:
122
+ timestamp = datetime.fromisoformat(metadata['x-timestamp'])
123
+ except:
124
+ pass
125
+
126
+ # 提取扩展字段
127
+ extra = {}
128
+ for key, value in metadata.items():
129
+ if key.startswith('x-') and key not in [
130
+ 'x-request-id', 'x-client-ip', 'x-client-version',
131
+ 'x-client-type', 'x-user-agent', 'x-timestamp',
132
+ 'x-org-id', 'x-user-id', 'x-actor-id', 'x-role'
133
+ ]:
134
+ extra[key[2:]] = value # 去掉 'x-' 前缀
135
+
136
+ return cls(
137
+ request_id=request_id,
138
+ client_ip=client_ip,
139
+ client_version=client_version,
140
+ client_type=client_type,
141
+ user_agent=user_agent,
142
+ timestamp=timestamp,
143
+ extra=extra
144
+ )
145
+
146
+
147
+ @dataclass
148
+ class FullContext:
149
+ """完整的上下文信息,包含用户上下文和请求上下文"""
150
+ user_context: Optional[UserContext] = None
151
+ request_context: Optional[RequestContext] = None
152
+
153
+ def to_metadata(self) -> Dict[str, str]:
154
+ """转换为gRPC metadata格式"""
155
+ metadata = {}
156
+
157
+ if self.user_context:
158
+ metadata.update(self.user_context.to_metadata())
159
+
160
+ if self.request_context:
161
+ metadata.update(self.request_context.to_metadata())
162
+
163
+ return metadata
164
+
165
+ @classmethod
166
+ def from_metadata(cls, metadata: Dict[str, str]) -> 'FullContext':
167
+ """从metadata中解析完整上下文"""
168
+ return cls(
169
+ user_context=UserContext.from_metadata(metadata),
170
+ request_context=RequestContext.from_metadata(metadata)
171
+ )
@@ -124,3 +124,47 @@ class GetGcsUrlResponse(BaseModel):
124
124
  class BatchGcsUrlResponse(BaseModel):
125
125
  """批量GCS URL响应"""
126
126
  gcs_urls: List[GcsUrlInfo] = Field(default_factory=list, description="GCS URL列表")
127
+
128
+
129
+ # ========= 压缩服务相关模型 =========
130
+
131
+ class CompressedVariant(BaseModel):
132
+ """压缩变体信息"""
133
+ variant_name: str = Field(..., description="变体名称")
134
+ variant_type: str = Field(..., description="变体类型")
135
+ media_type: str = Field(..., description="媒体类型")
136
+ width: int = Field(..., description="宽度")
137
+ height: int = Field(..., description="高度")
138
+ file_size: int = Field(..., description="文件大小")
139
+ format: str = Field(..., description="格式")
140
+ quality: Optional[int] = Field(None, description="质量")
141
+ duration: Optional[float] = Field(None, description="时长")
142
+ bitrate: Optional[int] = Field(None, description="比特率")
143
+ fps: Optional[int] = Field(None, description="帧率")
144
+ compression_ratio: float = Field(..., description="压缩比")
145
+ stored_path: str = Field(..., description="存储路径")
146
+
147
+
148
+ class CompressionStatusResponse(BaseModel):
149
+ """压缩状态响应"""
150
+ status: str = Field(..., description="状态: pending, processing, completed, failed")
151
+ error_message: Optional[str] = Field(None, description="错误信息")
152
+ variants: List[CompressedVariant] = Field(default_factory=list, description="压缩变体列表")
153
+
154
+
155
+ class GetVariantsResponse(BaseModel):
156
+ """获取变体响应"""
157
+ variants: List[CompressedVariant] = Field(default_factory=list, description="压缩变体列表")
158
+
159
+
160
+ class RecompressionResponse(BaseModel):
161
+ """重新压缩响应"""
162
+ task_id: str = Field(..., description="任务ID")
163
+ status: str = Field(..., description="状态")
164
+
165
+
166
+ class VariantDownloadUrlResponse(BaseModel):
167
+ """变体下载URL响应"""
168
+ url: str = Field(..., description="下载URL")
169
+ error: Optional[str] = Field(None, description="错误信息")
170
+ variant_info: Optional[CompressedVariant] = Field(None, description="变体详细信息")