langfun 0.0.2.dev20240308__py3-none-any.whl → 0.0.2.dev20240310__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.
@@ -107,9 +107,9 @@ class Gemini(lf.LanguageModel):
107
107
  for lf_chunk in formatted.chunk():
108
108
  if isinstance(lf_chunk, str):
109
109
  chunk = lf_chunk
110
- elif self.multimodal and isinstance(lf_chunk, lf_modalities.Image):
110
+ elif self.multimodal and isinstance(lf_chunk, lf_modalities.MimeType):
111
111
  chunk = genai.types.BlobDict(
112
- data=lf_chunk.to_bytes(), mime_type=f'image/{lf_chunk.image_format}'
112
+ data=lf_chunk.to_bytes(), mime_type=lf_chunk.mime_type
113
113
  )
114
114
  else:
115
115
  raise ValueError(f'Unsupported modality: {lf_chunk!r}')
@@ -237,7 +237,7 @@ class OpenAI(lf.LanguageModel):
237
237
  for chunk in prompt.chunk():
238
238
  if isinstance(chunk, str):
239
239
  item = dict(type='text', text=chunk)
240
- elif isinstance(chunk, lf_modalities.image.ImageFile):
240
+ elif isinstance(chunk, lf_modalities.Image) and chunk.uri:
241
241
  item = dict(type='image_url', image_url=chunk.uri)
242
242
  else:
243
243
  raise ValueError(f'Unsupported modality object: {chunk!r}.')
@@ -17,6 +17,8 @@
17
17
  # pylint: disable=g-bad-import-order
18
18
  # pylint: disable=g-import-not-at-top
19
19
 
20
+ from langfun.core.modalities.mime import MimeType
21
+ from langfun.core.modalities.mime import Custom
20
22
  from langfun.core.modalities.image import Image
21
23
 
22
24
  # pylint: enable=g-import-not-at-top
@@ -15,25 +15,13 @@
15
15
 
16
16
  import base64
17
17
  import imghdr
18
- from typing import Annotated, cast
18
+ from typing import cast
19
+ from langfun.core.modalities import mime
19
20
 
20
- import langfun.core as lf
21
- import requests
22
21
 
23
-
24
- class Image(lf.Modality):
22
+ class Image(mime.MimeType):
25
23
  """Base class for image."""
26
24
 
27
- @classmethod
28
- def from_bytes(cls, content: bytes) -> 'Image':
29
- """Creates an image from bytes."""
30
- return ImageContent(content)
31
-
32
- @classmethod
33
- def from_uri(cls, uri: str) -> 'Image':
34
- """Creates an image from file."""
35
- return ImageFile(uri)
36
-
37
25
  @property
38
26
  def image_format(self) -> str:
39
27
  iformat = imghdr.what(None, self.to_bytes())
@@ -41,36 +29,12 @@ class Image(lf.Modality):
41
29
  raise ValueError(f'Unsupported image format: {iformat!r}.')
42
30
  return cast(str, iformat)
43
31
 
44
-
45
- class ImageContent(Image):
46
- """Raw image content."""
47
-
48
- content: Annotated[bytes, 'The raw content of the image.']
49
-
50
- def to_bytes(self) -> bytes:
51
- return self.content
32
+ @property
33
+ def mime_type(self) -> str:
34
+ return f'image/{self.image_format}'
52
35
 
53
36
  def _repr_html_(self) -> str:
37
+ if self.uri:
38
+ return f'<img src="{self.uri}">'
54
39
  image_raw = base64.b64encode(self.to_bytes()).decode()
55
40
  return f'<img src="data:image/{self.image_format};base64,{image_raw}">'
