tamar-file-hub-client 0.1.4__py3-none-any.whl → 0.1.6__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.
@@ -182,7 +182,8 @@ message BatchDownloadUrlResponse {
182
182
  message DownloadUrlInfo {
183
183
  string file_id = 1;
184
184
  string url = 2;
185
- optional string error = 3;
185
+ string mime_type = 3;
186
+ optional string error = 4;
186
187
  }
187
188
 
188
189
  message GetGcsUrlResponse {
@@ -1,170 +1,171 @@
1
- """
2
- 文件相关数据模型
3
- """
4
- from datetime import datetime
5
- from typing import Optional, Dict, List, Any
6
- from pydantic import BaseModel, Field
7
-
8
-
9
- class File(BaseModel):
10
- """文件信息模型"""
11
- id: str = Field(..., description="文件ID")
12
- folder_id: str = Field(..., description="所属文件夹ID")
13
- file_name: str = Field(..., description="原始文件名")
14
- file_type: str = Field(..., description="文件类型")
15
- created_at: datetime = Field(..., description="创建时间")
16
- updated_at: datetime = Field(..., description="更新时间")
17
-
18
- class Config:
19
- json_encoders = {
20
- datetime: lambda v: v.isoformat()
21
- }
22
-
23
-
24
- class UploadFile(BaseModel):
25
- """上传文件信息模型"""
26
- id: str = Field(..., description="上传文件ID")
27
- folder_id: str = Field(..., description="所属文件夹ID")
28
- storage_type: str = Field(..., description="存储类型")
29
- stored_name: str = Field(..., description="存储文件名")
30
- stored_path: str = Field(..., description="存储路径")
31
- file_id: str = Field(..., description="所属文件ID")
32
- file_name: str = Field(..., description="原始文件名")
33
- file_size: int = Field(0, description="文件大小(字节)")
34
- file_ext: str = Field(..., description="文件后缀")
35
- mime_type: str = Field(..., description="MIME类型")
36
- created_at: datetime = Field(..., description="创建时间")
37
- updated_at: datetime = Field(..., description="更新时间")
38
-
39
- class Config:
40
- json_encoders = {
41
- datetime: lambda v: v.isoformat()
42
- }
43
-
44
-
45
- class FileUploadResponse(BaseModel):
46
- """文件上传返回"""
47
- file: File = Field(..., description="文件信息")
48
- upload_file: UploadFile = Field(..., description="上传文件信息")
49
-
50
-
51
- class UploadUrlResponse(BaseModel):
52
- """上传URL响应"""
53
- file: File = Field(..., description="文件信息")
54
- upload_file: UploadFile = Field(..., description="上传文件信息")
55
- upload_url: str = Field(..., description="上传URL")
56
-
57
-
58
- class ShareLinkRequest(BaseModel):
59
- """生成分享链接请求"""
60
- file_id: str = Field(..., description="文件ID")
61
- is_public: bool = Field(True, description="是否公开")
62
- access_scope: str = Field("view", description="访问范围")
63
- expire_seconds: int = Field(86400, description="过期时间(秒)")
64
- max_access: Optional[int] = Field(None, description="最大访问次数")
65
- password: Optional[str] = Field(None, description="访问密码")
66
-
67
-
68
- class FileVisitRequest(BaseModel):
69
- """文件访问请求"""
70
- file_share_id: str = Field(..., description="分享ID")
71
- access_type: str = Field(..., description="访问类型")
72
- access_duration: int = Field(..., description="访问时长")
73
- metadata: Dict[str, Any] = Field(default_factory=dict, description="元数据")
74
-
75
-
76
- class FileListRequest(BaseModel):
77
- """文件列表请求"""
78
- folder_id: str = Field(..., description="文件夹ID")
79
- file_name: Optional[str] = Field(None, description="文件名")
80
- file_type: Optional[List[str]] = Field(None, description="文件类型")
81
- created_by_role: Optional[str] = Field(None, description="创建者角色")
82
- created_by: Optional[str] = Field(None, description="创建者")
83
- page_size: int = Field(20, description="每页大小")
84
- page: int = Field(1, description="页码")
85
-
86
-
87
- class FileListResponse(BaseModel):
88
- """文件列表响应"""
89
- files: List[File] = Field(default_factory=list, description="文件列表")
90
-
91
-
92
- class GetFileResponse(BaseModel):
93
- """获取文件响应"""
94
- file: File = Field(..., description="文件信息")
95
- upload_file: Optional[UploadFile] = Field(None, description="上传文件信息")
96
-
97
-
98
- class DownloadUrlInfo(BaseModel):
99
- """下载URL信息"""
100
- file_id: str = Field(..., description="文件ID")
101
- url: str = Field(..., description="下载URL")
102
- error: Optional[str] = Field(None, description="错误信息")
103
-
104
-
105
- class BatchDownloadUrlResponse(BaseModel):
106
- """批量下载URL响应"""
107
- download_urls: List[DownloadUrlInfo] = Field(default_factory=list, description="下载URL列表")
108
-
109
-
110
- class GcsUrlInfo(BaseModel):
111
- """GCS URL信息"""
112
- file_id: str = Field(..., description="文件ID")
113
- gcs_url: str = Field(..., description="GCS URL")
114
- mime_type: str = Field(..., description="MIME类型")
115
- error: Optional[str] = Field(None, description="错误信息")
116
-
117
-
118
- class GetGcsUrlResponse(BaseModel):
119
- """获取GCS URL响应"""
120
- gcs_url: str = Field(..., description="GCS URL")
121
- mime_type: str = Field(..., description="MIME类型")
122
-
123
-
124
- class BatchGcsUrlResponse(BaseModel):
125
- """批量GCS URL响应"""
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="变体详细信息")
1
+ """
2
+ 文件相关数据模型
3
+ """
4
+ from datetime import datetime
5
+ from typing import Optional, Dict, List, Any
6
+ from pydantic import BaseModel, Field
7
+
8
+
9
+ class File(BaseModel):
10
+ """文件信息模型"""
11
+ id: str = Field(..., description="文件ID")
12
+ folder_id: str = Field(..., description="所属文件夹ID")
13
+ file_name: str = Field(..., description="原始文件名")
14
+ file_type: str = Field(..., description="文件类型")
15
+ created_at: datetime = Field(..., description="创建时间")
16
+ updated_at: datetime = Field(..., description="更新时间")
17
+
18
+ class Config:
19
+ json_encoders = {
20
+ datetime: lambda v: v.isoformat()
21
+ }
22
+
23
+
24
+ class UploadFile(BaseModel):
25
+ """上传文件信息模型"""
26
+ id: str = Field(..., description="上传文件ID")
27
+ folder_id: str = Field(..., description="所属文件夹ID")
28
+ storage_type: str = Field(..., description="存储类型")
29
+ stored_name: str = Field(..., description="存储文件名")
30
+ stored_path: str = Field(..., description="存储路径")
31
+ file_id: str = Field(..., description="所属文件ID")
32
+ file_name: str = Field(..., description="原始文件名")
33
+ file_size: int = Field(0, description="文件大小(字节)")
34
+ file_ext: str = Field(..., description="文件后缀")
35
+ mime_type: str = Field(..., description="MIME类型")
36
+ created_at: datetime = Field(..., description="创建时间")
37
+ updated_at: datetime = Field(..., description="更新时间")
38
+
39
+ class Config:
40
+ json_encoders = {
41
+ datetime: lambda v: v.isoformat()
42
+ }
43
+
44
+
45
+ class FileUploadResponse(BaseModel):
46
+ """文件上传返回"""
47
+ file: File = Field(..., description="文件信息")
48
+ upload_file: UploadFile = Field(..., description="上传文件信息")
49
+
50
+
51
+ class UploadUrlResponse(BaseModel):
52
+ """上传URL响应"""
53
+ file: File = Field(..., description="文件信息")
54
+ upload_file: UploadFile = Field(..., description="上传文件信息")
55
+ upload_url: str = Field(..., description="上传URL")
56
+
57
+
58
+ class ShareLinkRequest(BaseModel):
59
+ """生成分享链接请求"""
60
+ file_id: str = Field(..., description="文件ID")
61
+ is_public: bool = Field(True, description="是否公开")
62
+ access_scope: str = Field("view", description="访问范围")
63
+ expire_seconds: int = Field(86400, description="过期时间(秒)")
64
+ max_access: Optional[int] = Field(None, description="最大访问次数")
65
+ password: Optional[str] = Field(None, description="访问密码")
66
+
67
+
68
+ class FileVisitRequest(BaseModel):
69
+ """文件访问请求"""
70
+ file_share_id: str = Field(..., description="分享ID")
71
+ access_type: str = Field(..., description="访问类型")
72
+ access_duration: int = Field(..., description="访问时长")
73
+ metadata: Dict[str, Any] = Field(default_factory=dict, description="元数据")
74
+
75
+
76
+ class FileListRequest(BaseModel):
77
+ """文件列表请求"""
78
+ folder_id: str = Field(..., description="文件夹ID")
79
+ file_name: Optional[str] = Field(None, description="文件名")
80
+ file_type: Optional[List[str]] = Field(None, description="文件类型")
81
+ created_by_role: Optional[str] = Field(None, description="创建者角色")
82
+ created_by: Optional[str] = Field(None, description="创建者")
83
+ page_size: int = Field(20, description="每页大小")
84
+ page: int = Field(1, description="页码")
85
+
86
+
87
+ class FileListResponse(BaseModel):
88
+ """文件列表响应"""
89
+ files: List[File] = Field(default_factory=list, description="文件列表")
90
+
91
+
92
+ class GetFileResponse(BaseModel):
93
+ """获取文件响应"""
94
+ file: File = Field(..., description="文件信息")
95
+ upload_file: Optional[UploadFile] = Field(None, description="上传文件信息")
96
+
97
+
98
+ class DownloadUrlInfo(BaseModel):
99
+ """下载URL信息"""
100
+ file_id: str = Field(..., description="文件ID")
101
+ url: str = Field(..., description="下载URL")
102
+ mime_type: str = Field(..., description="MIME类型")
103
+ error: Optional[str] = Field(None, description="错误信息")
104
+
105
+
106
+ class BatchDownloadUrlResponse(BaseModel):
107
+ """批量下载URL响应"""
108
+ download_urls: List[DownloadUrlInfo] = Field(default_factory=list, description="下载URL列表")
109
+
110
+
111
+ class GcsUrlInfo(BaseModel):
112
+ """GCS URL信息"""
113
+ file_id: str = Field(..., description="文件ID")
114
+ gcs_url: str = Field(..., description="GCS URL")
115
+ mime_type: str = Field(..., description="MIME类型")
116
+ error: Optional[str] = Field(None, description="错误信息")
117
+
118
+
119
+ class GetGcsUrlResponse(BaseModel):
120
+ """获取GCS URL响应"""
121
+ gcs_url: str = Field(..., description="GCS URL")
122
+ mime_type: str = Field(..., description="MIME类型")
123
+
124
+
125
+ class BatchGcsUrlResponse(BaseModel):
126
+ """批量GCS URL响应"""
127
+ gcs_urls: List[GcsUrlInfo] = Field(default_factory=list, description="GCS URL列表")
128
+
129
+
130
+ # ========= 压缩服务相关模型 =========
131
+
132
+ class CompressedVariant(BaseModel):
133
+ """压缩变体信息"""
134
+ variant_name: str = Field(..., description="变体名称")
135
+ variant_type: str = Field(..., description="变体类型")
136
+ media_type: str = Field(..., description="媒体类型")
137
+ width: int = Field(..., description="宽度")
138
+ height: int = Field(..., description="高度")
139
+ file_size: int = Field(..., description="文件大小")
140
+ format: str = Field(..., description="格式")
141
+ quality: Optional[int] = Field(None, description="质量")
142
+ duration: Optional[float] = Field(None, description="时长")
143
+ bitrate: Optional[int] = Field(None, description="比特率")
144
+ fps: Optional[int] = Field(None, description="帧率")
145
+ compression_ratio: float = Field(..., description="压缩比")
146
+ stored_path: str = Field(..., description="存储路径")
147
+
148
+
149
+ class CompressionStatusResponse(BaseModel):
150
+ """压缩状态响应"""
151
+ status: str = Field(..., description="状态: pending, processing, completed, failed")
152
+ error_message: Optional[str] = Field(None, description="错误信息")
153
+ variants: List[CompressedVariant] = Field(default_factory=list, description="压缩变体列表")
154
+
155
+
156
+ class GetVariantsResponse(BaseModel):
157
+ """获取变体响应"""
158
+ variants: List[CompressedVariant] = Field(default_factory=list, description="压缩变体列表")
159
+
160
+
161
+ class RecompressionResponse(BaseModel):
162
+ """重新压缩响应"""
163
+ task_id: str = Field(..., description="任务ID")
164
+ status: str = Field(..., description="状态")
165
+
166
+
167
+ class VariantDownloadUrlResponse(BaseModel):
168
+ """变体下载URL响应"""
169
+ url: str = Field(..., description="下载URL")
170
+ error: Optional[str] = Field(None, description="错误信息")
171
+ variant_info: Optional[CompressedVariant] = Field(None, description="变体详细信息")
@@ -221,7 +221,7 @@ class AsyncBlobService(BaseFileService):
221
221
  upload_url = await self.http_uploader.start_resumable_session(
222
222
  url=upload_url_resp.upload_url,
223
223
  total_file_size=file_size,
224
- mine_type=mime_type,
224
+ mime_type=mime_type,
225
225
  )
226
226
 
227
227
  # 上传文件到对象存储
@@ -403,6 +403,7 @@ class AsyncBlobService(BaseFileService):
403
403
  keep_original_filename: Optional[bool] = False,
404
404
  url: Optional[str] = None,
405
405
  file_name: Optional[str] = None,
406
+ mime_type: Optional[str] = None,
406
407
  request_id: Optional[str] = None,
407
408
  **metadata
408
409
  ) -> FileUploadResponse:
