tamar-file-hub-client 0.2.2__py3-none-any.whl → 0.2.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.
Potentially problematic release.
This version of tamar-file-hub-client might be problematic. Click here for more details.
- file_hub_client/services/file/async_blob_service.py +1 -1
- file_hub_client/services/file/sync_blob_service.py +3 -3
- tamar_file_hub_client-0.2.3.dist-info/METADATA +704 -0
- {tamar_file_hub_client-0.2.2.dist-info → tamar_file_hub_client-0.2.3.dist-info}/RECORD +6 -6
- tamar_file_hub_client-0.2.2.dist-info/METADATA +0 -2640
- {tamar_file_hub_client-0.2.2.dist-info → tamar_file_hub_client-0.2.3.dist-info}/WHEEL +0 -0
- {tamar_file_hub_client-0.2.2.dist-info → tamar_file_hub_client-0.2.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,704 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tamar-file-hub-client
|
|
3
|
+
Version: 0.2.3
|
|
4
|
+
Summary: A Python SDK for gRPC-based file management system
|
|
5
|
+
Home-page: https://github.com/Tamar-Edge-AI/file-hub-client
|
|
6
|
+
Author: Oscar Ou
|
|
7
|
+
Author-email: oscar.ou@tamaredge.ai
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
21
|
+
Classifier: Topic :: Communications :: File Sharing
|
|
22
|
+
Classifier: Framework :: AsyncIO
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.8
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
Requires-Dist: grpcio>=1.67.1
|
|
27
|
+
Requires-Dist: grpcio-tools>=1.67.1
|
|
28
|
+
Requires-Dist: protobuf>=5.29.4
|
|
29
|
+
Requires-Dist: pydantic>=2.0.0
|
|
30
|
+
Requires-Dist: typing-extensions>=4.0.0; python_version < "3.10"
|
|
31
|
+
Requires-Dist: requests>=2.28.0
|
|
32
|
+
Requires-Dist: aiohttp>=3.8.0
|
|
33
|
+
Requires-Dist: aiofiles>=23.0.0
|
|
34
|
+
Requires-Dist: python-magic; platform_system != "Windows"
|
|
35
|
+
Requires-Dist: python-magic-bin~=0.4.14; platform_system == "Windows"
|
|
36
|
+
Dynamic: author
|
|
37
|
+
Dynamic: author-email
|
|
38
|
+
Dynamic: classifier
|
|
39
|
+
Dynamic: description
|
|
40
|
+
Dynamic: description-content-type
|
|
41
|
+
Dynamic: home-page
|
|
42
|
+
Dynamic: license
|
|
43
|
+
Dynamic: requires-dist
|
|
44
|
+
Dynamic: requires-python
|
|
45
|
+
Dynamic: summary
|
|
46
|
+
|
|
47
|
+
# File Hub Client
|
|
48
|
+
|
|
49
|
+
Python SDK,用于文件中心系统 - 一个支持传统文件、文件夹和电子表格(Taple)的综合文件管理系统。
|
|
50
|
+
|
|
51
|
+
## 功能特性
|
|
52
|
+
|
|
53
|
+
- 🚀 **双模式支持**:提供异步(AsyncIO)和同步两种客户端实现
|
|
54
|
+
- 📁 **完整的文件管理**:上传、下载、分享、重命名、删除文件
|
|
55
|
+
- 📂 **文件夹管理**:创建、重命名、移动、删除分层文件夹结构
|
|
56
|
+
- 📊 **Taple电子表格**:类Excel的完整功能,包括工作表、行、列、单元格操作
|
|
57
|
+
- 🔄 **多种上传模式**:普通模式、流式模式,根据文件大小自动选择
|
|
58
|
+
- 🎯 **智能MIME检测**:26+种文件格式的魔术字节检测和扩展名推断
|
|
59
|
+
- 🤖 **AI友好**:完美支持AI模型输出(字节+MIME类型)
|
|
60
|
+
- 🔒 **上传保护**:支持GCS和OSS存储后端的禁止覆盖功能
|
|
61
|
+
- 🎨 **媒体压缩**:自动生成和管理压缩的图片/视频变体
|
|
62
|
+
- 📊 **批量操作**:批量状态查询和批量操作支持
|
|
63
|
+
- 🛡️ **健壮的错误处理**:完善的异常体系和自动重试机制
|
|
64
|
+
- 📝 **完整类型支持**:完整的类型提示,更好的IDE支持
|
|
65
|
+
- 📡 **gRPC日志**:JSON格式的请求/响应日志,可自定义级别
|
|
66
|
+
- 🔧 **灵活配置**:支持环境变量和程序化配置
|
|
67
|
+
|
|
68
|
+
## 安装
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pip install file-hub-client
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## 快速开始
|
|
75
|
+
|
|
76
|
+
### 基础设置
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from file_hub_client import AsyncFileHubClient, FileHubClient
|
|
80
|
+
|
|
81
|
+
# 异步客户端
|
|
82
|
+
async_client = AsyncFileHubClient(
|
|
83
|
+
host="your-file-hub-server.com",
|
|
84
|
+
port=50051,
|
|
85
|
+
use_tls=True
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# 同步客户端
|
|
89
|
+
client = FileHubClient(
|
|
90
|
+
host="your-file-hub-server.com",
|
|
91
|
+
port=50051,
|
|
92
|
+
use_tls=True
|
|
93
|
+
)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 环境变量配置
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# 服务器配置
|
|
100
|
+
FILE_HUB_HOST=your-file-hub-server.com
|
|
101
|
+
FILE_HUB_PORT=50051
|
|
102
|
+
FILE_HUB_USE_TLS=true
|
|
103
|
+
|
|
104
|
+
# 可选认证头
|
|
105
|
+
FILE_HUB_HEADER_X_ORG_ID=your-org-id
|
|
106
|
+
FILE_HUB_HEADER_X_USER_ID=your-user-id
|
|
107
|
+
|
|
108
|
+
# 日志配置
|
|
109
|
+
FILE_HUB_LOG_LEVEL=INFO
|
|
110
|
+
FILE_HUB_LOG_GRPC_ENABLED=true
|
|
111
|
+
FILE_HUB_LOG_REQUEST_PAYLOAD=false
|
|
112
|
+
FILE_HUB_LOG_RESPONSE_PAYLOAD=false
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## 文件操作
|
|
116
|
+
|
|
117
|
+
### 上传文件
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
# 简单上传
|
|
121
|
+
result = await async_client.blobs.upload(
|
|
122
|
+
file=b"Hello, World!",
|
|
123
|
+
file_name="hello.txt"
|
|
124
|
+
)
|
|
125
|
+
print(f"文件ID: {result.file.id}")
|
|
126
|
+
|
|
127
|
+
# 使用文件路径上传
|
|
128
|
+
result = await async_client.blobs.upload(
|
|
129
|
+
file="/path/to/local/file.pdf"
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# 带MIME类型上传(适用于AI生成的内容)
|
|
133
|
+
result = await async_client.blobs.upload(
|
|
134
|
+
file=ai_generated_bytes,
|
|
135
|
+
mime_type="image/png",
|
|
136
|
+
file_name="generated.png"
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
# 上传到指定文件夹
|
|
140
|
+
result = await async_client.blobs.upload(
|
|
141
|
+
file="/path/to/document.docx",
|
|
142
|
+
folder_id="folder_123"
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
# 大文件流式上传(10MB-100MB)
|
|
146
|
+
result = await async_client.blobs.upload(
|
|
147
|
+
file=large_file_path,
|
|
148
|
+
mode=UploadMode.STREAM
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
# 禁止覆盖(防止重复上传)
|
|
152
|
+
result = await async_client.blobs.upload(
|
|
153
|
+
file=content,
|
|
154
|
+
forbid_overwrite=True # 如果文件已存在将失败
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
# 临时文件带过期时间
|
|
158
|
+
result = await async_client.blobs.upload(
|
|
159
|
+
file=temp_content,
|
|
160
|
+
is_temporary=True,
|
|
161
|
+
expire_seconds=3600 # 1小时后过期
|
|
162
|
+
)
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### 下载文件
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
# 下载到文件
|
|
169
|
+
await async_client.blobs.download(
|
|
170
|
+
file_id="file_123",
|
|
171
|
+
save_path="/path/to/save/file.pdf"
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
# 下载到字节
|
|
175
|
+
file_bytes = await async_client.blobs.download_to_bytes(
|
|
176
|
+
file_id="file_123"
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
# 生成下载URL
|
|
180
|
+
url_response = await async_client.blobs.generate_download_url(
|
|
181
|
+
file_id="file_123"
|
|
182
|
+
)
|
|
183
|
+
download_url = url_response.download_url
|
|
184
|
+
|
|
185
|
+
# 批量生成下载URL
|
|
186
|
+
batch_response = await async_client.blobs.batch_generate_download_url(
|
|
187
|
+
file_ids=["file_1", "file_2", "file_3"]
|
|
188
|
+
)
|
|
189
|
+
for item in batch_response.items:
|
|
190
|
+
print(f"{item.file_id}: {item.download_url}")
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### 文件分享
|
|
194
|
+
|
|
195
|
+
```python
|
|
196
|
+
# 生成分享链接
|
|
197
|
+
share_response = await async_client.files.generate_share_link(
|
|
198
|
+
file_id="file_123",
|
|
199
|
+
expire_seconds=86400, # 24小时
|
|
200
|
+
password="secret123",
|
|
201
|
+
max_visit_count=10
|
|
202
|
+
)
|
|
203
|
+
print(f"分享URL: {share_response.share_url}")
|
|
204
|
+
|
|
205
|
+
# 访问分享的文件
|
|
206
|
+
file_info = await async_client.files.visit_file(
|
|
207
|
+
share_url="https://share.example.com/xxx",
|
|
208
|
+
password="secret123"
|
|
209
|
+
)
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### 文件管理
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
# 获取文件信息
|
|
216
|
+
file_info = await async_client.files.get_file(file_id="file_123")
|
|
217
|
+
|
|
218
|
+
# 重命名文件
|
|
219
|
+
await async_client.files.rename_file(
|
|
220
|
+
file_id="file_123",
|
|
221
|
+
new_name="新名称.pdf"
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
# 删除文件
|
|
225
|
+
await async_client.files.delete_file(file_id="file_123")
|
|
226
|
+
|
|
227
|
+
# 列出文件夹中的文件
|
|
228
|
+
files = await async_client.files.list_files(
|
|
229
|
+
folder_id="folder_123",
|
|
230
|
+
page=1,
|
|
231
|
+
page_size=20
|
|
232
|
+
)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### 压缩和变体
|
|
236
|
+
|
|
237
|
+
```python
|
|
238
|
+
# 获取压缩状态
|
|
239
|
+
status = await async_client.blobs.get_compression_status(
|
|
240
|
+
file_id="image_123"
|
|
241
|
+
)
|
|
242
|
+
print(f"压缩状态: {status.status}")
|
|
243
|
+
|
|
244
|
+
# 获取压缩变体
|
|
245
|
+
variants = await async_client.blobs.get_compressed_variants(
|
|
246
|
+
file_id="image_123"
|
|
247
|
+
)
|
|
248
|
+
for variant in variants.variants:
|
|
249
|
+
print(f"{variant.spec}: {variant.size} 字节")
|
|
250
|
+
|
|
251
|
+
# 生成变体下载URL
|
|
252
|
+
variant_url = await async_client.blobs.generate_variant_download_url(
|
|
253
|
+
file_id="image_123",
|
|
254
|
+
variant_spec="800x600"
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
# 触发重新压缩
|
|
258
|
+
await async_client.blobs.trigger_recompression(
|
|
259
|
+
file_id="image_123",
|
|
260
|
+
variant_specs=["1920x1080", "1280x720", "640x480"]
|
|
261
|
+
)
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### 批量状态查询
|
|
265
|
+
|
|
266
|
+
```python
|
|
267
|
+
# 批量查询文件状态
|
|
268
|
+
status_response = await async_client.blobs.batch_get_file_status(
|
|
269
|
+
file_ids=["file_1", "file_2", "file_3"]
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
for status in status_response.statuses:
|
|
273
|
+
print(f"文件 {status.file_id}:")
|
|
274
|
+
print(f" 上传状态: {status.upload_status}")
|
|
275
|
+
print(f" 压缩状态: {status.compression_status}")
|
|
276
|
+
print(f" 同步状态: {status.sync_status}")
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## 文件夹操作
|
|
280
|
+
|
|
281
|
+
```python
|
|
282
|
+
# 创建文件夹
|
|
283
|
+
folder = await async_client.folders.create_folder(
|
|
284
|
+
name="我的文档",
|
|
285
|
+
parent_folder_id="parent_123" # 可选
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
# 重命名文件夹
|
|
289
|
+
await async_client.folders.rename_folder(
|
|
290
|
+
folder_id="folder_123",
|
|
291
|
+
new_name="重要文档"
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
# 移动文件夹
|
|
295
|
+
await async_client.folders.move_folder(
|
|
296
|
+
folder_id="folder_123",
|
|
297
|
+
new_parent_folder_id="parent_456"
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
# 删除文件夹
|
|
301
|
+
await async_client.folders.delete_folder(
|
|
302
|
+
folder_id="folder_123",
|
|
303
|
+
force=True # 即使非空也删除
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
# 列出文件夹
|
|
307
|
+
folders = await async_client.folders.list_folders(
|
|
308
|
+
parent_folder_id="parent_123",
|
|
309
|
+
page=1,
|
|
310
|
+
page_size=20
|
|
311
|
+
)
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Taple(电子表格)操作
|
|
315
|
+
|
|
316
|
+
### 表格管理
|
|
317
|
+
|
|
318
|
+
```python
|
|
319
|
+
# 创建表格
|
|
320
|
+
table = await async_client.taples.create_table(
|
|
321
|
+
name="销售报告 2024",
|
|
322
|
+
description="年度销售数据"
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
# 获取表格信息
|
|
326
|
+
table_info = await async_client.taples.get_table(
|
|
327
|
+
table_id="table_123"
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
# 更新表格
|
|
331
|
+
await async_client.taples.update_table(
|
|
332
|
+
table_id="table_123",
|
|
333
|
+
name="销售报告 2024(更新版)",
|
|
334
|
+
description="包含第四季度更新的年度销售数据"
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
# 删除表格
|
|
338
|
+
await async_client.taples.delete_table(
|
|
339
|
+
table_id="table_123"
|
|
340
|
+
)
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### 工作表操作
|
|
344
|
+
|
|
345
|
+
```python
|
|
346
|
+
# 创建工作表
|
|
347
|
+
sheet = await async_client.taples.create_sheet(
|
|
348
|
+
table_id="table_123",
|
|
349
|
+
name="第一季度销售",
|
|
350
|
+
position=0
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
# 列出工作表
|
|
354
|
+
sheets = await async_client.taples.list_sheets(
|
|
355
|
+
table_id="table_123"
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
# 获取工作表数据
|
|
359
|
+
sheet_data = await async_client.taples.get_sheet_data(
|
|
360
|
+
sheet_id="sheet_123"
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
# 更新工作表
|
|
364
|
+
await async_client.taples.update_sheet(
|
|
365
|
+
sheet_id="sheet_123",
|
|
366
|
+
name="第一季度销售(修订版)"
|
|
367
|
+
)
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### 列操作
|
|
371
|
+
|
|
372
|
+
```python
|
|
373
|
+
# 创建列
|
|
374
|
+
column = await async_client.taples.create_column(
|
|
375
|
+
sheet_id="sheet_123",
|
|
376
|
+
name="产品名称",
|
|
377
|
+
data_type="string",
|
|
378
|
+
position=0,
|
|
379
|
+
width=200
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
# 更新列
|
|
383
|
+
await async_client.taples.update_column(
|
|
384
|
+
column_id="col_123",
|
|
385
|
+
name="产品描述",
|
|
386
|
+
width=300
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
# 批量编辑列
|
|
390
|
+
await async_client.taples.batch_edit_columns(
|
|
391
|
+
sheet_id="sheet_123",
|
|
392
|
+
operations=[
|
|
393
|
+
{"type": "create", "name": "价格", "data_type": "number"},
|
|
394
|
+
{"type": "create", "name": "数量", "data_type": "integer"},
|
|
395
|
+
{"type": "update", "column_id": "col_123", "width": 150}
|
|
396
|
+
]
|
|
397
|
+
)
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### 行操作
|
|
401
|
+
|
|
402
|
+
```python
|
|
403
|
+
# 创建行
|
|
404
|
+
row = await async_client.taples.create_row(
|
|
405
|
+
sheet_id="sheet_123",
|
|
406
|
+
data={"col_1": "iPhone 15", "col_2": 6999.00, "col_3": 100},
|
|
407
|
+
position=0
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
# 更新行
|
|
411
|
+
await async_client.taples.update_row(
|
|
412
|
+
row_id="row_123",
|
|
413
|
+
data={"col_2": 6499.00, "col_3": 150}
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
# 批量编辑行
|
|
417
|
+
await async_client.taples.batch_edit_rows(
|
|
418
|
+
sheet_id="sheet_123",
|
|
419
|
+
operations=[
|
|
420
|
+
{"type": "create", "data": {"col_1": "iPad Pro"}},
|
|
421
|
+
{"type": "update", "row_id": "row_123", "data": {"col_3": 200}},
|
|
422
|
+
{"type": "delete", "row_id": "row_456"}
|
|
423
|
+
]
|
|
424
|
+
)
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
### 单元格操作
|
|
428
|
+
|
|
429
|
+
```python
|
|
430
|
+
# 编辑单元格
|
|
431
|
+
await async_client.taples.edit_cell(
|
|
432
|
+
sheet_id="sheet_123",
|
|
433
|
+
row_id="row_123",
|
|
434
|
+
column_id="col_456",
|
|
435
|
+
value="新值",
|
|
436
|
+
style={"bold": True, "color": "#FF0000"}
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
# 批量编辑单元格
|
|
440
|
+
await async_client.taples.batch_edit_cells(
|
|
441
|
+
sheet_id="sheet_123",
|
|
442
|
+
operations=[
|
|
443
|
+
{
|
|
444
|
+
"row_id": "row_1",
|
|
445
|
+
"column_id": "col_1",
|
|
446
|
+
"value": "已更新",
|
|
447
|
+
"style": {"italic": True}
|
|
448
|
+
},
|
|
449
|
+
{
|
|
450
|
+
"row_id": "row_2",
|
|
451
|
+
"column_id": "col_2",
|
|
452
|
+
"value": 123.45
|
|
453
|
+
}
|
|
454
|
+
]
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
# 获取单元格数据
|
|
458
|
+
cell_data = await async_client.taples.get_cell_data(
|
|
459
|
+
sheet_id="sheet_123",
|
|
460
|
+
row_id="row_123",
|
|
461
|
+
column_id="col_456"
|
|
462
|
+
)
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
### 数据导入/导出
|
|
466
|
+
|
|
467
|
+
```python
|
|
468
|
+
# 导出表格数据
|
|
469
|
+
export_result = await async_client.taples.export_table_data(
|
|
470
|
+
table_id="table_123",
|
|
471
|
+
format=ExportFormat.XLSX,
|
|
472
|
+
include_styles=True
|
|
473
|
+
)
|
|
474
|
+
# 使用file_id下载导出的文件
|
|
475
|
+
await async_client.blobs.download(
|
|
476
|
+
file_id=export_result.file_id,
|
|
477
|
+
save_path="导出的表格.xlsx"
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
# 从文件导入数据
|
|
481
|
+
import_result = await async_client.taples.import_table_data(
|
|
482
|
+
table_id="table_123",
|
|
483
|
+
file_id="file_789", # Excel/CSV文件
|
|
484
|
+
sheet_id="sheet_123", # 目标工作表
|
|
485
|
+
mode="append", # 或 "replace"
|
|
486
|
+
has_header=True
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
# 克隆表格
|
|
490
|
+
clone_result = await async_client.taples.clone_table_data(
|
|
491
|
+
source_table_id="table_123",
|
|
492
|
+
target_table_id="table_456",
|
|
493
|
+
mode="override"
|
|
494
|
+
)
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
## 同步模式使用
|
|
498
|
+
|
|
499
|
+
所有操作也都支持同步模式:
|
|
500
|
+
|
|
501
|
+
```python
|
|
502
|
+
from file_hub_client import FileHubClient
|
|
503
|
+
|
|
504
|
+
# 初始化同步客户端
|
|
505
|
+
client = FileHubClient(
|
|
506
|
+
host="your-file-hub-server.com",
|
|
507
|
+
port=50051
|
|
508
|
+
)
|
|
509
|
+
|
|
510
|
+
# 同步上传
|
|
511
|
+
result = client.blobs.upload(
|
|
512
|
+
file=b"Hello, 同步世界!",
|
|
513
|
+
file_name="hello_sync.txt"
|
|
514
|
+
)
|
|
515
|
+
|
|
516
|
+
# 同步下载
|
|
517
|
+
client.blobs.download(
|
|
518
|
+
file_id="file_123",
|
|
519
|
+
save_path="/path/to/save.pdf"
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
# 同步文件夹操作
|
|
523
|
+
folder = client.folders.create_folder(
|
|
524
|
+
name="同步文件夹"
|
|
525
|
+
)
|
|
526
|
+
|
|
527
|
+
# 同步Taple操作
|
|
528
|
+
table = client.taples.create_table(
|
|
529
|
+
name="同步表格"
|
|
530
|
+
)
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
## 日志配置
|
|
534
|
+
|
|
535
|
+
```python
|
|
536
|
+
from file_hub_client.utils.logging import setup_logging
|
|
537
|
+
|
|
538
|
+
# 基础设置
|
|
539
|
+
setup_logging(
|
|
540
|
+
level="DEBUG",
|
|
541
|
+
enable_grpc_logging=True
|
|
542
|
+
)
|
|
543
|
+
|
|
544
|
+
# 高级设置带自定义处理器
|
|
545
|
+
import logging
|
|
546
|
+
custom_handler = logging.FileHandler("file_hub.log")
|
|
547
|
+
|
|
548
|
+
setup_logging(
|
|
549
|
+
level="INFO",
|
|
550
|
+
enable_grpc_logging=True,
|
|
551
|
+
log_request_payload=True, # 记录请求数据
|
|
552
|
+
log_response_payload=True, # 记录响应数据
|
|
553
|
+
handler=custom_handler,
|
|
554
|
+
use_json_format=True # JSON格式日志
|
|
555
|
+
)
|
|
556
|
+
|
|
557
|
+
# 自定义格式的人类可读日志
|
|
558
|
+
setup_logging(
|
|
559
|
+
level="DEBUG",
|
|
560
|
+
use_json_format=False,
|
|
561
|
+
format_string="[%(asctime)s] %(levelname)s - %(message)s"
|
|
562
|
+
)
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
## 错误处理
|
|
566
|
+
|
|
567
|
+
```python
|
|
568
|
+
from file_hub_client.errors import (
|
|
569
|
+
FileHubError,
|
|
570
|
+
ValidationError,
|
|
571
|
+
NotFoundError,
|
|
572
|
+
PermissionError,
|
|
573
|
+
NetworkError,
|
|
574
|
+
ServerError
|
|
575
|
+
)
|
|
576
|
+
|
|
577
|
+
try:
|
|
578
|
+
result = await async_client.blobs.upload(
|
|
579
|
+
file=content,
|
|
580
|
+
forbid_overwrite=True
|
|
581
|
+
)
|
|
582
|
+
except ValidationError as e:
|
|
583
|
+
print(f"输入无效: {e}")
|
|
584
|
+
except NotFoundError as e:
|
|
585
|
+
print(f"资源未找到: {e}")
|
|
586
|
+
except PermissionError as e:
|
|
587
|
+
print(f"权限拒绝: {e}")
|
|
588
|
+
except NetworkError as e:
|
|
589
|
+
print(f"网络问题: {e}")
|
|
590
|
+
except ServerError as e:
|
|
591
|
+
print(f"服务器错误: {e}")
|
|
592
|
+
except FileHubError as e:
|
|
593
|
+
print(f"一般错误: {e}")
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
## 高级配置
|
|
597
|
+
|
|
598
|
+
### 自定义元数据
|
|
599
|
+
|
|
600
|
+
```python
|
|
601
|
+
# 向请求添加自定义元数据
|
|
602
|
+
result = await async_client.blobs.upload(
|
|
603
|
+
file=content,
|
|
604
|
+
file_name="document.pdf",
|
|
605
|
+
request_id="unique-request-id-123", # 用于幂等性
|
|
606
|
+
**{
|
|
607
|
+
"x-custom-header": "custom-value",
|
|
608
|
+
"x-trace-id": "trace-123"
|
|
609
|
+
}
|
|
610
|
+
)
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
### 连接池设置
|
|
614
|
+
|
|
615
|
+
```python
|
|
616
|
+
# 配置连接池
|
|
617
|
+
client = AsyncFileHubClient(
|
|
618
|
+
host="server.com",
|
|
619
|
+
port=50051,
|
|
620
|
+
max_connections=100,
|
|
621
|
+
connection_timeout=30,
|
|
622
|
+
request_timeout=60,
|
|
623
|
+
retry_config={
|
|
624
|
+
"max_attempts": 3,
|
|
625
|
+
"initial_backoff": 1,
|
|
626
|
+
"max_backoff": 30,
|
|
627
|
+
"backoff_multiplier": 2
|
|
628
|
+
}
|
|
629
|
+
)
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
### 上传模式选择
|
|
633
|
+
|
|
634
|
+
SDK根据文件大小自动选择最优上传模式:
|
|
635
|
+
|
|
636
|
+
- **NORMAL** (< 10MB):直接gRPC上传
|
|
637
|
+
- **STREAM** (10MB - 100MB):流式上传到云存储
|
|
638
|
+
- **STREAM** (> 100MB):当前使用流式上传(OSS断点续传功能待完成)
|
|
639
|
+
|
|
640
|
+
您也可以手动指定上传模式:
|
|
641
|
+
|
|
642
|
+
```python
|
|
643
|
+
from file_hub_client.enums import UploadMode
|
|
644
|
+
|
|
645
|
+
# 强制使用流式模式
|
|
646
|
+
result = await async_client.blobs.upload(
|
|
647
|
+
file=small_file,
|
|
648
|
+
mode=UploadMode.STREAM
|
|
649
|
+
)
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
## MIME类型检测
|
|
653
|
+
|
|
654
|
+
SDK使用魔术字节自动检测以下格式的MIME类型:
|
|
655
|
+
|
|
656
|
+
**图片**:JPEG、PNG、GIF、BMP、WebP、ICO、TIFF、SVG
|
|
657
|
+
**视频**:MP4、AVI、MOV、WMV、FLV、WebM、MKV
|
|
658
|
+
**文档**:PDF、DOCX、XLSX、PPTX
|
|
659
|
+
**压缩包**:ZIP、RAR、7Z、TAR、GZIP
|
|
660
|
+
**其他**:MP3、WAV、JSON、XML、HTML
|
|
661
|
+
|
|
662
|
+
对于AI生成的内容或已知MIME类型的情况:
|
|
663
|
+
|
|
664
|
+
```python
|
|
665
|
+
# 显式设置MIME类型
|
|
666
|
+
result = await async_client.blobs.upload(
|
|
667
|
+
file=ai_generated_bytes,
|
|
668
|
+
mime_type="image/png" # SDK会推断出.png扩展名
|
|
669
|
+
)
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
## 存储后端支持
|
|
673
|
+
|
|
674
|
+
SDK自动处理不同的存储后端:
|
|
675
|
+
|
|
676
|
+
- **谷歌云存储(GCS)**:自动检测和头部管理
|
|
677
|
+
- **阿里云OSS**:自动检测和头部管理
|
|
678
|
+
- **自定义S3兼容存储**:可与任何S3兼容存储配合使用
|
|
679
|
+
|
|
680
|
+
根据上传URL检测的存储类型自动应用禁止覆盖头部。
|
|
681
|
+
|
|
682
|
+
## 最佳实践
|
|
683
|
+
|
|
684
|
+
1. **I/O密集型操作使用异步客户端**:异步客户端在处理多个并发操作时更高效。
|
|
685
|
+
|
|
686
|
+
2. **批量操作**:处理多个文件时使用批量方法,减少网络开销。
|
|
687
|
+
|
|
688
|
+
3. **错误处理**:始终使用try-except块包装操作,优雅地处理潜在错误。
|
|
689
|
+
|
|
690
|
+
4. **连接复用**:创建客户端实例一次,在整个应用程序中复用。
|
|
691
|
+
|
|
692
|
+
5. **日志记录**:开发中启用gRPC日志,但在生产环境中考虑禁用载荷日志以提高性能。
|
|
693
|
+
|
|
694
|
+
6. **上传保护**:在生产环境中使用`forbid_overwrite=True`防止意外文件覆盖。
|
|
695
|
+
|
|
696
|
+
7. **请求ID**:为关键操作提供唯一的请求ID以实现幂等性。
|
|
697
|
+
|
|
698
|
+
## 许可证
|
|
699
|
+
|
|
700
|
+
MIT许可证
|
|
701
|
+
|
|
702
|
+
## 支持
|
|
703
|
+
|
|
704
|
+
有关问题、疑问或贡献,请访问[GitHub仓库](https://github.com/your-org/file-hub-client)。
|