56
-
57
-
58
- class ImageFile(Image):
59
- """A image file."""
60
-
61
- uri: Annotated[str, 'The URI of the image. (e.g. https://..../a.jpg).']
62
-
63
- def _on_bound(self):
64
- super()._on_bound()
65
- self._bytes = None
66
-
67
- def to_bytes(self) -> bytes:
68
- if self._bytes is None:
69
- self._bytes = requests.get(
70
- self.uri,
71
- headers={'User-Agent': 'Langfun'},
72
- ).content
73
- return self._bytes
74
-
75
- def _repr_html_(self) -> str:
76
- return f'<img src="{self.uri}">'
@@ -0,0 +1,81 @@
1
+ # Copyright 2023 The Langfun Authors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ """MIME type data."""
15
+
16
+ import abc
17
+ from typing import Annotated, Union
18
+ import langfun.core as lf
19
+ import pyglove as pg
20
+ import requests
21
+
22
+
23
+ class MimeType(lf.Modality):
24
+ """Base for MIME type data."""
25
+
26
+ @property
27
+ @abc.abstractmethod
28
+ def mime_type(self) -> str:
29
+ """Returns the MIME type."""
30
+
31
+ uri: Annotated[str | None, 'The URI for locating the MIME data. '] = None
32
+
33
+ content: Annotated[
34
+ Union[str, bytes, None], 'The raw content of the MIME type.'
35
+ ] = None
36
+
37
+ def _on_bound(self):
38
+ super()._on_bound()
39
+ if self.uri is None and self.content is None:
40
+ raise ValueError('Either uri or content must be provided.')
41
+
42
+ def to_bytes(self) -> bytes:
43
+ if self.content is not None:
44
+ return self.content
45
+
46
+ assert self.uri is not None
47
+ if self.uri.lower().startswith(('http:', 'https:', 'ftp:')):
48
+ content = requests.get(
49
+ self.uri,
50
+ headers={'User-Agent': 'Langfun'},
51
+ ).content
52
+ else:
53
+ content = pg.io.readfile(self.uri, mode='rb')
54
+ self.rebind(content=content, skip_notification=True)
55
+ return self.content
56
+
57
+ @classmethod
58
+ def from_uri(cls, uri: str, **kwargs) -> 'MimeType':
59
+ return cls(uri=uri, content=None, **kwargs)
60
+
61
+ @classmethod
62
+ def from_bytes(cls, content: bytes | str, **kwargs) -> 'MimeType':
63
+ return cls(content=content, **kwargs)
64
+
65
+
66
+ @pg.use_init_args(['type', 'content', 'uri'])
67
+ class Custom(MimeType):
68
+ """Custom MIME data."""
69
+
70
+ type: Annotated[
71
+ str, 'The MIME type of the data. E.g. text/plain, or image/png. '
72
+ ]
73
+
74
+ @property
75
+ def mime_type(self) -> str:
76
+ return self.type
77
+
78
+
79
+ class Pdf(Custom):
80
+ """PDF document."""
81
+ type = 'application/pdf'
@@ -0,0 +1,59 @@
1
+ # Copyright 2023 The Langfun Authors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ """MIME tests."""
15
+ import unittest
16
+ from unittest import mock
17
+
18
+ from langfun.core.modalities import mime
19
+ import pyglove as pg
20
+
21
+
22
+ def mock_request(*args, **kwargs):
23
+ del args, kwargs
24
+ return pg.Dict(content='foo')
25
+
26
+
27
+ def mock_readfile(*args, **kwargs):
28
+ del args, kwargs
29
+ return 'bar'
30
+
31
+
32
+ class CustomMimeTest(unittest.TestCase):
33
+
34
+ def test_content(self):
35
+ content = mime.Custom('text/plain', 'foo')
36
+ self.assertEqual(content.to_bytes(), 'foo')
37
+ self.assertEqual(content.mime_type, 'text/plain')
38
+
39
+ with self.assertRaisesRegex(
40
+ ValueError, 'Either uri or content must be provided.'
41
+ ):
42
+ mime.Custom('text/plain')
43
+
44
+ def test_from_uri(self):
45
+ content = mime.Custom.from_uri('http://mock/web/a.txt', type='text/plain')
46
+ with mock.patch('requests.get') as mock_requests_stub:
47
+ mock_requests_stub.side_effect = mock_request
48
+ self.assertEqual(content.to_bytes(), 'foo')
49
+ self.assertEqual(content.mime_type, 'text/plain')
50
+
51
+ content = mime.Custom.from_uri('a.txt', type='text/plain')
52
+ with mock.patch('pyglove.io.readfile') as mock_readfile_stub:
53
+ mock_readfile_stub.side_effect = mock_readfile
54
+ self.assertEqual(content.to_bytes(), 'bar')
55
+ self.assertEqual(content.mime_type, 'text/plain')
56
+
57
+
58
+ if __name__ == '__main__':
59
+ unittest.main()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: langfun
3
- Version: 0.0.2.dev20240308
3
+ Version: 0.0.2.dev20240310
4
4
  Summary: Langfun: Language as Functions.
