langchain-google-genai 2.0.3__tar.gz → 2.0.5__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.

Files changed (16) hide show
  1. {langchain_google_genai-2.0.3 → langchain_google_genai-2.0.5}/PKG-INFO +2 -12
  2. {langchain_google_genai-2.0.3 → langchain_google_genai-2.0.5}/README.md +0 -8
  3. {langchain_google_genai-2.0.3 → langchain_google_genai-2.0.5}/langchain_google_genai/_image_utils.py +15 -21
  4. {langchain_google_genai-2.0.3 → langchain_google_genai-2.0.5}/langchain_google_genai/chat_models.py +11 -86
  5. {langchain_google_genai-2.0.3 → langchain_google_genai-2.0.5}/langchain_google_genai/llms.py +12 -1
  6. {langchain_google_genai-2.0.3 → langchain_google_genai-2.0.5}/pyproject.toml +4 -24
  7. {langchain_google_genai-2.0.3 → langchain_google_genai-2.0.5}/LICENSE +0 -0
  8. {langchain_google_genai-2.0.3 → langchain_google_genai-2.0.5}/langchain_google_genai/__init__.py +0 -0
  9. {langchain_google_genai-2.0.3 → langchain_google_genai-2.0.5}/langchain_google_genai/_common.py +0 -0
  10. {langchain_google_genai-2.0.3 → langchain_google_genai-2.0.5}/langchain_google_genai/_enums.py +0 -0
  11. {langchain_google_genai-2.0.3 → langchain_google_genai-2.0.5}/langchain_google_genai/_function_utils.py +0 -0
  12. {langchain_google_genai-2.0.3 → langchain_google_genai-2.0.5}/langchain_google_genai/_genai_extension.py +0 -0
  13. {langchain_google_genai-2.0.3 → langchain_google_genai-2.0.5}/langchain_google_genai/embeddings.py +0 -0
  14. {langchain_google_genai-2.0.3 → langchain_google_genai-2.0.5}/langchain_google_genai/genai_aqa.py +0 -0
  15. {langchain_google_genai-2.0.3 → langchain_google_genai-2.0.5}/langchain_google_genai/google_vector_store.py +0 -0
  16. {langchain_google_genai-2.0.3 → langchain_google_genai-2.0.5}/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.0.3
3
+ Version: 2.0.5
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
@@ -11,10 +11,8 @@ Classifier: Programming Language :: Python :: 3.9
11
11
  Classifier: Programming Language :: Python :: 3.10
12
12
  Classifier: Programming Language :: Python :: 3.11
13
13
  Classifier: Programming Language :: Python :: 3.12
14
- Provides-Extra: images
15
14
  Requires-Dist: google-generativeai (>=0.8.0,<0.9.0)
16
- Requires-Dist: langchain-core (>=0.3.13,<0.4)
17
- Requires-Dist: pillow (>=10.1.0,<11.0.0) ; extra == "images"
15
+ Requires-Dist: langchain-core (>=0.3.15,<0.4)
18
16
  Requires-Dist: pydantic (>=2,<3)
19
17
  Project-URL: Repository, https://github.com/langchain-ai/langchain-google
20
18
  Project-URL: Source Code, https://github.com/langchain-ai/langchain-google/tree/main/libs/genai
@@ -30,12 +28,6 @@ This package contains the LangChain integrations for Gemini through their genera
30
28
  pip install -U langchain-google-genai
31
29
  ```
32
30
 
33
- ### Image utilities
34
- To use image utility methods, like loading images from GCS urls, install with extras group 'images':
35
-
36
- ```bash
37
- pip install -e "langchain-google-genai[images]"
38
- ```
39
31
 
40
32
  ## Chat Models
41
33
 
@@ -82,9 +74,7 @@ The value of `image_url` can be any of the following:
82
74
 
83
75
  - A public image URL
84
76
  - An accessible gcs file (e.g., "gcs://path/to/file.png")
85
- - A local file path
86
77
  - A base64 encoded image (e.g., `data:image/png;base64,abcd124`)
87
- - A PIL image
88
78
 
89
79
 
90
80
 
@@ -8,12 +8,6 @@ This package contains the LangChain integrations for Gemini through their genera
8
8
  pip install -U langchain-google-genai
9
9
  ```
10
10
 
11
- ### Image utilities
12
- To use image utility methods, like loading images from GCS urls, install with extras group 'images':
13
-
14
- ```bash
15
- pip install -e "langchain-google-genai[images]"
16
- ```
17
11
 
