tamar-model-client 0.1.27__py3-none-any.whl → 0.1.28__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.
@@ -31,6 +31,7 @@ import grpc
31
31
  from .core import (
32
32
  generate_request_id,
33
33
  set_request_id,
34
+ set_origin_request_id,
34
35
  get_protected_logger,
35
36
  MAX_MESSAGE_LENGTH,
36
37
  get_request_id,
@@ -352,20 +353,15 @@ class TamarModelClient(BaseClient, HttpFallbackMixin):
352
353
  except grpc.RpcError as e:
353
354
  # 使用新的错误处理逻辑
354
355
  context['retry_count'] = attempt
356
+ current_duration = time.time() - method_start_time
355
357
 
356
358
  # 判断是否可以重试
357
359
  should_retry = self._should_retry(e, attempt)
358
- if not should_retry or attempt >= self.max_retries:
359
- # 不可重试或已达到最大重试次数
360
- current_duration = time.time() - method_start_time
361
- context['duration'] = current_duration
362
- last_exception = self.error_handler.handle_error(e, context)
363
- break
364
-
365
- # 计算当前的耗时
366
- current_duration = time.time() - method_start_time
367
360
 
368
- # 特殊处理 CANCELLED 错误
361
+ # 记录 channel 错误
362
+ self._record_channel_error(e)
363
+
364
+ # 特殊处理 CANCELLED 错误的日志
369
365
  if e.code() == grpc.StatusCode.CANCELLED:
370
366
  channel_state = None
371
367
  if self.channel:
@@ -389,7 +385,106 @@ class TamarModelClient(BaseClient, HttpFallbackMixin):
389
385
  }
390
386
  )
391
387
 
392
- # 记录重试日志
388
+ # 检查是否应该尝试快速降级
389
+ should_try_fallback = self._should_try_fallback(e.code(), attempt)
390
+
391
+ if should_try_fallback:
392
+ # 尝试快速降级到HTTP
393
+ logger.warning(
394
+ f"🚀 Fast fallback triggered for {e.code().name} after {attempt + 1} attempts",
395
+ extra={
396
+ "log_type": "fast_fallback",
397
+ "request_id": context.get('request_id'),
398
+ "data": {
399
+ "error_code": e.code().name,
400
+ "attempt": attempt,
401
+ "fallback_reason": "immediate" if e.code() in self.immediate_fallback_errors else "after_retries"
402
+ }
403
+ }
404
+ )
405
+
406
+ try:
407
+ # 从 kwargs 中提取降级所需的参数
408
+ fallback_kwargs = kwargs.copy()
409
+
410
+ # 如果是 _invoke_request,需要提取 model_request
411
+ if func.__name__ == '_invoke_request' and len(args) >= 3:
412
+ # args 结构: (request, metadata, invoke_timeout)
413
+ # 需要从原始参数中恢复 model_request
414
+ if hasattr(self, '_current_model_request'):
415
+ model_request = self._current_model_request
416
+ origin_request_id = getattr(self, '_current_origin_request_id', None)
417
+ timeout = args[2] if len(args) > 2 else None
418
+ request_id = context.get('request_id')
419
+
420
+ # 尝试HTTP降级
421
+ result = self._invoke_http_fallback(model_request, timeout, request_id, origin_request_id)
422
+ # 如果是 BatchInvoke,需要使用批量降级
423
+ elif func.__name__ == 'BatchInvoke' and hasattr(self, '_current_batch_request'):
424
+ batch_request = self._current_batch_request
425
+ origin_request_id = getattr(self, '_current_origin_request_id', None)
426
+ timeout = fallback_kwargs.get('timeout')
427
+ request_id = context.get('request_id')
428
+
429
+ # 尝试批量HTTP降级
430
+ result = self._invoke_batch_http_fallback(batch_request, timeout, request_id, origin_request_id)
431
+ else:
432
+ # 其他情况,无法处理降级
433
+ raise ValueError(f"Unable to perform HTTP fallback for {func.__name__}")
434
+
435
+ logger.info(
436
+ f"✅ Fast fallback to HTTP succeeded",
437
+ extra={
438
+ "log_type": "fast_fallback_success",
439
+ "request_id": request_id,
440
+ "data": {
441
+ "grpc_attempts": attempt + 1,
442
+ "fallback_duration": time.time() - method_start_time
443
+ }
444
+ }
445
+ )
446
+
447
+ return result
448
+ except Exception as fallback_error:
449
+ # 降级失败,记录日志但继续原有重试逻辑
450
+ logger.warning(
451
+ f"⚠️ Fast fallback to HTTP failed: {str(fallback_error)}",
452
+ extra={
453
+ "log_type": "fast_fallback_failed",
454
+ "request_id": context.get('request_id'),
455
+ "data": {
456
+ "fallback_error": str(fallback_error),
457
+ "will_continue_grpc_retry": should_retry and attempt < self.max_retries
458
+ }
459
+ }
460
+ )
461
+
462
+ if not should_retry or attempt >= self.max_retries:
463
+ # 不可重试或已达到最大重试次数
464
+ context['duration'] = current_duration
465
+
466
+ # 记录最终失败日志
467
+ log_data = {
468
+ "log_type": "info",
469
+ "request_id": context.get('request_id'),
470
+ "data": {
471
+ "error_code": e.code().name if e.code() else 'UNKNOWN',
472
+ "retry_count": attempt,
473
+ "max_retries": self.max_retries,
474
+ "method": context.get('method', 'unknown'),
475
+ "final_failure": True
476
+ },
477
+ "duration": current_duration
478
+ }
479
+ logger.warning(
480
+ f"Final attempt {attempt + 1}/{self.max_retries + 1} failed: {e.code()} (no more retries)",
481
+ extra=log_data
482
+ )
483
+
484
+ last_exception = self.error_handler.handle_error(e, context)
485
+ break
486
+
487
+ # 可以重试,记录重试日志
393
488
  log_data = {
394
489
  "log_type": "info",
395
490
  "request_id": context.get('request_id'),
@@ -397,12 +492,14 @@ class TamarModelClient(BaseClient, HttpFallbackMixin):
397
492
  "error_code": e.code().name if e.code() else 'UNKNOWN',
398
493
  "retry_count": attempt,
399
494
  "max_retries": self.max_retries,
400
- "method": context.get('method', 'unknown')
495
+ "method": context.get('method', 'unknown'),
496
+ "will_retry": True,
497
+ "fallback_attempted": should_try_fallback
401
498
  },