5
5
  Home-page: https://github.com/google/langfun
6
6
  Author: Langfun Authors
@@ -49,11 +49,11 @@ langfun/core/eval/scoring_test.py,sha256=_L_B40VZkyI2_PJce-jVKYC4llrO4jGUR5j86Gu
49
49
  langfun/core/llms/__init__.py,sha256=T4mgT091BLA4mHrOjAvEGhZPHf0tiYgqD88l_JTp1dQ,2386
50
50
  langfun/core/llms/fake.py,sha256=dVzOrW27RZ1p3DdQoRCRZs_vfoQcTcNrlWxia7oqmvw,2499
51
51
  langfun/core/llms/fake_test.py,sha256=Qk_Yoi4Z7P9o6f8Q_BZkaSlvxH89ZVsDxnVIbSBRBXk,3555
52
- langfun/core/llms/gemini.py,sha256=p3d4Cl2uET-os1n_V3YNE6-6cYrZjndj7lxZIk2E8_4,5688
52
+ langfun/core/llms/gemini.py,sha256=9HxrTvac_dMbDytNCEo6YcYqs8vsePtScfI_EygpI5Y,5677
53
53
  langfun/core/llms/gemini_test.py,sha256=ybNNCn3JW3hYpMe0wT5ILGDrMPaYYU8PN2kSookM0jk,5433
54
54
  langfun/core/llms/llama_cpp.py,sha256=EIjJa1-Tg4_VaIxVR88oDWSWc_axc1r2KwSPpl4PSp0,2549
55
55
  langfun/core/llms/llama_cpp_test.py,sha256=ZxC6defGd_HX9SFRU9U4cJiQnBKundbOrchbXuC1Z2M,1683
56
- langfun/core/llms/openai.py,sha256=ufFz1Q2bHVukyAck0dZ5MYZ8IKcVkYzDjQn3YXugLCQ,11711
56
+ langfun/core/llms/openai.py,sha256=-PnJ8OICuPTzr-unIys4HftNVZ6seAhV5nXny4OfVYc,11715
57
57
  langfun/core/llms/openai_test.py,sha256=yfw7A-4Zo9u1cIkAMk39evE-tO7z6isNYTXiSnJXDQw,7599
58
58
  langfun/core/llms/cache/__init__.py,sha256=QAo3InUMDM_YpteNnVCSejI4zOsnjSMWKJKzkb3VY64,993
59
59
  langfun/core/llms/cache/base.py,sha256=cFfYvOIUae842pncqCAsRvqXCk2AnAsRYVx0mcIoAeY,3338
@@ -62,9 +62,11 @@ langfun/core/llms/cache/in_memory_test.py,sha256=WYLg_SlUdkUxIdBYnbksMqwVLFuzcNL
62
62
  langfun/core/memories/__init__.py,sha256=HpghfZ-w1NQqzJXBx8Lz0daRhB2rcy2r9Xm491SBhC4,773
