tamar-model-client 0.1.2__tar.gz → 0.1.3__tar.gz

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.
Files changed (24) hide show
  1. {tamar_model_client-0.1.2 → tamar_model_client-0.1.3}/PKG-INFO +1 -1
  2. {tamar_model_client-0.1.2 → tamar_model_client-0.1.3}/setup.py +1 -1
  3. {tamar_model_client-0.1.2 → tamar_model_client-0.1.3}/tamar_model_client/async_client.py +81 -86
  4. {tamar_model_client-0.1.2 → tamar_model_client-0.1.3}/tamar_model_client.egg-info/PKG-INFO +1 -1
  5. {tamar_model_client-0.1.2 → tamar_model_client-0.1.3}/README.md +0 -0
  6. {tamar_model_client-0.1.2 → tamar_model_client-0.1.3}/setup.cfg +0 -0
  7. {tamar_model_client-0.1.2 → tamar_model_client-0.1.3}/tamar_model_client/__init__.py +0 -0
  8. {tamar_model_client-0.1.2 → tamar_model_client-0.1.3}/tamar_model_client/auth.py +0 -0
  9. {tamar_model_client-0.1.2 → tamar_model_client-0.1.3}/tamar_model_client/enums/__init__.py +0 -0
  10. {tamar_model_client-0.1.2 → tamar_model_client-0.1.3}/tamar_model_client/enums/channel.py +0 -0
  11. {tamar_model_client-0.1.2 → tamar_model_client-0.1.3}/tamar_model_client/enums/invoke.py +0 -0
  12. {tamar_model_client-0.1.2 → tamar_model_client-0.1.3}/tamar_model_client/enums/providers.py +0 -0
  13. {tamar_model_client-0.1.2 → tamar_model_client-0.1.3}/tamar_model_client/exceptions.py +0 -0
  14. {tamar_model_client-0.1.2 → tamar_model_client-0.1.3}/tamar_model_client/generated/__init__.py +0 -0
  15. {tamar_model_client-0.1.2 → tamar_model_client-0.1.3}/tamar_model_client/generated/model_service_pb2.py +0 -0
  16. {tamar_model_client-0.1.2 → tamar_model_client-0.1.3}/tamar_model_client/generated/model_service_pb2_grpc.py +0 -0
  17. {tamar_model_client-0.1.2 → tamar_model_client-0.1.3}/tamar_model_client/schemas/__init__.py +0 -0
  18. {tamar_model_client-0.1.2 → tamar_model_client-0.1.3}/tamar_model_client/schemas/inputs.py +0 -0
  19. {tamar_model_client-0.1.2 → tamar_model_client-0.1.3}/tamar_model_client/schemas/outputs.py +0 -0
  20. {tamar_model_client-0.1.2 → tamar_model_client-0.1.3}/tamar_model_client/sync_client.py +0 -0
  21. {tamar_model_client-0.1.2 → tamar_model_client-0.1.3}/tamar_model_client.egg-info/SOURCES.txt +0 -0
  22. {tamar_model_client-0.1.2 → tamar_model_client-0.1.3}/tamar_model_client.egg-info/dependency_links.txt +0 -0
  23. {tamar_model_client-0.1.2 → tamar_model_client-0.1.3}/tamar_model_client.egg-info/requires.txt +0 -0
  24. {tamar_model_client-0.1.2 → tamar_model_client-0.1.3}/tamar_model_client.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tamar-model-client
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: A Python SDK for interacting with the Model Manager gRPC service
5
5
  Home-page: http://gitlab.tamaredge.top/project-tap/AgentOS/model-manager-client
6
6
  Author: Oscar Ou
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="tamar-model-client",
5
- version="0.1.2",
5
+ version="0.1.3",
6
6
  description="A Python SDK for interacting with the Model Manager gRPC service",
7
7
  author="Oscar Ou",
8
8
  author_email="oscar.ou@tamaredge.ai",
@@ -1,5 +1,6 @@
1
1
  import asyncio
2
2
  import atexit
3
+ import base64
3
4
  import json
4
5
  import logging
