langchain-google-genai 2.0.11__py3-none-any.whl → 2.1.1__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 langchain-google-genai might be problematic. Click here for more details.
- langchain_google_genai/__init__.py +2 -1
- langchain_google_genai/_common.py +5 -2
- langchain_google_genai/_enums.py +2 -1
- langchain_google_genai/chat_models.py +77 -12
- {langchain_google_genai-2.0.11.dist-info → langchain_google_genai-2.1.1.dist-info}/METADATA +39 -2
- {langchain_google_genai-2.0.11.dist-info → langchain_google_genai-2.1.1.dist-info}/RECORD +8 -8
- {langchain_google_genai-2.0.11.dist-info → langchain_google_genai-2.1.1.dist-info}/LICENSE +0 -0
- {langchain_google_genai-2.0.11.dist-info → langchain_google_genai-2.1.1.dist-info}/WHEEL +0 -0
|
@@ -55,7 +55,7 @@ embeddings.embed_query("hello, world!")
|
|
|
55
55
|
```
|
|
56
56
|
""" # noqa: E501
|
|
57
57
|
|
|
58
|
-
from langchain_google_genai._enums import HarmBlockThreshold, HarmCategory
|
|
58
|
+
from langchain_google_genai._enums import HarmBlockThreshold, HarmCategory, Modality
|
|
59
59
|
from langchain_google_genai.chat_models import ChatGoogleGenerativeAI
|
|
60
60
|
from langchain_google_genai.embeddings import GoogleGenerativeAIEmbeddings
|
|
61
61
|
from langchain_google_genai.genai_aqa import (
|
|
@@ -80,5 +80,6 @@ __all__ = [
|
|
|
80
80
|
"GoogleVectorStore",
|
|
81
81
|
"HarmBlockThreshold",
|
|
82
82
|
"HarmCategory",
|
|
83
|
+
"Modality",
|
|
83
84
|
"DoesNotExistsException",
|
|
84
85
|
]
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
from importlib import metadata
|
|
2
|
-
from typing import Any, Dict, Optional, Tuple, TypedDict
|
|
2
|
+
from typing import Any, Dict, List, Optional, Tuple, TypedDict
|
|
3
3
|
|
|
4
4
|
from google.api_core.gapic_v1.client_info import ClientInfo
|
|
5
5
|
from langchain_core.utils import secret_from_env
|
|
6
6
|
from pydantic import BaseModel, Field, SecretStr
|
|
7
7
|
|
|
8
|
-
from langchain_google_genai._enums import HarmBlockThreshold, HarmCategory
|
|
8
|
+
from langchain_google_genai._enums import HarmBlockThreshold, HarmCategory, Modality
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class GoogleGenerativeAIError(Exception):
|
|
@@ -72,6 +72,9 @@ Supported examples:
|
|
|
72
72
|
"A key-value dictionary representing additional headers for the model call"
|
|
73
73
|
),
|
|
74
74
|
)
|
|
75
|
+
response_modalities: Optional[List[Modality]] = Field(
|
|
76
|
+
default=None, description=("A list of modalities of the response")
|
|
77
|
+
)
|
|
75
78
|
|
|
76
79
|
safety_settings: Optional[Dict[HarmCategory, HarmBlockThreshold]] = None
|
|
77
80
|
"""The default safety settings to use for all generations.
|
langchain_google_genai/_enums.py
CHANGED
|
@@ -2,5 +2,6 @@ import google.ai.generativelanguage_v1beta as genai
|
|
|
2
2
|
|
|
3
3
|
HarmBlockThreshold = genai.SafetySetting.HarmBlockThreshold
|
|
4
4
|
HarmCategory = genai.HarmCategory
|
|
5
|
+
Modality = genai.GenerationConfig.Modality
|
|
5
6
|
|
|
6
|
-
__all__ = ["HarmBlockThreshold", "HarmCategory"]
|
|
7
|
+
__all__ = ["HarmBlockThreshold", "HarmCategory", "Modality"]
|
|
@@ -67,7 +67,7 @@ from langchain_core.messages.ai import UsageMetadata
|
|
|
67
67
|
from langchain_core.messages.tool import invalid_tool_call, tool_call, tool_call_chunk
|
|
68
68
|
from langchain_core.output_parsers.base import OutputParserLike
|
|
69
69
|
from langchain_core.output_parsers.openai_tools import (
|
|
70
|
-
|
|
70
|
+
JsonOutputKeyToolsParser,
|
|
71
71
|
PydanticToolsParser,
|
|
72
72
|
parse_tool_calls,
|
|
73
73
|
)
|
|
@@ -89,7 +89,7 @@ from tenacity import (
|
|
|
89
89
|
stop_after_attempt,
|
|
90
90
|
wait_exponential,
|
|
91
91
|
)
|
|
92
|
-
from typing_extensions import Self
|
|
92
|
+
from typing_extensions import Self, is_typeddict
|
|
93
93
|
|
|
94
94
|
from langchain_google_genai._common import (
|
|
95
95
|
GoogleGenerativeAIError,
|
|
@@ -106,10 +106,16 @@ from langchain_google_genai._function_utils import (
|
|
|
106
106
|
is_basemodel_subclass_safe,
|
|
107
107
|
tool_to_dict,
|
|
108
108
|
)
|
|
109
|
-
from langchain_google_genai._image_utils import
|
|
109
|
+
from langchain_google_genai._image_utils import (
|
|
110
|
+
ImageBytesLoader,
|
|
111
|
+
image_bytes_to_b64_string,
|
|
112
|
+
)
|
|
110
113
|
|
|
111
114
|
from . import _genai_extension as genaix
|
|
112
115
|
|
|
116
|
+
WARNED_STRUCTURED_OUTPUT_JSON_MODE = False
|
|
117
|
+
|
|
118
|
+
|
|
113
119
|
logger = logging.getLogger(__name__)
|
|
114
120
|
|
|
115
121
|
|
|
@@ -427,7 +433,7 @@ def _parse_chat_history(
|
|
|
427
433
|
def _parse_response_candidate(
|
|
428
434
|
response_candidate: Candidate, streaming: bool = False
|
|
429
435
|
) -> AIMessage:
|
|
430
|
-
content: Union[None, str, List[str]] = None
|
|
436
|
+
content: Union[None, str, List[Union[str, dict]]] = None
|
|
431
437
|
additional_kwargs = {}
|
|
432
438
|
tool_calls = []
|
|
433
439
|
invalid_tool_calls = []
|
|
@@ -452,6 +458,26 @@ def _parse_response_candidate(
|
|
|
452
458
|
elif text:
|
|
453
459
|
raise Exception("Unexpected content type")
|
|
454
460
|
|
|
461
|
+
if part.inline_data.mime_type.startswith("image/"):
|
|
462
|
+
image_format = part.inline_data.mime_type[6:]
|
|
463
|
+
message = {
|
|
464
|
+
"type": "image_url",
|
|
465
|
+
"image_url": {
|
|
466
|
+
"url": image_bytes_to_b64_string(
|
|
467
|
+
part.inline_data.data, image_format=image_format
|
|
468
|
+
)
|
|
469
|
+
},
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
if not content:
|
|
473
|
+
content = [message]
|
|
474
|
+
elif isinstance(content, str) and message:
|
|
475
|
+
content = [content, message]
|
|
476
|
+
elif isinstance(content, list) and message:
|
|
477
|
+
content.append(message)
|
|
478
|
+
elif message:
|
|
479
|
+
raise Exception("Unexpected content type")
|
|
480
|
+
|
|
455
481
|
if part.function_call:
|
|
456
482
|
function_call = {"name": part.function_call.name}
|
|
457
483
|
# dump to match other function calling llm for now
|
|
@@ -828,8 +854,8 @@ class ChatGoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseChatModel):
|
|
|
828
854
|
@model_validator(mode="after")
|
|
829
855
|
def validate_environment(self) -> Self:
|
|
830
856
|
"""Validates params and passes them to google-generativeai package."""
|
|
831
|
-
if self.temperature is not None and not 0 <= self.temperature <=
|
|
832
|
-
raise ValueError("temperature must be in the range [0.0,
|
|
857
|
+
if self.temperature is not None and not 0 <= self.temperature <= 2.0:
|
|
858
|
+
raise ValueError("temperature must be in the range [0.0, 2.0]")
|
|
833
859
|
|
|
834
860
|
if self.top_p is not None and not 0 <= self.top_p <= 1:
|
|
835
861
|
raise ValueError("top_p must be in the range [0.0, 1.0]")
|
|
@@ -892,6 +918,7 @@ class ChatGoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseChatModel):
|
|
|
892
918
|
"top_k": self.top_k,
|
|
893
919
|
"n": self.n,
|
|
894
920
|
"safety_settings": self.safety_settings,
|
|
921
|
+
"response_modalities": self.response_modalities,
|
|
895
922
|
}
|
|
896
923
|
|
|
897
924
|
def _get_ls_params(
|
|
@@ -925,6 +952,7 @@ class ChatGoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseChatModel):
|
|
|
925
952
|
"max_output_tokens": self.max_output_tokens,
|
|
926
953
|
"top_k": self.top_k,
|
|
927
954
|
"top_p": self.top_p,
|
|
955
|
+
"response_modalities": self.response_modalities,
|
|
928
956
|
}.items()
|
|
929
957
|
if v is not None
|
|
930
958
|
}
|
|
@@ -1177,6 +1205,16 @@ class ChatGoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseChatModel):
|
|
|
1177
1205
|
elif functions:
|
|
1178
1206
|
formatted_tools = [convert_to_genai_function_declarations(functions)]
|
|
1179
1207
|
|
|
1208
|
+
filtered_messages = []
|
|
1209
|
+
for message in messages:
|
|
1210
|
+
if isinstance(message, HumanMessage) and not message.content:
|
|
1211
|
+
warnings.warn(
|
|
1212
|
+
"HumanMessage with empty content was removed to prevent API error"
|
|
1213
|
+
)
|
|
1214
|
+
else:
|
|
1215
|
+
filtered_messages.append(message)
|
|
1216
|
+
messages = filtered_messages
|
|
1217
|
+
|
|
1180
1218
|
system_instruction, history = _parse_chat_history(
|
|
1181
1219
|
messages,
|
|
1182
1220
|
convert_system_message_to_human=self.convert_system_message_to_human,
|
|
@@ -1243,16 +1281,37 @@ class ChatGoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseChatModel):
|
|
|
1243
1281
|
include_raw: bool = False,
|
|
1244
1282
|
**kwargs: Any,
|
|
1245
1283
|
) -> Runnable[LanguageModelInput, Union[Dict, BaseModel]]:
|
|
1284
|
+
_ = kwargs.pop("method", None)
|
|
1285
|
+
_ = kwargs.pop("strict", None)
|
|
1246
1286
|
if kwargs:
|
|
1247
1287
|
raise ValueError(f"Received unsupported arguments {kwargs}")
|
|
1288
|
+
tool_name = _get_tool_name(schema) # type: ignore[arg-type]
|
|
1248
1289
|
if isinstance(schema, type) and is_basemodel_subclass_safe(schema):
|
|
1249
1290
|
parser: OutputParserLike = PydanticToolsParser(
|
|
1250
1291
|
tools=[schema], first_tool_only=True
|
|
1251
1292
|
)
|
|
1252
1293
|
else:
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1294
|
+
global WARNED_STRUCTURED_OUTPUT_JSON_MODE
|
|
1295
|
+
warnings.warn(
|
|
1296
|
+
"ChatGoogleGenerativeAI.with_structured_output with dict schema has "
|
|
1297
|
+
"changed recently to align with behavior of other LangChain chat "
|
|
1298
|
+
"models. More context: "
|
|
1299
|
+
"https://github.com/langchain-ai/langchain-google/pull/772"
|
|
1300
|
+
)
|
|
1301
|
+
WARNED_STRUCTURED_OUTPUT_JSON_MODE = True
|
|
1302
|
+
parser = JsonOutputKeyToolsParser(key_name=tool_name, first_tool_only=True)
|
|
1303
|
+
tool_choice = tool_name if self._supports_tool_choice else None
|
|
1304
|
+
try:
|
|
1305
|
+
llm = self.bind_tools(
|
|
1306
|
+
[schema],
|
|
1307
|
+
tool_choice=tool_choice,
|
|
1308
|
+
ls_structured_output_format={
|
|
1309
|
+
"kwargs": {"method": "function_calling"},
|
|
1310
|
+
"schema": convert_to_openai_tool(schema),
|
|
1311
|
+
},
|
|
1312
|
+
)
|
|
1313
|
+
except Exception:
|
|
1314
|
+
llm = self.bind_tools([schema], tool_choice=tool_choice)
|
|
1256
1315
|
if include_raw:
|
|
1257
1316
|
parser_with_fallback = RunnablePassthrough.assign(
|
|
1258
1317
|
parsed=itemgetter("raw") | parser, parsing_error=lambda _: None
|
|
@@ -1315,7 +1374,13 @@ class ChatGoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseChatModel):
|
|
|
1315
1374
|
|
|
1316
1375
|
|
|
1317
1376
|
def _get_tool_name(
|
|
1318
|
-
tool: Union[_ToolDict, GoogleTool],
|
|
1377
|
+
tool: Union[_ToolDict, GoogleTool, Dict],
|
|
1319
1378
|
) -> str:
|
|
1320
|
-
|
|
1321
|
-
|
|
1379
|
+
try:
|
|
1380
|
+
genai_tool = tool_to_dict(convert_to_genai_function_declarations([tool]))
|
|
1381
|
+
return [f["name"] for f in genai_tool["function_declarations"]][0] # type: ignore[index]
|
|
1382
|
+
except ValueError as e: # other TypedDict
|
|
1383
|
+
if is_typeddict(tool):
|
|
1384
|
+
return convert_to_openai_tool(cast(Dict, tool))["function"]["name"]
|
|
1385
|
+
else:
|
|
1386
|
+
raise e
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: langchain-google-genai
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.1
|
|
4
4
|
Summary: An integration package connecting Google's genai package and LangChain
|
|
5
5
|
Home-page: https://github.com/langchain-ai/langchain-google
|
|
6
6
|
License: MIT
|
|
@@ -13,7 +13,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.12
|
|
14
14
|
Requires-Dist: filetype (>=1.2.0,<2.0.0)
|
|
15
15
|
Requires-Dist: google-ai-generativelanguage (>=0.6.16,<0.7.0)
|
|
16
|
-
Requires-Dist: langchain-core (>=0.3.
|
|
16
|
+
Requires-Dist: langchain-core (>=0.3.47,<0.4.0)
|
|
17
17
|
Requires-Dist: pydantic (>=2,<3)
|
|
18
18
|
Project-URL: Repository, https://github.com/langchain-ai/langchain-google
|
|
19
19
|
Project-URL: Source Code, https://github.com/langchain-ai/langchain-google/tree/main/libs/genai
|
|
@@ -77,7 +77,44 @@ The value of `image_url` can be any of the following:
|
|
|
77
77
|
- An accessible gcs file (e.g., "gcs://path/to/file.png")
|
|
78
78
|
- A base64 encoded image (e.g., `data:image/png;base64,abcd124`)
|
|
79
79
|
|
|
80
|
+
#### Multimodal outputs
|
|
80
81
|
|
|
82
|
+
Gemini 2.0 Flash Experimental model supports text output with inline images
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
from langchain_google_genai import ChatGoogleGenerativeAI
|
|
86
|
+
|
|
87
|
+
llm = ChatGoogleGenerativeAI(model="models/gemini-2.0-flash-exp-image-generation")
|
|
88
|
+
# example
|
|
89
|
+
response = llm.invoke(
|
|
90
|
+
"Generate an image of a cat and say meow",
|
|
91
|
+
generation_config=dict(response_modalities=["TEXT", "IMAGE"]),
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
# Base64 encoded binary data of the image
|
|
95
|
+
image_base64 = response.content[0].get("image_url").get("url").split(",")[-1]
|
|
96
|
+
meow_str = response.content[1]
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
#### Multimodal Outputs in Chains
|
|
100
|
+
|
|
101
|
+
'''
|
|
102
|
+
from langchain_core.runnables import RunnablePassthrough
|
|
103
|
+
from langchain_core.prompts import ChatPromptTemplate
|
|
104
|
+
|
|
105
|
+
from langchain_google_genai import ChatGoogleGenerativeAI, Modality
|
|
106
|
+
|
|
107
|
+
llm = ChatGoogleGenerativeAI(
|
|
108
|
+
model="models/gemini-2.0-flash-exp-image-generation",
|
|
109
|
+
response_modalities=[Modality.TEXT, Modality.IMAGE],
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
prompt = ChatPromptTemplate(
|
|
113
|
+
[("human", "Generate an image of {animal} and tell me the sound of the animal")]
|
|
114
|
+
)
|
|
115
|
+
chain = {"animal": RunnablePassthrough()} | prompt | llm
|
|
116
|
+
res = chain.invoke("cat")
|
|
117
|
+
'''
|
|
81
118
|
|
|
82
119
|
## Embeddings
|
|
83
120
|
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
langchain_google_genai/__init__.py,sha256=
|
|
2
|
-
langchain_google_genai/_common.py,sha256=
|
|
3
|
-
langchain_google_genai/_enums.py,sha256=
|
|
1
|
+
langchain_google_genai/__init__.py,sha256=IsTvA3UcECLDckt3zWxK6u-n3MEa5KeEQpqsS-Z8shM,2784
|
|
2
|
+
langchain_google_genai/_common.py,sha256=RS_FN1k9BeeSRz8HuPyjh_lfDQPZKY6KdvK5EfVuxDw,5431
|
|
3
|
+
langchain_google_genai/_enums.py,sha256=Zj3BXXLlkm_UybegCi6fLsfFhriJCt_LAJvgatgPWQ0,252
|
|
4
4
|
langchain_google_genai/_function_utils.py,sha256=FPZ4CxI4iTFco_W6oWNCNV_lgNbCLRbj7Gf-D0zeTCY,17736
|
|
5
5
|
langchain_google_genai/_genai_extension.py,sha256=81a4ly5ZHlqMf37uJfdB8K41qE6J5ujLnbUypIfFf2o,20775
|
|
6
6
|
langchain_google_genai/_image_utils.py,sha256=tPrQyMvVmO8xkuow1SvA91omxUEv9ZUy1EMHNGjMAKY,5202
|
|
7
|
-
langchain_google_genai/chat_models.py,sha256=
|
|
7
|
+
langchain_google_genai/chat_models.py,sha256=ZFjhFz3a4t-6CEYGSYujYrTf29QEvKsIHeKZu8nJftI,53404
|
|
8
8
|
langchain_google_genai/embeddings.py,sha256=jQRWPXD9twXoVBlXJQG7Duz0fb8UC0kgRzzwAmW3Dic,10146
|
|
9
9
|
langchain_google_genai/genai_aqa.py,sha256=qB6h3-BSXqe0YLR3eeVllYzmNKK6ofI6xJLdBahUVZo,4300
|
|
10
10
|
langchain_google_genai/google_vector_store.py,sha256=4wvhIiOmc3Fo046FyafPmT9NBCLek-9bgluvuTfrbpQ,16148
|
|
11
11
|
langchain_google_genai/llms.py,sha256=QNPitkORf86w8WQpTbjuPFCQFkB-qKRMW2phhRBwAEA,4318
|
|
12
12
|
langchain_google_genai/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
-
langchain_google_genai-2.
|
|
14
|
-
langchain_google_genai-2.
|
|
15
|
-
langchain_google_genai-2.
|
|
16
|
-
langchain_google_genai-2.
|
|
13
|
+
langchain_google_genai-2.1.1.dist-info/LICENSE,sha256=DppmdYJVSc1jd0aio6ptnMUn5tIHrdAhQ12SclEBfBg,1072
|
|
14
|
+
langchain_google_genai-2.1.1.dist-info/METADATA,sha256=600J_hgujuZPiW-FliQBH9SbAeSw5Bb3tAyZzG2NES8,4728
|
|
15
|
+
langchain_google_genai-2.1.1.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
16
|
+
langchain_google_genai-2.1.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|