402
499
  "duration": current_duration
403
500
  }
404
501
  logger.warning(
405
- f"Attempt {attempt + 1}/{self.max_retries + 1} failed: {e.code()}",
502
+ f"Attempt {attempt + 1}/{self.max_retries + 1} failed: {e.code()} (will retry)",
406
503
  extra=log_data
407
504
  )
408
505
 
@@ -410,12 +507,9 @@ class TamarModelClient(BaseClient, HttpFallbackMixin):
410
507
  if attempt < self.max_retries:
411
508
  delay = self._calculate_backoff(attempt, e.code())
412
509
  time.sleep(delay)
413
-
414
- context['duration'] = current_duration
415
- last_exception = self.error_handler.handle_error(e, context)
416
510
 
417
- # 记录 channel 错误
418
- self._record_channel_error(e)
511
+ # 保存异常,以备后续使用
512
+ last_exception = e
419
513
 
420
514
  except Exception as e:
421
515
  # 非 gRPC 错误,直接包装抛出
@@ -803,7 +897,12 @@ class TamarModelClient(BaseClient, HttpFallbackMixin):
803
897
  if self.resilient_enabled and self.circuit_breaker and self.circuit_breaker.is_open:
804
898
  if self.http_fallback_url:
805
899
  logger.warning("🔻 Circuit breaker is OPEN, using HTTP fallback")
806
- return self._invoke_http_fallback(model_request, timeout, request_id)
900
+ # 在这里还没有计算origin_request_id,所以先计算
901
+ temp_origin_request_id = None
902
+ temp_request_id = request_id
903
+ if request_id:
904
+ temp_request_id, temp_origin_request_id = self._request_id_manager.get_composite_id(request_id)
905
+ return self._invoke_http_fallback(model_request, timeout, temp_request_id, temp_origin_request_id)
807
906
 
808
907
  self._ensure_initialized()
809
908
 
@@ -823,6 +922,8 @@ class TamarModelClient(BaseClient, HttpFallbackMixin):
823
922
  request_id = generate_request_id()
824
923
 
825
924
  set_request_id(request_id)
925
+ if origin_request_id:
926
+ set_origin_request_id(origin_request_id)
826
927
  metadata = self._build_auth_metadata(request_id, origin_request_id)
827
928
 
828
929
  # 构建日志数据