@@ -418,6 +419,7 @@ class AsyncBlobService(BaseFileService):
418
419
  keep_original_filename: 是否保留原始文件名(默认False)
419
420
  url: 要下载并上传的URL(可选)
420
421
  file_name: 当使用url参数时指定的文件名(可选)
422
+ mime_type: MIME类型(可选,用于推断文件扩展名,特别适用于AI生成的字节数据)
421
423
  request_id: 请求ID(可选,如果不提供则自动生成)
422
424
  **metadata: 额外的元数据
423
425
 
@@ -427,6 +429,8 @@ class AsyncBlobService(BaseFileService):
427
429
  Note:
428
430
  必须提供 file 或 url 参数之一
429
431
 
432
+ 当传入bytes或BinaryIO且未提供file_name时,建议提供mime_type以确保正确的文件扩展名推断
433
+
430
434
  Cache-Control 头在 GCS 直传模式(STREAM/RESUMABLE)下自动设置为 "public, max-age=86400"
431
435
  """
432
436
  # 参数验证:必须提供 file 或 url 之一
@@ -449,26 +453,38 @@ class AsyncBlobService(BaseFileService):
449
453
  # 使用下载的内容作为file参数
450
454
  file = downloaded_content
451
455
 
452
- # 提取文件信息(bytes会返回默认的MIME类型,我们稍后会基于文件名重新计算)
453
- _, content, file_size, _, _, file_hash = self._extract_file_info(file)
456
+ # 基于文件名计算MIME类型
457
+ mime_type = get_file_mime_type(Path(file_name))
458
+
459
+ # 提取文件信息,传入MIME类型用于推断扩展名
460
+ _, content, file_size, _, _, file_hash = self._extract_file_info(file, mime_type)
454
461
 
455
462
  # file_name已经在上面设置了(要么是用户指定的,要么是从URL提取的)
456
463
  extracted_file_name = file_name
457
464
 
458
- # 基于文件名计算文件类型和MIME类型
465
+ # 基于文件名计算文件类型
459
466
  file_type = Path(extracted_file_name).suffix.lstrip('.').lower() if Path(
460
467
  extracted_file_name).suffix else 'dat'
461
- mime_type = get_file_mime_type(Path(extracted_file_name))
462
468
  else:
463
469
  # 解析文件参数,提取文件信息
464
- extracted_file_name, content, file_size, extract_mime_type, extract_file_type, file_hash = self._extract_file_info(
465
- file)
470
+ # 如果用户指定了文件名,先从文件名推断MIME类型,然后传给_extract_file_info
466
471
  if file_name:
472
+ # 用户指定了文件名,优先使用用户提供的MIME类型,否则从文件名推断
473
+ if mime_type:
474
+ file_name_mime_type = mime_type
475
+ else:
476
+ file_name_mime_type = get_file_mime_type(Path(file_name))
477
+ extracted_file_name, content, file_size, extract_mime_type, extract_file_type, file_hash = self._extract_file_info(
478
+ file, file_name_mime_type)
479
+ # 使用用户指定的文件名
467
480
  extracted_file_name = file_name
468
- mime_type = get_file_mime_type(file_name)
481
+ mime_type = file_name_mime_type
469
482
  file_type = Path(extracted_file_name).suffix.lstrip('.').lower() if Path(
470
483
  extracted_file_name).suffix else 'dat'
471
484
  else:
485
+ # 没有指定文件名,传入用户提供的MIME类型(如果有)
486
+ extracted_file_name, content, file_size, extract_mime_type, extract_file_type, file_hash = self._extract_file_info(
487
+ file, mime_type)
472
488
  mime_type = extract_mime_type
473
489
  file_type = extract_file_type
474
490
 
@@ -670,6 +686,7 @@ class AsyncBlobService(BaseFileService):
670
686
  download_urls.append(DownloadUrlInfo(
671
687
  file_id=url_info.file_id,
672
688
  url=url_info.url,
689
+ mime_type=url_info.mime_type,
673
690
  error=url_info.error if url_info.HasField('error') else None
674
691
  ))
675
692