18
12
  ## Chat Models
19
13
 
@@ -60,9 +54,7 @@ The value of `image_url` can be any of the following:
60
54
 
61
55
  - A public image URL
62
56
  - An accessible gcs file (e.g., "gcs://path/to/file.png")
63
- - A local file path
64
57
  - A base64 encoded image (e.g., `data:image/png;base64,abcd124`)
65
- - A PIL image
66
58
 
67
59
 
68
60
 
@@ -25,7 +25,6 @@ class ImageBytesLoader:
25
25
 
26
26
  Currently supported:
27
27
  - B64 Encoded image string
28
- - Local file path
29
28
  - URL
30
29
  """
31
30
 
@@ -35,7 +34,6 @@ class ImageBytesLoader:
35
34
  Args:
36
35
  image_string: Can be either:
37
36
  - B64 Encoded image string
38
- - Local file path
39
37
  - URL
40
38
 
41
39
  Returns:
@@ -51,12 +49,17 @@ class ImageBytesLoader:
51
49
  return self._bytes_from_url(image_string)
52
50
 
53
51
  if route == Route.LOCAL_FILE:
52
+ raise ValueError(
53
+ "Loading from local files is no longer supported for security reasons. "
54
+ "Please pass in images as Google Cloud Storage URI, "
55
+ "b64 encoded image string (data:image/...), or valid image url."
56
+ )
54
57
  return self._bytes_from_file(image_string)
55
58
 
56
59
  raise ValueError(
57
60
  "Image string must be one of: Google Cloud Storage URI, "
58
- "b64 encoded image string (data:image/...), valid image url, "
59
- f"or existing local image file. Instead got '{image_string}'."
61
+ "b64 encoded image string (data:image/...), or valid image url."
62
+ f"Instead got '{image_string}'."
60
63
  )
61
64
 
62
65
  def load_part(self, image_string: str) -> Part:
@@ -65,7 +68,6 @@ class ImageBytesLoader:
65
68
  Args:
66
69
  image_string: Can be either:
67
70
  - B64 Encoded image string
68
- - Local file path
69
71
  - URL
70
72
  """
71
73
  route = self._route(image_string)
@@ -77,7 +79,12 @@ class ImageBytesLoader:
77
79
  bytes_ = self._bytes_from_url(image_string)
78
80
 
79
81
  if route == Route.LOCAL_FILE:
80
- bytes_ = self._bytes_from_file(image_string)
82
+ msg = (
83
+ "Loading from local files is no longer supported for security reasons. "
84
+ "Please specify images as Google Cloud Storage URI, "
85
+ "b64 encoded image string (data:image/...), or valid image url."
86
+ )
87
+ raise ValueError(msg)
81
88
 
82
89
  inline_data: Dict[str, Any] = {"data": bytes_}
83
90
  mime_type, _ = mimetypes.guess_type(image_string)
@@ -98,8 +105,8 @@ class ImageBytesLoader:
98
105
 
99
106
  raise ValueError(
100
107
  "Image string must be one of: "
101
- "b64 encoded image string (data:image/...), valid image url, "
102
- f"or existing local image file. Instead got '{image_string}'."
108
+ "b64 encoded image string (data:image/...) or valid image url."
109
+ f" Instead got '{image_string}'."
103
110
  )
104
111
 
105
112
  def _bytes_from_b64(self, base64_image: str) -> bytes:
@@ -121,19 +128,6 @@ class ImageBytesLoader:
121
128
 
122
129
  raise ValueError(f"Error in b64 encoded image. Must follow pattern: {pattern}")
123
130
 
124
- def _bytes_from_file(self, file_path: str) -> bytes:
125
- """Gets image bytes from a local file path.
126
-
127
- Args:
128
- file_path: Existing file path.
129
-
130
- Returns:
131
- Image bytes
132
- """
133
- with open(file_path, "rb") as image_file:
134
- image_bytes = image_file.read()
135
- return image_bytes
136
-
137
131
  def _bytes_from_url(self, url: str) -> bytes:
