处理单个上游 JSON 对象,提取 Gemini chunk。 返回 (chunk, auth_error_msg, is_quota_error)。
(obj: Dict[str, Any])
| 461 | |
| 462 | |
| 463 | def _process_object(obj: Dict[str, Any]) -> Tuple[Optional[Dict[str, Any]], Optional[str], bool]: |
| 464 | """ |
| 465 | 处理单个上游 JSON 对象,提取 Gemini chunk。 |
| 466 | 返回 (chunk, auth_error_msg, is_quota_error)。 |
| 467 | """ |
| 468 | results = obj.get("results", []) |
| 469 | if not isinstance(results, list): |
| 470 | return None, None, False |
| 471 | |
| 472 | for result in results: |
| 473 | if not isinstance(result, dict): |
| 474 | continue |
| 475 | |
| 476 | # 检查 errors 字段 |
| 477 | errors = result.get("errors", []) |
| 478 | if errors and isinstance(errors, list): |
| 479 | first = errors[0] |
| 480 | err_msg = first.get("message", "") if isinstance(first, dict) else str(first) |
| 481 | if _is_auth_error(err_msg): |
| 482 | return None, err_msg, False |
| 483 | if _is_quota_error(err_msg): |
| 484 | log.warning(f"[VERTEX] upstream quota/429 error: {err_msg}") |
| 485 | return None, None, True |
| 486 | log.warning(f"[VERTEX] upstream errors in result: {err_msg}") |
| 487 | |
| 488 | data = result.get("data") |
| 489 | if not isinstance(data, dict): |
| 490 | continue |
| 491 | |
| 492 | # unwrap data.ui.streamGenerateContentAnonymous |
| 493 | ui = data.get("ui") |
| 494 | if isinstance(ui, dict) and "streamGenerateContentAnonymous" in ui: |
| 495 | inner = ui["streamGenerateContentAnonymous"] |
| 496 | if isinstance(inner, dict): |
| 497 | data = inner |
| 498 | elif isinstance(inner, list): |
| 499 | for item in inner: |
| 500 | if isinstance(item, dict): |
| 501 | chunk = _extract_chunk(item) |
| 502 | if chunk: |
| 503 | return chunk, None, False |
| 504 | continue |
| 505 | |
| 506 | chunk = _extract_chunk(data) |
| 507 | if chunk: |
| 508 | return chunk, None, False |
| 509 | |
| 510 | return None, None, False |
| 511 | |
| 512 | |
| 513 | def _clean_part(part: Dict[str, Any]) -> Optional[Dict[str, Any]]: |
no test coverage detected