@@ -874,7 +975,17 @@ class TamarModelClient(BaseClient, HttpFallbackMixin):
874
975
  request_id=request_id
875
976
  )
876
977
  else:
877
- result = self._retry_request(self._invoke_request, request, metadata, invoke_timeout, request_id=request_id)
978
+ # 存储model_request和origin_request_id供重试方法使用
979
+ self._current_model_request = model_request
980
+ self._current_origin_request_id = origin_request_id
981
+ try:
982
+ result = self._retry_request(self._invoke_request, request, metadata, invoke_timeout, request_id=request_id)
983
+ finally:
984
+ # 清理临时存储
985
+ if hasattr(self, '_current_model_request'):
986
+ delattr(self, '_current_model_request')
987
+ if hasattr(self, '_current_origin_request_id'):
988
+ delattr(self, '_current_origin_request_id')
878
989
 
879
990
  # 记录非流式响应的成功日志
880
991
  duration = time.time() - start_time
@@ -922,16 +1033,11 @@ class TamarModelClient(BaseClient, HttpFallbackMixin):
922
1033
  if isinstance(e, grpc.RpcError):
923
1034
  self._record_channel_error(e)
924
1035
 
925
- # 记录失败并尝试降级(如果启用了熔断)
1036
+ # 记录失败(如果启用了熔断)
926
1037
  if self.resilient_enabled and self.circuit_breaker:
927
1038
  # 将错误码传递给熔断器,用于智能失败统计
928
1039
  error_code = e.code() if hasattr(e, 'code') else None
929
1040
  self.circuit_breaker.record_failure(error_code)
930
-
931
- # 如果可以降级,则降级
932
- if self.http_fallback_url and self.circuit_breaker.should_fallback():
933
- logger.warning(f"🔻 gRPC failed, falling back to HTTP: {str(e)}")
934
- return self._invoke_http_fallback(model_request, timeout, request_id)
935
1041
 
936
1042
  raise e
937
1043
  except Exception as e:
@@ -961,6 +1067,17 @@ class TamarModelClient(BaseClient, HttpFallbackMixin):
961
1067
  Returns:
962
1068
  BatchModelResponse: 批量请求的结果