5
6
  import os
@@ -27,6 +28,72 @@ if not logging.getLogger().hasHandlers():
27
28
  logger = logging.getLogger(__name__)
28
29
 
29
30
 
31
+ def is_effective_value(value) -> bool:
32
+ """
33
+ 递归判断value是否是有意义的有效值
34
+ """
35
+ if value is None or value is NOT_GIVEN:
36
+ return False
37
+
38
+ if isinstance(value, str):
39
+ return value.strip() != ""
40
+
41
+ if isinstance(value, bytes):
42
+ return len(value) > 0
43
+
44
+ if isinstance(value, dict):
45
+ for v in value.values():
46
+ if is_effective_value(v):
47
+ return True
48
+ return False
49
+
50
+ if isinstance(value, list):
51
+ for item in value:
52
+ if is_effective_value(item):
53
+ return True
54
+ return False
55
+
56
+ return True # 其他类型(int/float/bool)只要不是None就算有效
57
+
58
+
59
+ def serialize_value(value):
60
+ """递归处理单个值,处理BaseModel, dict, list, bytes"""
61
+ if not is_effective_value(value):
62
+ return None
63
+ if isinstance(value, BaseModel):
64
+ return serialize_value(value.model_dump())
65
+ if hasattr(value, "dict") and callable(value.dict):
66
+ return serialize_value(value.dict())
67
+ if isinstance(value, dict):
68
+ return {k: serialize_value(v) for k, v in value.items()}
69
+ if isinstance(value, list) or (isinstance(value, Iterable) and not isinstance(value, (str, bytes))):
70
+ return [serialize_value(v) for v in value]
71
+ if isinstance(value, bytes):
72
+ return f"bytes:{base64.b64encode(value).decode('utf-8')}"
73
+ return value
74
+
75
+
76
+ from typing import Any
77
+
78
+
79
+ def remove_none_from_dict(data: Any) -> Any:
80
+ """
81
+ 遍历 dict/list,递归删除 value 为 None 的字段
82
+ """
83
+ if isinstance(data, dict):
84
+ new_dict = {}
85
+ for key, value in data.items():
86
+ if value is None:
87
+ continue
88
+ cleaned_value = remove_none_from_dict(value)
89
+ new_dict[key] = cleaned_value
90
+ return new_dict
91
+ elif isinstance(data, list):
92
+ return [remove_none_from_dict(item) for item in data]
93
+ else:
94
+ return data
95
+
96
+
30
97
  class AsyncTamarModelClient:
