langchain-google-genai 2.1.2__tar.gz → 2.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.
Potentially problematic release.
This version of langchain-google-genai might be problematic. Click here for more details.
- {langchain_google_genai-2.1.2 → langchain_google_genai-2.1.3}/PKG-INFO +2 -2
- {langchain_google_genai-2.1.2 → langchain_google_genai-2.1.3}/langchain_google_genai/_common.py +1 -1
- {langchain_google_genai-2.1.2 → langchain_google_genai-2.1.3}/langchain_google_genai/chat_models.py +163 -18
- {langchain_google_genai-2.1.2 → langchain_google_genai-2.1.3}/langchain_google_genai/embeddings.py +14 -8
- {langchain_google_genai-2.1.2 → langchain_google_genai-2.1.3}/langchain_google_genai/llms.py +26 -0
- {langchain_google_genai-2.1.2 → langchain_google_genai-2.1.3}/pyproject.toml +5 -5
- {langchain_google_genai-2.1.2 → langchain_google_genai-2.1.3}/LICENSE +0 -0
- {langchain_google_genai-2.1.2 → langchain_google_genai-2.1.3}/README.md +0 -0
- {langchain_google_genai-2.1.2 → langchain_google_genai-2.1.3}/langchain_google_genai/__init__.py +0 -0
- {langchain_google_genai-2.1.2 → langchain_google_genai-2.1.3}/langchain_google_genai/_enums.py +0 -0
- {langchain_google_genai-2.1.2 → langchain_google_genai-2.1.3}/langchain_google_genai/_function_utils.py +0 -0
- {langchain_google_genai-2.1.2 → langchain_google_genai-2.1.3}/langchain_google_genai/_genai_extension.py +0 -0
- {langchain_google_genai-2.1.2 → langchain_google_genai-2.1.3}/langchain_google_genai/_image_utils.py +0 -0
- {langchain_google_genai-2.1.2 → langchain_google_genai-2.1.3}/langchain_google_genai/genai_aqa.py +0 -0
- {langchain_google_genai-2.1.2 → langchain_google_genai-2.1.3}/langchain_google_genai/google_vector_store.py +0 -0
- {langchain_google_genai-2.1.2 → langchain_google_genai-2.1.3}/langchain_google_genai/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: langchain-google-genai
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.3
|
|
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.52,<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
|
{langchain_google_genai-2.1.2 → langchain_google_genai-2.1.3}/langchain_google_genai/_common.py
RENAMED
|
@@ -36,7 +36,7 @@ Supported examples:
|
|
|
36
36
|
"the GOOGLE_API_KEY envvar"
|
|
37
37
|
temperature: float = 0.7
|
|
38
38
|
"""Run inference with this temperature. Must by in the closed interval
|
|
39
|
-
[0.0,
|
|
39
|
+
[0.0, 2.0]."""
|
|
40
40
|
top_p: Optional[float] = None
|
|
41
41
|
"""Decode using nucleus sampling: consider the smallest set of tokens whose
|
|
42
42
|
probability sum is at least top_p. Must be in the closed interval [0.0, 1.0]."""
|
{langchain_google_genai-2.1.2 → langchain_google_genai-2.1.3}/langchain_google_genai/chat_models.py
RENAMED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
import base64
|
|
4
5
|
import json
|
|
5
6
|
import logging
|
|
7
|
+
import mimetypes
|
|
6
8
|
import uuid
|
|
7
9
|
import warnings
|
|
10
|
+
from difflib import get_close_matches
|
|
8
11
|
from operator import itemgetter
|
|
9
12
|
from typing import (
|
|
10
13
|
Any,
|
|
@@ -22,6 +25,7 @@ from typing import (
|
|
|
22
25
|
cast,
|
|
23
26
|
)
|
|
24
27
|
|
|
28
|
+
import filetype # type: ignore[import]
|
|
25
29
|
import google.api_core
|
|
26
30
|
|
|
27
31
|
# TODO: remove ignore once the google package is published with types
|
|
@@ -61,6 +65,7 @@ from langchain_core.messages import (
|
|
|
61
65
|
HumanMessage,
|
|
62
66
|
SystemMessage,
|
|
63
67
|
ToolMessage,
|
|
68
|
+
is_data_content_block,
|
|
64
69
|
)
|
|
65
70
|
from langchain_core.messages.ai import UsageMetadata
|
|
66
71
|
from langchain_core.messages.tool import invalid_tool_call, tool_call, tool_call_chunk
|
|
@@ -112,9 +117,6 @@ from langchain_google_genai._image_utils import (
|
|
|
112
117
|
|
|
113
118
|
from . import _genai_extension as genaix
|
|
114
119
|
|
|
115
|
-
WARNED_STRUCTURED_OUTPUT_JSON_MODE = False
|
|
116
|
-
|
|
117
|
-
|
|
118
120
|
logger = logging.getLogger(__name__)
|
|
119
121
|
|
|
120
122
|
|
|
@@ -239,7 +241,7 @@ async def _achat_with_retry(generation_method: Callable, **kwargs: Any) -> Any:
|
|
|
239
241
|
return await _achat_with_retry(**kwargs)
|
|
240
242
|
|
|
241
243
|
|
|
242
|
-
def
|
|
244
|
+
def _is_lc_content_block(part: dict) -> bool:
|
|
243
245
|
return "type" in part
|
|
244
246
|
|
|
245
247
|
|
|
@@ -254,10 +256,29 @@ def _convert_to_parts(
|
|
|
254
256
|
if isinstance(part, str):
|
|
255
257
|
parts.append(Part(text=part))
|
|
256
258
|
elif isinstance(part, Mapping):
|
|
257
|
-
|
|
258
|
-
if _is_openai_parts_format(part):
|
|
259
|
+
if _is_lc_content_block(part):
|
|
259
260
|
if part["type"] == "text":
|
|
260
261
|
parts.append(Part(text=part["text"]))
|
|
262
|
+
elif is_data_content_block(part):
|
|
263
|
+
if part["source_type"] == "url":
|
|
264
|
+
bytes_ = image_loader._bytes_from_url(part["url"])
|
|
265
|
+
elif part["source_type"] == "base64":
|
|
266
|
+
bytes_ = base64.b64decode(part["data"])
|
|
267
|
+
else:
|
|
268
|
+
raise ValueError("source_type must be url or base64.")
|
|
269
|
+
inline_data: dict = {"data": bytes_}
|
|
270
|
+
if "mime_type" in part:
|
|
271
|
+
inline_data["mime_type"] = part["mime_type"]
|
|
272
|
+
else:
|
|
273
|
+
source = cast(str, part.get("url") or part.get("data"))
|
|
274
|
+
mime_type, _ = mimetypes.guess_type(source)
|
|
275
|
+
if not mime_type:
|
|
276
|
+
kind = filetype.guess(bytes_)
|
|
277
|
+
if kind:
|
|
278
|
+
mime_type = kind.mime
|
|
279
|
+
if mime_type:
|
|
280
|
+
inline_data["mime_type"] = mime_type
|
|
281
|
+
parts.append(Part(inline_data=inline_data))
|
|
261
282
|
elif part["type"] == "image_url":
|
|
262
283
|
img_url = part["image_url"]
|
|
263
284
|
if isinstance(img_url, dict):
|
|
@@ -709,7 +730,7 @@ class ChatGoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseChatModel):
|
|
|
709
730
|
.. code-block:: python
|
|
710
731
|
|
|
711
732
|
AIMessageChunk(content='J', response_metadata={'finish_reason': 'STOP', 'safety_ratings': []}, id='run-e905f4f4-58cb-4a10-a960-448a2bb649e3', usage_metadata={'input_tokens': 18, 'output_tokens': 1, 'total_tokens': 19})
|
|
712
|
-
AIMessageChunk(content="'adore programmer.
|
|
733
|
+
AIMessageChunk(content="'adore programmer. \\n", response_metadata={'finish_reason': 'STOP', 'safety_ratings': [{'category': 'HARM_CATEGORY_SEXUALLY_EXPLICIT', 'probability': 'NEGLIGIBLE', 'blocked': False}, {'category': 'HARM_CATEGORY_HATE_SPEECH', 'probability': 'NEGLIGIBLE', 'blocked': False}, {'category': 'HARM_CATEGORY_HARASSMENT', 'probability': 'NEGLIGIBLE', 'blocked': False}, {'category': 'HARM_CATEGORY_DANGEROUS_CONTENT', 'probability': 'NEGLIGIBLE', 'blocked': False}]}, id='run-e905f4f4-58cb-4a10-a960-448a2bb649e3', usage_metadata={'input_tokens': 18, 'output_tokens': 5, 'total_tokens': 23})
|
|
713
734
|
|
|
714
735
|
.. code-block:: python
|
|
715
736
|
|
|
@@ -739,6 +760,109 @@ class ChatGoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseChatModel):
|
|
|
739
760
|
# batch:
|
|
740
761
|
# await llm.abatch([messages])
|
|
741
762
|
|
|
763
|
+
Context Caching:
|
|
764
|
+
Context caching allows you to store and reuse content (e.g., PDFs, images) for faster processing.
|
|
765
|
+
The `cached_content` parameter accepts a cache name created via the Google Generative AI API.
|
|
766
|
+
Below are two examples: caching a single file directly and caching multiple files using `Part`.
|
|
767
|
+
|
|
768
|
+
Single File Example:
|
|
769
|
+
This caches a single file and queries it.
|
|
770
|
+
|
|
771
|
+
.. code-block:: python
|
|
772
|
+
|
|
773
|
+
from google import genai
|
|
774
|
+
from google.genai import types
|
|
775
|
+
import time
|
|
776
|
+
from langchain_google_genai import ChatGoogleGenerativeAI
|
|
777
|
+
from langchain_core.messages import HumanMessage
|
|
778
|
+
|
|
779
|
+
client = genai.Client()
|
|
780
|
+
|
|
781
|
+
# Upload file
|
|
782
|
+
file = client.files.upload(file="./example_file")
|
|
783
|
+
while file.state.name == 'PROCESSING':
|
|
784
|
+
time.sleep(2)
|
|
785
|
+
file = client.files.get(name=file.name)
|
|
786
|
+
|
|
787
|
+
# Create cache
|
|
788
|
+
model = 'models/gemini-1.5-flash-001'
|
|
789
|
+
cache = client.caches.create(
|
|
790
|
+
model=model,
|
|
791
|
+
config=types.CreateCachedContentConfig(
|
|
792
|
+
display_name='Cached Content',
|
|
793
|
+
system_instruction=(
|
|
794
|
+
'You are an expert content analyzer, and your job is to answer '
|
|
795
|
+
'the user\'s query based on the file you have access to.'
|
|
796
|
+
),
|
|
797
|
+
contents=[file],
|
|
798
|
+
ttl="300s",
|
|
799
|
+
)
|
|
800
|
+
)
|
|
801
|
+
|
|
802
|
+
# Query with LangChain
|
|
803
|
+
llm = ChatGoogleGenerativeAI(
|
|
804
|
+
model=model,
|
|
805
|
+
cached_content=cache.name,
|
|
806
|
+
)
|
|
807
|
+
message = HumanMessage(content="Summarize the main points of the content.")
|
|
808
|
+
llm.invoke([message])
|
|
809
|
+
|
|
810
|
+
Multiple Files Example:
|
|
811
|
+
This caches two files using `Part` and queries them together.
|
|
812
|
+
|
|
813
|
+
.. code-block:: python
|
|
814
|
+
|
|
815
|
+
from google import genai
|
|
816
|
+
from google.genai.types import CreateCachedContentConfig, Content, Part
|
|
817
|
+
import time
|
|
818
|
+
from langchain_google_genai import ChatGoogleGenerativeAI
|
|
819
|
+
from langchain_core.messages import HumanMessage
|
|
820
|
+
|
|
821
|
+
client = genai.Client()
|
|
822
|
+
|
|
823
|
+
# Upload files
|
|
824
|
+
file_1 = client.files.upload(file="./file1")
|
|
825
|
+
while file_1.state.name == 'PROCESSING':
|
|
826
|
+
time.sleep(2)
|
|
827
|
+
file_1 = client.files.get(name=file_1.name)
|
|
828
|
+
|
|
829
|
+
file_2 = client.files.upload(file="./file2")
|
|
830
|
+
while file_2.state.name == 'PROCESSING':
|
|
831
|
+
time.sleep(2)
|
|
832
|
+
file_2 = client.files.get(name=file_2.name)
|
|
833
|
+
|
|
834
|
+
# Create cache with multiple files
|
|
835
|
+
contents = [
|
|
836
|
+
Content(
|
|
837
|
+
role="user",
|
|
838
|
+
parts=[
|
|
839
|
+
Part.from_uri(file_uri=file_1.uri, mime_type=file_1.mime_type),
|
|
840
|
+
Part.from_uri(file_uri=file_2.uri, mime_type=file_2.mime_type),
|
|
841
|
+
],
|
|
842
|
+
)
|
|
843
|
+
]
|
|
844
|
+
model = "gemini-1.5-flash-001"
|
|
845
|
+
cache = client.caches.create(
|
|
846
|
+
model=model,
|
|
847
|
+
config=CreateCachedContentConfig(
|
|
848
|
+
display_name='Cached Contents',
|
|
849
|
+
system_instruction=(
|
|
850
|
+
'You are an expert content analyzer, and your job is to answer '
|
|
851
|
+
'the user\'s query based on the files you have access to.'
|
|
852
|
+
),
|
|
853
|
+
contents=contents,
|
|
854
|
+
ttl="300s",
|
|
855
|
+
)
|
|
856
|
+
)
|
|
857
|
+
|
|
858
|
+
# Query with LangChain
|
|
859
|
+
llm = ChatGoogleGenerativeAI(
|
|
860
|
+
model=model,
|
|
861
|
+
cached_content=cache.name,
|
|
862
|
+
)
|
|
863
|
+
message = HumanMessage(content="Provide a summary of the key information across both files.")
|
|
864
|
+
llm.invoke([message])
|
|
865
|
+
|
|
742
866
|
Tool calling:
|
|
743
867
|
.. code-block:: python
|
|
744
868
|
|
|
@@ -842,7 +966,7 @@ class ChatGoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseChatModel):
|
|
|
842
966
|
|
|
843
967
|
.. code-block:: python
|
|
844
968
|
|
|
845
|
-
'The weather in this image appears to be sunny and pleasant. The sky is a bright blue with scattered white clouds, suggesting fair weather. The lush green grass and trees indicate a warm and possibly slightly breezy day. There are no signs of rain or storms.
|
|
969
|
+
'The weather in this image appears to be sunny and pleasant. The sky is a bright blue with scattered white clouds, suggesting fair weather. The lush green grass and trees indicate a warm and possibly slightly breezy day. There are no signs of rain or storms.'
|
|
846
970
|
|
|
847
971
|
Token usage:
|
|
848
972
|
.. code-block:: python
|
|
@@ -891,6 +1015,28 @@ class ChatGoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseChatModel):
|
|
|
891
1015
|
``cachedContents/{cachedContent}``.
|
|
892
1016
|
"""
|
|
893
1017
|
|
|
1018
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
1019
|
+
"""Needed for arg validation."""
|
|
1020
|
+
# Get all valid field names, including aliases
|
|
1021
|
+
valid_fields = set()
|
|
1022
|
+
for field_name, field_info in self.model_fields.items():
|
|
1023
|
+
valid_fields.add(field_name)
|
|
1024
|
+
if hasattr(field_info, "alias") and field_info.alias is not None:
|
|
1025
|
+
valid_fields.add(field_info.alias)
|
|
1026
|
+
|
|
1027
|
+
# Check for unrecognized arguments
|
|
1028
|
+
for arg in kwargs:
|
|
1029
|
+
if arg not in valid_fields:
|
|
1030
|
+
suggestions = get_close_matches(arg, valid_fields, n=1)
|
|
1031
|
+
suggestion = (
|
|
1032
|
+
f" Did you mean: '{suggestions[0]}'?" if suggestions else ""
|
|
1033
|
+
)
|
|
1034
|
+
logger.warning(
|
|
1035
|
+
f"Unexpected argument '{arg}' "
|
|
1036
|
+
f"provided to ChatGoogleGenerativeAI.{suggestion}"
|
|
1037
|
+
)
|
|
1038
|
+
super().__init__(**kwargs)
|
|
1039
|
+
|
|
894
1040
|
model_config = ConfigDict(
|
|
895
1041
|
populate_by_name=True,
|
|
896
1042
|
)
|
|
@@ -927,7 +1073,9 @@ class ChatGoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseChatModel):
|
|
|
927
1073
|
if self.top_k is not None and self.top_k <= 0:
|
|
928
1074
|
raise ValueError("top_k must be positive")
|
|
929
1075
|
|
|
930
|
-
if not
|
|
1076
|
+
if not any(
|
|
1077
|
+
self.model.startswith(prefix) for prefix in ("models/", "tunedModels/")
|
|
1078
|
+
):
|
|
931
1079
|
self.model = f"models/{self.model}"
|
|
932
1080
|
|
|
933
1081
|
additional_headers = self.additional_headers or {}
|
|
@@ -964,12 +1112,17 @@ class ChatGoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseChatModel):
|
|
|
964
1112
|
# this check ensures that async client is only initialized
|
|
965
1113
|
# within an asyncio event loop to avoid the error
|
|
966
1114
|
if not self.async_client_running and _is_event_loop_running():
|
|
1115
|
+
# async clients don't support "rest" transport
|
|
1116
|
+
# https://github.com/googleapis/gapic-generator-python/issues/1962
|
|
1117
|
+
transport = self.transport
|
|
1118
|
+
if transport == "rest":
|
|
1119
|
+
transport = "grpc_asyncio"
|
|
967
1120
|
self.async_client_running = genaix.build_generative_async_service(
|
|
968
1121
|
credentials=self.credentials,
|
|
969
1122
|
api_key=google_api_key,
|
|
970
1123
|
client_info=get_client_info("ChatGoogleGenerativeAI"),
|
|
971
1124
|
client_options=self.client_options,
|
|
972
|
-
transport=
|
|
1125
|
+
transport=transport,
|
|
973
1126
|
)
|
|
974
1127
|
return self.async_client_running
|
|
975
1128
|
|
|
@@ -1406,14 +1559,6 @@ class ChatGoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseChatModel):
|
|
|
1406
1559
|
tools=[schema], first_tool_only=True
|
|
1407
1560
|
)
|
|
1408
1561
|
else:
|
|
1409
|
-
global WARNED_STRUCTURED_OUTPUT_JSON_MODE
|
|
1410
|
-
warnings.warn(
|
|
1411
|
-
"ChatGoogleGenerativeAI.with_structured_output with dict schema has "
|
|
1412
|
-
"changed recently to align with behavior of other LangChain chat "
|
|
1413
|
-
"models. More context: "
|
|
1414
|
-
"https://github.com/langchain-ai/langchain-google/pull/772"
|
|
1415
|
-
)
|
|
1416
|
-
WARNED_STRUCTURED_OUTPUT_JSON_MODE = True
|
|
1417
1562
|
parser = JsonOutputKeyToolsParser(key_name=tool_name, first_tool_only=True)
|
|
1418
1563
|
tool_choice = tool_name if self._supports_tool_choice else None
|
|
1419
1564
|
try:
|
{langchain_google_genai-2.1.2 → langchain_google_genai-2.1.3}/langchain_google_genai/embeddings.py
RENAMED
|
@@ -6,6 +6,7 @@ from typing import Any, Dict, List, Optional
|
|
|
6
6
|
from google.ai.generativelanguage_v1beta.types import (
|
|
7
7
|
BatchEmbedContentsRequest,
|
|
8
8
|
EmbedContentRequest,
|
|
9
|
+
EmbedContentResponse,
|
|
9
10
|
)
|
|
10
11
|
from langchain_core.embeddings import Embeddings
|
|
11
12
|
from langchain_core.utils import secret_from_env
|
|
@@ -239,7 +240,8 @@ class GoogleGenerativeAIEmbeddings(BaseModel, Embeddings):
|
|
|
239
240
|
title: Optional[str] = None,
|
|
240
241
|
output_dimensionality: Optional[int] = None,
|
|
241
242
|
) -> List[float]:
|
|
242
|
-
"""Embed a text
|
|
243
|
+
"""Embed a text, using the non-batch endpoint:
|
|
244
|
+
https://ai.google.dev/api/rest/v1/models/embedContent#EmbedContentRequest
|
|
243
245
|
|
|
244
246
|
Args:
|
|
245
247
|
text: The text to embed.
|
|
@@ -247,15 +249,19 @@ class GoogleGenerativeAIEmbeddings(BaseModel, Embeddings):
|
|
|
247
249
|
title: An optional title for the text.
|
|
248
250
|
Only applicable when TaskType is RETRIEVAL_DOCUMENT.
|
|
249
251
|
output_dimensionality: Optional reduced dimension for the output embedding.
|
|
250
|
-
https://ai.google.dev/api/rest/v1/models/batchEmbedContents#EmbedContentRequest
|
|
251
252
|
|
|
252
253
|
Returns:
|
|
253
254
|
Embedding for the text.
|
|
254
255
|
"""
|
|
255
256
|
task_type = self.task_type or "RETRIEVAL_QUERY"
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
257
|
+
try:
|
|
258
|
+
request: EmbedContentRequest = self._prepare_request(
|
|
259
|
+
text=text,
|
|
260
|
+
task_type=task_type,
|
|
261
|
+
title=title,
|
|
262
|
+
output_dimensionality=output_dimensionality,
|
|
263
|
+
)
|
|
264
|
+
result: EmbedContentResponse = self.client.embed_content(request)
|
|
265
|
+
except Exception as e:
|
|
266
|
+
raise GoogleGenerativeAIError(f"Error embedding content: {e}") from e
|
|
267
|
+
return list(result.embedding.values)
|
{langchain_google_genai-2.1.2 → langchain_google_genai-2.1.3}/langchain_google_genai/llms.py
RENAMED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import logging
|
|
4
|
+
from difflib import get_close_matches
|
|
3
5
|
from typing import Any, Iterator, List, Optional
|
|
4
6
|
|
|
5
7
|
from langchain_core.callbacks import (
|
|
@@ -17,6 +19,8 @@ from langchain_google_genai._common import (
|
|
|
17
19
|
)
|
|
18
20
|
from langchain_google_genai.chat_models import ChatGoogleGenerativeAI
|
|
19
21
|
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
20
24
|
|
|
21
25
|
class GoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseLLM):
|
|
22
26
|
"""Google GenerativeAI models.
|
|
@@ -33,6 +37,28 @@ class GoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseLLM):
|
|
|
33
37
|
populate_by_name=True,
|
|
34
38
|
)
|
|
35
39
|
|
|
40
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
41
|
+
"""Needed for arg validation."""
|
|
42
|
+
# Get all valid field names, including aliases
|
|
43
|
+
valid_fields = set()
|
|
44
|
+
for field_name, field_info in self.model_fields.items():
|
|
45
|
+
valid_fields.add(field_name)
|
|
46
|
+
if hasattr(field_info, "alias") and field_info.alias is not None:
|
|
47
|
+
valid_fields.add(field_info.alias)
|
|
48
|
+
|
|
49
|
+
# Check for unrecognized arguments
|
|
50
|
+
for arg in kwargs:
|
|
51
|
+
if arg not in valid_fields:
|
|
52
|
+
suggestions = get_close_matches(arg, valid_fields, n=1)
|
|
53
|
+
suggestion = (
|
|
54
|
+
f" Did you mean: '{suggestions[0]}'?" if suggestions else ""
|
|
55
|
+
)
|
|
56
|
+
logger.warning(
|
|
57
|
+
f"Unexpected argument '{arg}' "
|
|
58
|
+
f"provided to GoogleGenerativeAI.{suggestion}"
|
|
59
|
+
)
|
|
60
|
+
super().__init__(**kwargs)
|
|
61
|
+
|
|
36
62
|
@model_validator(mode="after")
|
|
37
63
|
def validate_environment(self) -> Self:
|
|
38
64
|
"""Validates params and passes them to google-generativeai package."""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "langchain-google-genai"
|
|
3
|
-
version = "2.1.
|
|
3
|
+
version = "2.1.3"
|
|
4
4
|
description = "An integration package connecting Google's genai package and LangChain"
|
|
5
5
|
authors = []
|
|
6
6
|
readme = "README.md"
|
|
@@ -12,7 +12,7 @@ license = "MIT"
|
|
|
12
12
|
|
|
13
13
|
[tool.poetry.dependencies]
|
|
14
14
|
python = ">=3.9,<4.0"
|
|
15
|
-
langchain-core = "^0.3.
|
|
15
|
+
langchain-core = "^0.3.52"
|
|
16
16
|
google-ai-generativelanguage = "^0.6.16"
|
|
17
17
|
pydantic = ">=2,<3"
|
|
18
18
|
filetype = "^1.2.0"
|
|
@@ -27,8 +27,8 @@ pytest-mock = "^3.10.0"
|
|
|
27
27
|
syrupy = "^4.0.2"
|
|
28
28
|
pytest-watcher = "^0.3.4"
|
|
29
29
|
pytest-asyncio = "^0.21.1"
|
|
30
|
-
numpy = "
|
|
31
|
-
langchain-tests = "0.3.
|
|
30
|
+
numpy = ">=1.26.2"
|
|
31
|
+
langchain-tests = "0.3.18"
|
|
32
32
|
|
|
33
33
|
[tool.codespell]
|
|
34
34
|
ignore-words-list = "rouge"
|
|
@@ -60,7 +60,7 @@ mypy = "^1.10"
|
|
|
60
60
|
types-requests = "^2.28.11.5"
|
|
61
61
|
types-google-cloud-ndb = "^2.2.0.1"
|
|
62
62
|
types-protobuf = "^4.24.0.20240302"
|
|
63
|
-
numpy = "
|
|
63
|
+
numpy = ">=1.26.2"
|
|
64
64
|
|
|
65
65
|
|
|
66
66
|
[tool.poetry.group.dev]
|
|
File without changes
|
|
File without changes
|
{langchain_google_genai-2.1.2 → langchain_google_genai-2.1.3}/langchain_google_genai/__init__.py
RENAMED
|
File without changes
|
{langchain_google_genai-2.1.2 → langchain_google_genai-2.1.3}/langchain_google_genai/_enums.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{langchain_google_genai-2.1.2 → langchain_google_genai-2.1.3}/langchain_google_genai/_image_utils.py
RENAMED
|
File without changes
|
{langchain_google_genai-2.1.2 → langchain_google_genai-2.1.3}/langchain_google_genai/genai_aqa.py
RENAMED
|
File without changes
|
|
File without changes
|
{langchain_google_genai-2.1.2 → langchain_google_genai-2.1.3}/langchain_google_genai/py.typed
RENAMED
|
File without changes
|