138
132
  """Gets image bytes from a public url.
139
133
 
@@ -1,13 +1,10 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import asyncio
4
- import base64
5
4
  import json
6
5
  import logging
7
- import os
8
6
  import uuid
9
7
  import warnings
10
- from io import BytesIO
11
8
  from operator import itemgetter
12
9
  from typing import (
13
10
  Any,
@@ -24,13 +21,11 @@ from typing import (
24
21
  Union,
25
22
  cast,
26
23
  )
27
- from urllib.parse import urlparse
28
24
 
29
25
  import google.api_core
30
26
 
31
27
  # TODO: remove ignore once the google package is published with types
32
28
  import proto # type: ignore[import]
33
- import requests
34
29
  from google.ai.generativelanguage_v1beta import (
35
30
  GenerativeServiceAsyncClient as v1betaGenerativeServiceAsyncClient,
36
31
  )
@@ -117,16 +112,6 @@ from langchain_google_genai.llms import _BaseGoogleGenerativeAI
117
112
 
118
113
  from . import _genai_extension as genaix
119
114
 
120
- IMAGE_TYPES: Tuple = ()
121
- try:
122
- import PIL
123
- from PIL.Image import Image
124
-
125
- IMAGE_TYPES = IMAGE_TYPES + (Image,)
126
- except ImportError:
127
- PIL = None # type: ignore
128
- Image = None # type: ignore
129
-
130
115
  logger = logging.getLogger(__name__)
131
116
 
132
117
 
@@ -248,75 +233,6 @@ def _is_openai_parts_format(part: dict) -> bool:
248
233
  return "type" in part
249
234
 
250
235
 
251
- def _is_vision_model(model: str) -> bool:
252
- return "vision" in model
253
-
254
-
255
- def _is_url(s: str) -> bool:
256
- try:
257
- result = urlparse(s)
258
- return all([result.scheme, result.netloc])
259
- except Exception as e:
260
- logger.debug(f"Unable to parse URL: {e}")
261
- return False
262
-
263
-
264
- def _is_b64(s: str) -> bool:
265
- return s.startswith("data:image")
266
-
267
-
268
- def _load_image_from_gcs(path: str, project: Optional[str] = None) -> Image:
269
- try:
270
- from google.cloud import storage # type: ignore[attr-defined]
271
- except ImportError:
272
- raise ImportError(
273
- "google-cloud-storage is required to load images from GCS."
274
- " Install it with `pip install google-cloud-storage`"
275
- )
276
- if PIL is None:
277
- raise ImportError(
278
- "PIL is required to load images. Please install it "
279
- "with `pip install pillow`"
280
- )
281
-
282
- gcs_client = storage.Client(project=project)
283
- pieces = path.split("/")
284
- blobs = list(gcs_client.list_blobs(pieces[2], prefix="/".join(pieces[3:])))
285
- if len(blobs) > 1:
286
- raise ValueError(f"Found more than one candidate for {path}!")
287
- img_bytes = blobs[0].download_as_bytes()
288
- return PIL.Image.open(BytesIO(img_bytes))
289
-
290
-
291
- def _url_to_pil(image_source: str) -> Image:
292
- if PIL is None:
293
- raise ImportError(
294
- "PIL is required to load images. Please install it "
295
- "with `pip install pillow`"
296
- )
297
- try:
298
- if isinstance(image_source, IMAGE_TYPES):
299
- return image_source # type: ignore[return-value]
300
- elif _is_url(image_source):
301
- if image_source.startswith("gs://"):
302
- return _load_image_from_gcs(image_source)
303
- response = requests.get(image_source)
304
- response.raise_for_status()
305
- return PIL.Image.open(BytesIO(response.content))
306
- elif _is_b64(image_source):
307
- _, encoded = image_source.split(",", 1)
308
- data = base64.b64decode(encoded)
309
- return PIL.Image.open(BytesIO(data))
310
- elif os.path.exists(image_source):
311
- return PIL.Image.open(image_source)
312
- else:
313
- raise ValueError(
314
- "The provided string is not a valid URL, base64, or file path."
315
- )
316
- except Exception as e:
317
- raise ValueError(f"Unable to process the provided image source: {e}")
318
-
319
-
320
236
  def _convert_to_parts(
321
237
  raw_content: Union[str, Sequence[Union[str, dict]]],
322
238
  ) -> List[Part]:
@@ -400,8 +316,17 @@ def _parse_chat_history(
400
316
  continue
401
317
  elif isinstance(message, AIMessage):
402
318
  role = "model"
403
- raw_function_call = message.additional_kwargs.get("function_call")
404
- if raw_function_call:
319
+ if message.tool_calls:
320
+ parts = []
321
+ for tool_call in message.tool_calls:
322
+ function_call = FunctionCall(
323
+ {
324
+ "name": tool_call["name"],
325
+ "args": tool_call["args"],
326
+ }
327
+ )
328
+ parts.append(Part(function_call=function_call))
329
+ elif raw_function_call := message.additional_kwargs.get("function_call"):
405
330
  function_call = FunctionCall(
406
331
  {
407
332
  "name": raw_function_call["name"],
@@ -310,10 +310,21 @@ class GoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseLLM):
310
310
  generation_config=generation_config,
311
311
  safety_settings=kwargs.pop("safety_settings", None),
312
312
  )
313
+ generation_info = None
314
+ if res.usage_metadata is not None:
315
+ generation_info = {
316
+ "usage_metadata": res.to_dict().get("usage_metadata")
317
+ }
318
+
313
319
  candidates = [
314
320
  "".join([p.text for p in c.content.parts]) for c in res.candidates
315
321
  ]
316
- generations.append([Generation(text=c) for c in candidates])
322
+ generations.append(
323
+ [
324
+ Generation(text=c, generation_info=generation_info)
325
+ for c in candidates
326
+ ]
327
+ )
317
328
  else:
318
329
  res = _completion_with_retry(
319
330
  self,
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "langchain-google-genai"
3
- version = "2.0.3"
3
+ version = "2.0.5"
4
4
  description = "An integration package connecting Google's genai package and LangChain"
5
5
  authors = []
6
6
  readme = "README.md"
@@ -12,14 +12,10 @@ license = "MIT"
12
12
 
13
13
  [tool.poetry.dependencies]
14
14
  python = ">=3.9,<4.0"
15
- langchain-core = ">=0.3.13,<0.4"
15
+ langchain-core = ">=0.3.15,<0.4"
16
16
  google-generativeai = "^0.8.0"
17
- pillow = { version = "^10.1.0", optional = true }
18
17
  pydantic = ">=2,<3"
19
18
 
20
- [tool.poetry.extras]
21
- images = ["pillow"]
22
-
23
19
  [tool.poetry.group.test]
24
20
  optional = true
25
21
 
@@ -31,15 +27,12 @@ syrupy = "^4.0.2"
31
27
  pytest-watcher = "^0.3.4"
32
28
  pytest-asyncio = "^0.21.1"
33
29
  numpy = "^1.26.2"
34
- langchain-core = { git = "https://github.com/langchain-ai/langchain.git", subdirectory = "libs/core" }
35
- langchain-standard-tests = { git = "https://github.com/langchain-ai/langchain.git", subdirectory = "libs/standard-tests" }
30
+ langchain-tests = "0.3.1"
36
31
 
37
32
  [tool.codespell]
38
33
  ignore-words-list = "rouge"
39
34
 
40
35
 
41
-
42
-
43
36
  [tool.poetry.group.codespell]
44
37
  optional = true
45
38
 
@@ -47,15 +40,11 @@ optional = true
47
40
  codespell = "^2.2.0"
48
41
 
49
42
 
50
-
51
-
52
43
  [tool.poetry.group.test_integration]
53
44
  optional = true
54
45
 
55
46
  [tool.poetry.group.test_integration.dependencies]
56
- pillow = "^10.1.0"
57
-
58
-
47
+ pytest = "^7.3.0"
59
48
 
60
49
 
61
50
  [tool.poetry.group.lint]
@@ -65,29 +54,20 @@ optional = true
65
54
  ruff = "^0.1.5"
66
55
 
67
56
 
68
-
69
-
70
57
  [tool.poetry.group.typing.dependencies]
71
58
  mypy = "^1.10"
72
59
  types-requests = "^2.28.11.5"
73
60
  types-google-cloud-ndb = "^2.2.0.1"
74
- types-pillow = "^10.1.0.2"
75
61
  types-protobuf = "^4.24.0.20240302"
76
- langchain-core = { git = "https://github.com/langchain-ai/langchain.git", subdirectory = "libs/core" }
77
62
  numpy = "^1.26.2"
78
63
 
79
64
 
80
-
81
-
82
65
  [tool.poetry.group.dev]
83
66
  optional = true
84
67
 
85
68
  [tool.poetry.group.dev.dependencies]
86
- pillow = "^10.1.0"
87
69
  types-requests = "^2.31.0.10"
88
- types-pillow = "^10.1.0.2"
89
70
  types-google-cloud-ndb = "^2.2.0.1"
90
- langchain-core = { git = "https://github.com/langchain-ai/langchain.git", subdirectory = "libs/core" }
91
71
 
92
72
  [tool.ruff.lint]
93
73
  select = [