31
98
  def __init__(
32
99
  self,
@@ -177,51 +244,15 @@ class AsyncTamarModelClient:
177
244
  if field in model_request_dict:
178
245
  value = model_request_dict[field]
179
246
 
180
- # Skip fields with NotGiven or None (unless explicitly allowed)
181
- if value is NOT_GIVEN or value is None:
247
+ # 跳过无效的值
248
+ if not is_effective_value(value):
182
249
  continue
183
250
 
184
- # 特别处理:如果是自定义的 BaseModel 或特定类型
185
- if isinstance(value, BaseModel):
186
- grpc_request_kwargs[field] = value.model_dump()
187
- # 如果是 OpenAI / Google 里的自定义对象,通常有 dict() 方法
188
- elif hasattr(value, "dict") and callable(value.dict):
189
- grpc_request_kwargs[field] = value.dict()
190
- # 如果是 list,需要处理里面元素也是自定义对象的情况
191
- elif isinstance(value, Iterable) and not isinstance(value, (str, bytes, dict)):
192
- new_list = []
193
- for item in value:
194
- if isinstance(item, BaseModel):
195
- new_list.append(item.model_dump())
196
- elif hasattr(item, "dict") and callable(item.dict):
197
- new_list.append(item.dict())
198
- elif isinstance(item, dict):
199
- # Handle nested dictionaries
200
- nested_dict = {}
201
- for k, v in item.items():
202
- if isinstance(v, BaseModel):
203
- nested_dict[k] = v.model_dump()
204
- elif hasattr(v, "dict") and callable(v.dict):
205
- nested_dict[k] = v.dict()
206
- else:
207
- nested_dict[k] = v
208
- new_list.append(nested_dict)
209
- else:
210
- new_list.append(item)
211
- grpc_request_kwargs[field] = new_list
212
- # 如果是 dict,同理处理内部元素
213
- elif isinstance(value, dict):
214
- new_dict = {}
215
- for k, v in value.items():
216
- if isinstance(v, BaseModel):
217
- new_dict[k] = v.model_dump()
218
- elif hasattr(v, "dict") and callable(v.dict):
219
- new_dict[k] = v.dict()
220
- else:
221
- new_dict[k] = v
222
- grpc_request_kwargs[field] = new_dict
223
- else:
224
- grpc_request_kwargs[field] = value
251
+ # 序列化grpc不支持的类型
252
+ grpc_request_kwargs[field] = serialize_value(value)
253
+
254
+ # 清理 serialize后的 grpc_request_kwargs
255
+ grpc_request_kwargs = remove_none_from_dict(grpc_request_kwargs)
225
256
 
226
257
  request = model_service_pb2.ModelRequestItem(
227
258
  provider=model_request.provider.value,
@@ -300,51 +331,15 @@ class AsyncTamarModelClient:
300
331
  if field in model_request_dict:
301
332
  value = model_request_dict[field]
302
333
 
303
- # Skip fields with NotGiven or None (unless explicitly allowed)
304
- if value is NOT_GIVEN or value is None:
334
+ # 跳过无效的值
335
+ if not is_effective_value(value):
305
336
  continue
306
337
 
307
- # 特别处理:如果是自定义的 BaseModel 或特定类型
308
- if isinstance(value, BaseModel):
309
- grpc_request_kwargs[field] = value.model_dump()
310
- # 如果是 OpenAI / Google 里的自定义对象,通常有 dict() 方法
311
- elif hasattr(value, "dict") and callable(value.dict):
312
- grpc_request_kwargs[field] = value.dict()
313
- # 如果是 list,需要处理里面元素也是自定义对象的情况
314
- elif isinstance(value, Iterable) and not isinstance(value, (str, bytes, dict)):
315
- new_list = []
316
- for item in value:
317
- if isinstance(item, BaseModel):
318
- new_list.append(item.model_dump())
319
- elif hasattr(item, "dict") and callable(item.dict):
320
- new_list.append(item.dict())
321
- elif isinstance(item, dict):
322
- # Handle nested dictionaries
323
- nested_dict = {}
324
- for k, v in item.items():
325
- if isinstance(v, BaseModel):
326
- nested_dict[k] = v.model_dump()
327
- elif hasattr(v, "dict") and callable(v.dict):
328
- nested_dict[k] = v.dict()
329
- else:
330
- nested_dict[k] = v
331
- new_list.append(nested_dict)
332
- else:
333
- new_list.append(item)
334
- grpc_request_kwargs[field] = new_list
335
- # 如果是 dict,同理处理内部元素
336
- elif isinstance(value, dict):
337
- new_dict = {}
338
- for k, v in value.items():
339
- if isinstance(v, BaseModel):
340
- new_dict[k] = v.model_dump()
341
- elif hasattr(v, "dict") and callable(v.dict):
342
- new_dict[k] = v.dict()
343
- else:
344
- new_dict[k] = v
345
- grpc_request_kwargs[field] = new_dict
346
- else:
347
- grpc_request_kwargs[field] = value
338
+ # 序列化grpc不支持的类型
339
+ grpc_request_kwargs[field] = serialize_value(value)
340
+
341
+ # 清理 serialize后的 grpc_request_kwargs
342
+ grpc_request_kwargs = remove_none_from_dict(grpc_request_kwargs)
348
343
 
349
344
  items.append(model_service_pb2.ModelRequestItem(
350
345
  provider=model_request_item.provider.value,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tamar-model-client
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: A Python SDK for interacting with the Model Manager gRPC service
5
5
  Home-page: http://gitlab.tamaredge.top/project-tap/AgentOS/model-manager-client
6
6
  Author: Oscar Ou