Content-Length: 575374 | pFad | https://github.com/googleapis/python-aiplatform/commit/3090812b1e2d189acf532506c7a654a698bd192c

F2 fix: GenAI - Fixed from_dict methods · googleapis/python-aiplatform@3090812 · GitHub
Skip to content

Commit 3090812

Browse files
Ark-kuncopybara-github
authored andcommitted
fix: GenAI - Fixed from_dict methods
The parsing of dictionaries was standardized and improved. Parsing dictionaries via `json_formt.ParseDict` allows automatically handling renamed fields like `type_`, `format_`, `enum_` and also camelCase keys like `minItems` that are often used in Json Schema schemas. The `json_formt.ParseDict` method succeeds in such cases while the Proto Message constructors fail. However there is an issue with enums which makes full migration to `json_schema.ParseDict` non-trivial. Protobuf's ParseDict treats enum names as case sensitive. This is mostly problematic for Shema messages where Python protos use uppercase enum names like `"OBJECT"` while Json Schemas usually use lowercase types like `"object"`. I've created a fix for the protobuf library, but it will take a while before it's released everywhere. So, enums need to be fixed. But such enums can happen in multiple places in a deeply nested dictionary structure. We need to carefully fix all enum casing issues in nested dicts before we can use `ParseDict`. PiperOrigin-RevId: 680480143
1 parent 29dec74 commit 3090812

File tree

1 file changed

+56
-21
lines changed

1 file changed

+56
-21
lines changed

vertexai/generative_models/_generative_models.py

Lines changed: 56 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
Literal,
3333
Optional,
3434
Sequence,
35+
Type,
36+
TypeVar,
3537
Union,
3638
overload,
3739
TYPE_CHECKING,
@@ -66,6 +68,10 @@
6668
except ImportError:
6769
PIL_Image = None
6870

71+
72+
T = TypeVar("T")
73+
74+
6975
# Re-exporting some GAPIC types
7076