963
1069
  """
1070
+ # 如果启用了熔断且熔断器打开,直接走 HTTP
1071
+ if self.resilient_enabled and self.circuit_breaker and self.circuit_breaker.is_open:
1072
+ if self.http_fallback_url:
1073
+ logger.warning("🔻 Circuit breaker is OPEN, using HTTP fallback for batch request")
1074
+ # 在这里还没有计算origin_request_id,所以先计算
1075
+ temp_origin_request_id = None
1076
+ temp_request_id = request_id
1077
+ if request_id:
1078
+ temp_request_id, temp_origin_request_id = self._request_id_manager.get_composite_id(request_id)
1079
+ return self._invoke_batch_http_fallback(batch_request_model, timeout, temp_request_id, temp_origin_request_id)
1080
+
964
1081
  self._ensure_initialized()
965
1082
 
966
1083
  if not self.default_payload:
@@ -979,6 +1096,8 @@ class TamarModelClient(BaseClient, HttpFallbackMixin):
979
1096
  request_id = generate_request_id()
980
1097
 
981
1098
  set_request_id(request_id)
1099
+ if origin_request_id:
1100
+ set_origin_request_id(origin_request_id)
982
1101
  metadata = self._build_auth_metadata(request_id, origin_request_id)
983
1102
 
984
1103
  # 构建日志数据
@@ -1025,6 +1144,11 @@ class TamarModelClient(BaseClient, HttpFallbackMixin):
1025
1144
 
1026
1145
  try:
1027
1146
  invoke_timeout = timeout or self.default_invoke_timeout
1147
+
1148
+ # 保存批量请求信息用于降级
1149
+ self._current_batch_request = batch_request_model
1150
+ self._current_origin_request_id = origin_request_id
1151
+
1028
1152
  batch_response = self._retry_request(
1029
1153
  self.stub.BatchInvoke,
1030
1154
  batch_request,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tamar-model-client
3
- Version: 0.1.27
3
+ Version: 0.1.28
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
@@ -18,6 +18,8 @@ Requires-Dist: PyJWT
18
18
  Requires-Dist: nest_asyncio
19
19
  Requires-Dist: openai
20
20
  Requires-Dist: google-genai
21
+ Requires-Dist: requests>=2.25.0
22
+ Requires-Dist: aiohttp>=3.7.0
21
23
  Dynamic: author
22
24
  Dynamic: author-email
23
25
  Dynamic: classifier
@@ -65,6 +67,8 @@ Dynamic: summary
65
67
  - 🔄 **自动重试** 指数退避策略
66
68
 
67
69
  ### 🛡️ 生产级特性
70
+ - 🛡️ **熔断降级** 服务故障时自动切换到 HTTP
71
+ - 🚀 **快速降级** 失败立即降级,最大化成功率
68
72
  - 🔐 **JWT 认证** 安全可靠
69
73
  - 📊 **使用量追踪** Token 统计与成本计算
70
74
  - 🆔 **请求追踪** 唯一 request_id
@@ -87,7 +91,14 @@ pip install tamar-model-client
87
91
 
88
92
  - Python ≥ 3.8
89
93
  - 支持 Windows / Linux / macOS
90
- - 依赖项会自动安装(grpcio, pydantic, python-dotenv 等)
94
+ - 依赖项会自动安装(包括以下核心库):
95
+ - `grpcio>=1.67.1` - gRPC 通信协议
96
+ - `pydantic` - 数据验证和序列化
97
+ - `PyJWT` - JWT 认证
98
+ - `requests>=2.25.0` - HTTP 降级功能(同步)
99
+ - `aiohttp>=3.7.0` - HTTP 降级功能(异步)
100
+ - `openai` - OpenAI 服务商支持
101
+ - `google-genai` - Google AI 服务商支持
91
102
 
92
103
  ## 🏗️ 项目架构
93
104
 
@@ -339,7 +350,7 @@ async def main():
339
350
  )
340
351
 
341
352
  # 发送请求并获取响应
342
- async for r in await client.invoke(model_request):
353
+ async for r in await client.invoke(request_data):
343
354
  if r.error:
344
355
  print(f"错误: {r.error}")
345
356
  else:
@@ -587,6 +598,62 @@ metrics = client.get_resilient_metrics()
587
598
  # }
588
599
  ```
589
600
 
601
+ ### 🚀 快速降级功能(用户体验优化)
602
+
603
+ 在传统的熔断降级基础上,SDK 新增了快速降级功能,进一步提升用户体验:
604
+
605
+ #### 传统降级 vs 快速降级
606
+
607
+ **传统模式**:
608
+ ```
609
+ gRPC请求 → 失败 → 重试1 → 失败 → 重试2 → 失败 → ... → 重试N → 失败 → HTTP降级
610
+ 耗时:(重试次数 × 退避时间) + 降级时间 // 可能需要十几秒
611
+ ```
612
+
613
+ **快速降级模式**:
614
+ ```
615
+ gRPC请求 → 失败 → 立即HTTP降级 (或重试1次后降级)
616
+ 耗时:降级时间 // 通常1-2秒内完成
617
+ ```
618
+
619
+ #### 降级策略配置
620
+
621
+ - **立即降级错误**:`UNAVAILABLE`, `DEADLINE_EXCEEDED`, `CANCELLED` (网络问题)
622
+ - **延迟降级错误**:其他错误重试指定次数后降级
623
+ - **永不降级错误**:`UNAUTHENTICATED`, `PERMISSION_DENIED` (客户端问题)
624
+
625
+ #### 使用示例
626
+
627
+ ```python
628
+ from tamar_model_client import TamarModelClient
629
+
630
+ # 启用快速降级(通过环境变量)
631
+ # MODEL_CLIENT_FAST_FALLBACK_ENABLED=true
632
+ # MODEL_CLIENT_FALLBACK_AFTER_RETRIES=1
633
+
634
+ client = TamarModelClient()
635
+
636
+ # 正常使用,快速降级对用户透明
637
+ response = client.invoke(request)
638
+ # 如果gRPC不可用,会在1-2秒内自动切换到HTTP并返回结果
639
+ ```
640
+
641
+ #### 配置选项详解
642
+
643
+ ```bash
644
+ # 启用快速降级(默认开启)
645
+ MODEL_CLIENT_FAST_FALLBACK_ENABLED=true
646
+
647
+ # 非立即降级的错误,重试多少次后降级(默认1次)
648
+ MODEL_CLIENT_FALLBACK_AFTER_RETRIES=1
649
+
650
+ # 网络错误立即降级(默认配置)
651
+ MODEL_CLIENT_IMMEDIATE_FALLBACK_ERRORS=UNAVAILABLE,DEADLINE_EXCEEDED,CANCELLED
652
+
653
+ # 认证错误永不降级(避免无效降级)
654
+ MODEL_CLIENT_NEVER_FALLBACK_ERRORS=UNAUTHENTICATED,PERMISSION_DENIED,INVALID_ARGUMENT
655
+ ```
656
+
590
657
  ### ⚠️ 注意事项
591
658
 
592
659
  1. **参数说明**
@@ -614,6 +681,11 @@ export MODEL_MANAGER_SERVER_GRPC_USE_TLS="false"
614
681
  export MODEL_MANAGER_SERVER_GRPC_DEFAULT_AUTHORITY="localhost"
615
682
  export MODEL_MANAGER_SERVER_GRPC_MAX_RETRIES="5"
616
683
  export MODEL_MANAGER_SERVER_GRPC_RETRY_DELAY="1.5"
684
+
685
+ # 快速降级配置(可选,优化用户体验)
686
+ export MODEL_CLIENT_FAST_FALLBACK_ENABLED="true"
687
+ export MODEL_CLIENT_HTTP_FALLBACK_URL="http://localhost:8080"
688
+ export MODEL_CLIENT_FALLBACK_AFTER_RETRIES="1"
617
689
  ```
618
690
 
619
691
  或者本地 `.env` 文件
@@ -667,6 +739,27 @@ MODEL_CLIENT_CIRCUIT_BREAKER_THRESHOLD=5
667
739
 
668
740
  # 熔断器恢复超时(秒,熔断后多久尝试恢复,默认 60)
669
741
  MODEL_CLIENT_CIRCUIT_BREAKER_TIMEOUT=60
742
+
743
+
744
+ # ========================
745
+ # 🚀 快速降级配置(可选,优化体验)
746
+ # ========================
747
+
748
+ # 是否启用快速降级功能(默认 true)
749
+ # 启用后,gRPC 请求失败时会立即尝试 HTTP 降级,而不是等待所有重试完成
750
+ MODEL_CLIENT_FAST_FALLBACK_ENABLED=true
751
+
752
+ # 降级前的最大 gRPC 重试次数(默认 1)
753
+ # 对于非立即降级的错误,重试指定次数后才尝试降级
754
+ MODEL_CLIENT_FALLBACK_AFTER_RETRIES=1
755
+
756
+ # 立即降级的错误类型(逗号分隔,默认网络相关错误)
757
+ # 这些错误类型会在第一次失败后立即尝试降级
758
+ MODEL_CLIENT_IMMEDIATE_FALLBACK_ERRORS=UNAVAILABLE,DEADLINE_EXCEEDED,CANCELLED
759
+
760
+ # 永不降级的错误类型(逗号分隔,默认认证相关错误)
761
+ # 这些错误类型不会触发降级,通常是客户端问题而非服务不可用
762
+ MODEL_CLIENT_NEVER_FALLBACK_ERRORS=UNAUTHENTICATED,PERMISSION_DENIED,INVALID_ARGUMENT
670
763
  ```
671
764
 
672
765
  加载后,初始化时无需传参:
@@ -1,21 +1,21 @@
1
1
  tamar_model_client/__init__.py,sha256=4DEIUGlLTeiaECjJQbGYik7C0JO6hHwwfbLYpYpMdzg,444
2
- tamar_model_client/async_client.py,sha256=FYZdo7ltypC4IEq2eUevcxxjTqoKXjZaCv_jpKle7tA,42788
2
+ tamar_model_client/async_client.py,sha256=x1hFOpwrRS2bhLKDct-wO4bdrkfovwvCMYyJ_6XlDvU,44655
3
3
  tamar_model_client/auth.py,sha256=gbwW5Aakeb49PMbmYvrYlVx1mfyn1LEDJ4qQVs-9DA4,438
4
- tamar_model_client/circuit_breaker.py,sha256=0XHJXBYA4O8vwsDGwqNrae9zxNJphY5Rfucc9ytVFGA,5419
5
- tamar_model_client/error_handler.py,sha256=oI_jUTjnq4OXu8fwJoGXNmQpddEgOFF9ZUhbytq7H6c,12384
4
+ tamar_model_client/circuit_breaker.py,sha256=Y3AVp7WzVYU-ubcmovKsJ8DRJbbO4G7vdZgSjnwcWJQ,5550
5
+ tamar_model_client/error_handler.py,sha256=iEgaJOCoQJ4riVSi9ehLl7514jjbfBI9QDd-OTTXpnc,18091
6
6
  tamar_model_client/exceptions.py,sha256=EOr4JMYI7hVszRvNYJ1JqsUNpVmd16T2KpJ0MkFTsUE,13073
7
7
  tamar_model_client/json_formatter.py,sha256=IyBv_pEEzjF-KaMF-7rxRpNc_fxRYK2A-pu_2n4Liow,1990
8
8
  tamar_model_client/logging_icons.py,sha256=MRTZ1Xvkep9ce_jdltj54_XZUXvIpQ95soRNmLdJ4qw,1837
9
- tamar_model_client/sync_client.py,sha256=BRra6GyTwVA4Sm8tjYnwkJg-iJZ_y1fbXuk0-EsJvGo,44396
9
+ tamar_model_client/sync_client.py,sha256=NcruPoLVmrIiyOy8hExqt3uZRE5UvBWDqmaCgl2J3jc,51497
10
10
  tamar_model_client/utils.py,sha256=Kn6pFz9GEC96H4eejEax66AkzvsrXI3WCSDtgDjnVTI,5238
11
- tamar_model_client/core/__init__.py,sha256=rHwVOs4h4eHKy6FCgIv9PJKYKUZHyPjPkdYbbxraLNc,938
12
- tamar_model_client/core/base_client.py,sha256=nSQTvW8oz4wLpBKArgiNjuzpEyv0X5jALwrNmkcUzTw,9267
13
- tamar_model_client/core/http_fallback.py,sha256=1OuSMxzhDyxy07JZa5artMTNdPNMyAhI7By3RUCSPDw,9872
14
- tamar_model_client/core/logging_setup.py,sha256=h1aky1uslIQnx4NxMqjoDMxwlc4Vg46KYTjW9yPu2xQ,6032
11
+ tamar_model_client/core/__init__.py,sha256=RMiZjV1S4csWPLxB_JfdOea8fYPz97Oj3humQSBw1OI,1054
12
+ tamar_model_client/core/base_client.py,sha256=0oEhmxz_Y60c04XFziLv70PLDijLWYAeRVSg1oldYjI,12992
13
+ tamar_model_client/core/http_fallback.py,sha256=_3Cd0ziv-w2BeWhZPlrtzVRD90WaggB0Fg_Jaup1F9E,19058
14
+ tamar_model_client/core/logging_setup.py,sha256=-MXzTR4Ax50H16cbq1jCXbxgayf5fZ0U3o0--fMmxD8,6692
15
15
  tamar_model_client/core/request_builder.py,sha256=yi8iy2Ps2m4d1YwIFiQLRxTvxQxgEGV576aXnNYRl7E,8507
16
16
  tamar_model_client/core/request_id_manager.py,sha256=S-Mliaby9zN_bx-B85FvVnttal-w0skkjy2ZvWoQ5vw,3689
17
17
  tamar_model_client/core/response_handler.py,sha256=_q5galAT0_RaUT5C_yZsjg-9VnT9CBjmIASOt28BUmQ,4616
18
- tamar_model_client/core/utils.py,sha256=8jSx8UOE6ukbiIgruCX7SXN8J5FyuGbqENOmJDsxaSM,5084
18
+ tamar_model_client/core/utils.py,sha256=AcbsGfNQEaZLYI4OZJs-BdmJgxAoLUC5LFoiYmji820,5875
19
19
  tamar_model_client/enums/__init__.py,sha256=3cYYn8ztNGBa_pI_5JGRVYf2QX8fkBVWdjID1PLvoBQ,182
20
20
  tamar_model_client/enums/channel.py,sha256=wCzX579nNpTtwzGeS6S3Ls0UzVAgsOlfy4fXMzQTCAw,199
21
21
  tamar_model_client/enums/invoke.py,sha256=Up87myAg4-0SDJV5a82ggPDpYHSLEtIco8BF_5Ph1nY,322
@@ -28,10 +28,10 @@ tamar_model_client/schemas/inputs.py,sha256=dz1m8NbUIxA99JXZc8WlyzbKpDuz1lEzx3Vg
28
28
  tamar_model_client/schemas/outputs.py,sha256=M_fcqUtXPJnfiLabHlyA8BorlC5pYkf5KLjXO1ysKIQ,1031
29
29
  tests/__init__.py,sha256=kbmImddLDwdqlkkmkyKtl4bQy_ipe-R8eskpaBylU9w,38
30
30
  tests/stream_hanging_analysis.py,sha256=W3W48IhQbNAR6-xvMpoWZvnWOnr56CTaH4-aORNBuD4,14807
31
- tests/test_google_azure_final.py,sha256=NozBjNvbPm5vRw_GdEGMcdB4L-xtuMI3VQHObaccVr8,26425
31
+ tests/test_google_azure_final.py,sha256=YRBn1JH1fMJMOQHk6a04NYR9fybboOhqR4urU7vnShI,26330
32
32
  tests/test_logging_issue.py,sha256=JTMbotfHpAEPMBj73pOwxPn-Zn4QVQJX6scMz48FRDQ,2427
33
33
  tests/test_simple.py,sha256=Xf0U-J9_xn_LzUsmYu06suK0_7DrPeko8OHoHldsNxE,7169
34
- tamar_model_client-0.1.27.dist-info/METADATA,sha256=YsBltIhH5QAfn43-DpMOQm4KnsWpUtdX6Jbg0UU1NVM,23453
35
- tamar_model_client-0.1.27.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
36
- tamar_model_client-0.1.27.dist-info/top_level.txt,sha256=f1I-S8iWN-cgv4gB8gxRg9jJOTJMumvm4oGKVPfGg6A,25
37
- tamar_model_client-0.1.27.dist-info/RECORD,,
34
+ tamar_model_client-0.1.28.dist-info/METADATA,sha256=wGQvtURWcFMoreHt52qQhjgCPjIgUruUuWaMZd4-B6A,26880
35
+ tamar_model_client-0.1.28.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
36
+ tamar_model_client-0.1.28.dist-info/top_level.txt,sha256=f1I-S8iWN-cgv4gB8gxRg9jJOTJMumvm4oGKVPfGg6A,25
37
+ tamar_model_client-0.1.28.dist-info/RECORD,,
@@ -26,8 +26,8 @@ test_logger.addHandler(test_handler)
26
26
 
27
27
  logger = test_logger
28
28
 
29
- os.environ['MODEL_MANAGER_SERVER_GRPC_USE_TLS'] = "true"
30
- os.environ['MODEL_MANAGER_SERVER_ADDRESS'] = "model-manager-server-grpc-131786869360.asia-northeast1.run.app"
29
+ os.environ['MODEL_MANAGER_SERVER_GRPC_USE_TLS'] = "false"
30
+ os.environ['MODEL_MANAGER_SERVER_ADDRESS'] = "localhost:50051"
31
31
  os.environ['MODEL_MANAGER_SERVER_JWT_SECRET_KEY'] = "model-manager-server-jwt-key"
32
32
 
33
33
  # 导入客户端模块
@@ -630,25 +630,25 @@ async def main():
630
630
 
631
631
  try:
632
632
  # # 同步测试
633
- # test_google_ai_studio()
634
- # test_google_vertex_ai()
635
- # test_azure_openai()
636
- #
637
- # # 同步批量测试
638
- # test_sync_batch_requests()
639
- #
640
- # # 异步流式测试
641
- # await asyncio.wait_for(test_google_streaming(), timeout=60.0)
642
- # await asyncio.wait_for(test_azure_streaming(), timeout=60.0)
643
- #
644
- # # 异步批量测试
645
- # await asyncio.wait_for(test_batch_requests(), timeout=120.0)
633
+ test_google_ai_studio()
634
+ test_google_vertex_ai()
635
+ test_azure_openai()
636
+
637
+ # 同步批量测试
638
+ test_sync_batch_requests()
639
+
640
+ # 异步流式测试
641
+ await asyncio.wait_for(test_google_streaming(), timeout=60.0)
642
+ await asyncio.wait_for(test_azure_streaming(), timeout=60.0)
643
+
644
+ # 异步批量测试
645
+ await asyncio.wait_for(test_batch_requests(), timeout=120.0)
646
646
 
647
647
  # 同步并发测试
648
- test_concurrent_requests(25) # 测试150个并发请求
648
+ test_concurrent_requests(2) # 测试150个并发请求
649
649
 
650
650
  # 异步并发测试
651
- await test_async_concurrent_requests(25) # 测试150个异步并发请求
651
+ await test_async_concurrent_requests(2) # 测试150个异步并发请求
652
652
 
653
653
  print("\n✅ 测试完成")
654
654