63
63
  langfun/core/memories/conversation_history.py,sha256=c9amD8hCxGFiZuVAzkP0dOMWSp8L90uvwkOejjuBqO0,1835
64
64
  langfun/core/memories/conversation_history_test.py,sha256=AaW8aNoFjxNusanwJDV0r3384Mg0eAweGmPx5DIkM0Y,2052
65
- langfun/core/modalities/__init__.py,sha256=VI96XGNfXqcJpBh2c17tkTs0gpO5ftc77Ep0jfLOztw,882
66
- langfun/core/modalities/image.py,sha256=HU0sV4ZTwRnAwQthmdWZwhFZRD86RyvqoS8JUW2Ia-A,2065
65
+ langfun/core/modalities/__init__.py,sha256=mK82mgydGHsQLEfMRO4J-dlFzPVIrB2KPIA3OVUL6GQ,980
66
+ langfun/core/modalities/image.py,sha256=jYkVRoD2yLgh1ywJwbeHjHompvy3RbHIFb_xYgKzbsc,1297
67
67
  langfun/core/modalities/image_test.py,sha256=YxDRvC49Bjwyyndd_P7y6XjyS7dOft0Zewwxk-7q4kE,2301
68
+ langfun/core/modalities/mime.py,sha256=mMjDufv2HpnYrLUD05LqhcuinIW8yp0xRSa8TmBW9ow,2238
69
+ langfun/core/modalities/mime_test.py,sha256=cVHxRvJ1QXC1SVhBmWkJdWGpL9Xl0UNfTQq6j0OGGL4,1881
68
70
  langfun/core/structured/__init__.py,sha256=LZ5BFLX6VXy1zH17yChWCdg8bvIDrhtL2lqtSCwtZ-M,3187
69
71
  langfun/core/structured/completion.py,sha256=skBxt6V_fv2TBUKnzFgnPMbVY8HSYn8sY04MLok2yvs,7299
70
72
  langfun/core/structured/completion_test.py,sha256=98UCgA4gzfp6H6HgP2s2kcKs25YH3k4Nxj1rgAvmVBw,19249
@@ -89,8 +91,8 @@ langfun/core/templates/demonstration.py,sha256=vCrgYubdZM5Umqcgp8NUVGXgr4P_c-fik
89
91
  langfun/core/templates/demonstration_test.py,sha256=SafcDQ0WgI7pw05EmPI2S4v1t3ABKzup8jReCljHeK4,2162
90
92
  langfun/core/templates/selfplay.py,sha256=yhgrJbiYwq47TgzThmHrDQTF4nDrTI09CWGhuQPNv-s,2273
91
93
  langfun/core/templates/selfplay_test.py,sha256=IB5rWbjK_9CTkqEo1BclQPzFAKcIiusJckH8J19HFgI,2096
92
- langfun-0.0.2.dev20240308.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
93
- langfun-0.0.2.dev20240308.dist-info/METADATA,sha256=hzyG6mL6i6mEGWa7q9eDovYRVCH_UmjAA3wlFo79oII,3368
94
- langfun-0.0.2.dev20240308.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
95
- langfun-0.0.2.dev20240308.dist-info/top_level.txt,sha256=RhlEkHxs1qtzmmtWSwYoLVJAc1YrbPtxQ52uh8Z9VvY,8
96
- langfun-0.0.2.dev20240308.dist-info/RECORD,,
94
+ langfun-0.0.2.dev20240310.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
95
+ langfun-0.0.2.dev20240310.dist-info/METADATA,sha256=TOSROdxEVxAK4gY073Yz2QNk6oskWwfXRO_0_0-Qv5I,3368
96
+ langfun-0.0.2.dev20240310.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
97
+ langfun-0.0.2.dev20240310.dist-info/top_level.txt,sha256=RhlEkHxs1qtzmmtWSwYoLVJAc1YrbPtxQ52uh8Z9VvY,8
98
+ langfun-0.0.2.dev20240310.dist-info/RECORD,,