7177
# GAPIC types used in request
@@ -1627,8 +1633,9 @@ def __init__(
16271633
if response_schema is None:
16281634
raw_schema = None
16291635
else:
1630-
gapic_schema_dict = _convert_schema_dict_to_gapic(response_schema)
1631-
raw_schema = aiplatform_types.Schema(gapic_schema_dict)
1636+
raw_schema = FunctionDeclaration(
1637+
name="tmp", parameters=response_schema
1638+
)._raw_function_declaration.parameters
16321639
self._raw_generation_config = gapic_content_types.GenerationConfig(
16331640
temperature=temperature,
16341641
top_p=top_p,
@@ -1660,8 +1667,12 @@ def _from_gapic(
16601667

16611668
@classmethod
16621669
def from_dict(cls, generation_config_dict: Dict[str, Any]) -> "GenerationConfig":
1663-
raw_generation_config = gapic_content_types.GenerationConfig(
1664-
generation_config_dict
1670+
generation_config_dict = copy.deepcopy(generation_config_dict)
1671+
response_schema = generation_config_dict.get("response_schema")
1672+
if response_schema:
1673+
_fix_schema_dict_for_gapic_in_place(response_schema)
1674+
raw_generation_config = _dict_to_proto(
1675+
gapic_content_types.GenerationConfig, generation_config_dict
16651676
)
16661677
return cls._from_gapic(raw_generation_config=raw_generation_config)
16671678

@@ -1872,12 +1883,11 @@ def _from_gapic(
18721883
@classmethod
18731884
def from_dict(cls, tool_dict: Dict[str, Any]) -> "Tool":
18741885
tool_dict = copy.deepcopy(tool_dict)
1875-
function_declarations = tool_dict["function_declarations"]
1876-
for function_declaration in function_declarations:
1877-
function_declaration["parameters"] = _convert_schema_dict_to_gapic(
1878-
function_declaration["parameters"]
1879-
)
1880-
raw_tool = gapic_tool_types.Tool(tool_dict)
1886+
for function_declaration in tool_dict.get("function_declarations") or []:
1887+
parameters = function_declaration.get("parameters")
1888+
if parameters:
1889+
_fix_schema_dict_for_gapic_in_place(parameters)
1890+
raw_tool = _dict_to_proto(aiplatform_types.Tool, tool_dict)
18811891
return cls._from_gapic(raw_tool=raw_tool)
18821892

18831893
def to_dict(self) -> Dict[str, Any]:
@@ -2035,8 +2045,9 @@ def __init__(
20352045
description: Description and purpose of the function.
20362046
Model uses it to decide how and whether to call the function.
20372047
"""
2038-
gapic_schema_dict = _convert_schema_dict_to_gapic(parameters)
2039-
raw_schema = aiplatform_types.Schema(gapic_schema_dict)
2048+
parameters = copy.deepcopy(parameters)
2049+
_fix_schema_dict_for_gapic_in_place(parameters)
2050+
raw_schema = _dict_to_proto(aiplatform_types.Schema, parameters)
20402051
self._raw_function_declaration = gapic_tool_types.FunctionDeclaration(
20412052
name=name, description=description, parameters=raw_schema
20422053
)
@@ -2052,6 +2063,7 @@ def __repr__(self) -> str:
20522063
return self._raw_function_declaration.__repr__()
20532064

20542065

2066+
# TODO: Remove this function once Reasoning Engines moves away from it.
20552067
def _convert_schema_dict_to_gapic(schema_dict: Dict[str, Any]) -> Dict[str, Any]:
20562068
"""Converts a JsonSchema to a dict that the GAPIC Schema class accepts."""
20572069
gapic_schema_dict = copy.copy(schema_dict)
@@ -2070,6 +2082,20 @@ def _convert_schema_dict_to_gapic(schema_dict: Dict[str, Any]) -> Dict[str, Any]
20702082
return gapic_schema_dict
20712083

20722084

2085+
def _fix_schema_dict_for_gapic_in_place(schema_dict: Dict[str, Any]) -> None:
2086+
"""Converts a JsonSchema to a dict that the Schema proto class accepts."""
2087+
schema_dict["type"] = schema_dict["type"].upper()
2088+
2089+
items_schema = schema_dict.get("items")
2090+
if items_schema:
2091+
_fix_schema_dict_for_gapic_in_place(items_schema)
2092+
2093+
properties = schema_dict.get("properties")
2094+
if properties:
2095+
for property_schema in properties.values():
2096+
_fix_schema_dict_for_gapic_in_place(property_schema)
2097+
2098+
20732099
class CallableFunctionDeclaration(FunctionDeclaration):
20742100
"""A function declaration plus a function."""
20752101

@@ -2139,8 +2165,9 @@ def _from_gapic(
21392165

21402166
@classmethod
21412167
def from_dict(cls, response_dict: Dict[str, Any]) -> "GenerationResponse":
2142-
raw_response = gapic_prediction_service_types.GenerateContentResponse()
2143-
json_format.ParseDict(response_dict, raw_response._pb)
2168+
raw_response = _dict_to_proto(
2169+
gapic_prediction_service_types.GenerateContentResponse, response_dict
2170+
)
21442171
return cls._from_gapic(raw_response=raw_response)
21452172

21462173
def to_dict(self) -> Dict[str, Any]:
@@ -2209,8 +2236,7 @@ def _from_gapic(cls, raw_candidate: gapic_content_types.Candidate) -> "Candidate
22092236

22102237
@classmethod
22112238
def from_dict(cls, candidate_dict: Dict[str, Any]) -> "Candidate":
2212-
raw_candidate = gapic_content_types.Candidate()
2213-
json_format.ParseDict(candidate_dict, raw_candidate._pb)
2239+
raw_candidate = _dict_to_proto(gapic_content_types.Candidate, candidate_dict)
22142240
return cls._from_gapic(raw_candidate=raw_candidate)
22152241

22162242
def to_dict(self) -> Dict[str, Any]:
@@ -2310,8 +2336,7 @@ def _from_gapic(cls, raw_content: gapic_content_types.Content) -> "Content":
23102336

23112337
@classmethod
23122338
def from_dict(cls, content_dict: Dict[str, Any]) -> "Content":
2313-
raw_content = gapic_content_types.Content()
2314-
json_format.ParseDict(content_dict, raw_content._pb)
2339+
raw_content = _dict_to_proto(gapic_content_types.Content, content_dict)
23152340
return cls._from_gapic(raw_content=raw_content)
23162341

23172342
def to_dict(self) -> Dict[str, Any]:
@@ -2381,8 +2406,7 @@ def _from_gapic(cls, raw_part: gapic_content_types.Part) -> "Part":
23812406

23822407
@classmethod
23832408
def from_dict(cls, part_dict: Dict[str, Any]) -> "Part":
2384-
raw_part = gapic_content_types.Part()
2385-
json_format.ParseDict(part_dict, raw_part._pb)
2409+
raw_part = _dict_to_proto(gapic_content_types.Part, part_dict)
23862410
return cls._from_gapic(raw_part=raw_part)
23872411

23882412
def __repr__(self) -> str:
@@ -2510,7 +2534,9 @@ def _from_gapic(
25102534

25112535
@classmethod
25122536
def from_dict(cls, safety_setting_dict: Dict[str, Any]) -> "SafetySetting":
2513-
raw_safety_setting = gapic_content_types.SafetySetting(safety_setting_dict)
2537+
raw_safety_setting = _dict_to_proto(
2538+
aiplatform_types.SafetySetting, safety_setting_dict
2539+
)
25142540
return cls._from_gapic(raw_safety_setting=raw_safety_setting)
25152541

25162542
def to_dict(self) -> Dict[str, Any]:
@@ -2760,6 +2786,15 @@ def _proto_to_dict(message) -> Dict[str, Any]:
27602786
)
27612787

27622788

2789+
def _dict_to_proto(message_type: Type[T], message_dict: Dict[str, Any]) -> T:
2790+
"""Converts a dictionary to a proto-plus protobuf message."""
2791+
# We cannot just use `message = message_type(message_dict)` because
2792+
# it fails for classes where GAPIC has renamed proto fields.
2793+
message = message_type()
2794+
json_format.ParseDict(message_dict, message._pb)
2795+
return message
2796+
2797+
27632798
def _dict_to_pretty_string(d: dict) -> str:
27642799
"""Format dict as a pretty-printed JSON string."""
27652800
return json.dumps(d, indent=2)

0 commit comments

Comments
 (0)








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: https://github.com/googleapis/python-aiplatform/commit/3090812b1e2d189acf532506c7a654a698bd192c

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy