pixeltable 0.3.14__py3-none-any.whl → 0.4.0rc1__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 pixeltable might be problematic. Click here for more details.

Files changed (50) hide show
  1. pixeltable/__version__.py +2 -2
  2. pixeltable/catalog/catalog.py +292 -105
  3. pixeltable/catalog/column.py +10 -8
  4. pixeltable/catalog/dir.py +1 -2
  5. pixeltable/catalog/insertable_table.py +25 -20
  6. pixeltable/catalog/schema_object.py +3 -6
  7. pixeltable/catalog/table.py +245 -189
  8. pixeltable/catalog/table_version.py +319 -201
  9. pixeltable/catalog/table_version_handle.py +15 -2
  10. pixeltable/catalog/table_version_path.py +60 -21
  11. pixeltable/catalog/view.py +14 -5
  12. pixeltable/dataframe.py +11 -9
  13. pixeltable/env.py +2 -4
  14. pixeltable/exec/in_memory_data_node.py +1 -1
  15. pixeltable/exec/sql_node.py +20 -11
  16. pixeltable/exprs/column_property_ref.py +15 -6
  17. pixeltable/exprs/column_ref.py +32 -11
  18. pixeltable/exprs/comparison.py +1 -1
  19. pixeltable/exprs/row_builder.py +4 -6
  20. pixeltable/exprs/rowid_ref.py +8 -0
  21. pixeltable/exprs/similarity_expr.py +1 -0
  22. pixeltable/func/query_template_function.py +1 -1
  23. pixeltable/functions/gemini.py +166 -33
  24. pixeltable/functions/math.py +63 -0
  25. pixeltable/functions/string.py +212 -58
  26. pixeltable/globals.py +7 -4
  27. pixeltable/index/base.py +5 -0
  28. pixeltable/index/btree.py +5 -0
  29. pixeltable/index/embedding_index.py +5 -0
  30. pixeltable/io/external_store.py +8 -29
  31. pixeltable/io/label_studio.py +1 -1
  32. pixeltable/io/parquet.py +4 -4
  33. pixeltable/io/table_data_conduit.py +0 -31
  34. pixeltable/metadata/__init__.py +1 -1
  35. pixeltable/metadata/converters/convert_13.py +2 -2
  36. pixeltable/metadata/converters/convert_30.py +6 -11
  37. pixeltable/metadata/converters/convert_35.py +9 -0
  38. pixeltable/metadata/converters/util.py +3 -9
  39. pixeltable/metadata/notes.py +1 -0
  40. pixeltable/metadata/schema.py +5 -1
  41. pixeltable/plan.py +4 -4
  42. pixeltable/share/packager.py +207 -15
  43. pixeltable/share/publish.py +2 -2
  44. pixeltable/store.py +31 -13
  45. pixeltable/utils/dbms.py +1 -1
  46. {pixeltable-0.3.14.dist-info → pixeltable-0.4.0rc1.dist-info}/METADATA +1 -1
  47. {pixeltable-0.3.14.dist-info → pixeltable-0.4.0rc1.dist-info}/RECORD +50 -49
  48. {pixeltable-0.3.14.dist-info → pixeltable-0.4.0rc1.dist-info}/LICENSE +0 -0
  49. {pixeltable-0.3.14.dist-info → pixeltable-0.4.0rc1.dist-info}/WHEEL +0 -0
  50. {pixeltable-0.3.14.dist-info → pixeltable-0.4.0rc1.dist-info}/entry_points.txt +0 -0
@@ -5,10 +5,16 @@ first `pip install google-genai` and configure your Gemini credentials, as descr
5
5
  the [Working with Gemini](https://pixeltable.readme.io/docs/working-with-gemini) tutorial.
6
6
  """
7
7
 
8
+ import asyncio
9
+ import io
10
+ import tempfile
11
+ from pathlib import Path
8
12
  from typing import TYPE_CHECKING, Optional
9
13
 
14
+ import PIL.Image
15
+
10
16
  import pixeltable as pxt
11
- from pixeltable import env
17
+ from pixeltable import env, exceptions as excs, exprs
12
18
 
13
19
  if TYPE_CHECKING:
14
20
  from google import genai
@@ -27,23 +33,11 @@ def _genai_client() -> 'genai.client.Client':
27
33
 
28
34
  @pxt.udf(resource_pool='request-rate:gemini')
29
35
  async def generate_content(
30
- contents: str,
31
- *,
32
- model: str,
33
- candidate_count: Optional[int] = None,
34
- stop_sequences: Optional[list[str]] = None,
35
- max_output_tokens: Optional[int] = None,
36
- temperature: Optional[float] = None,
37
- top_p: Optional[float] = None,
38
- top_k: Optional[int] = None,
39
- response_mime_type: Optional[str] = None,
40
- response_schema: Optional[dict] = None,
41
- presence_penalty: Optional[float] = None,
42
- frequency_penalty: Optional[float] = None,
36
+ contents: str, *, model: str, config: Optional[dict] = None, tools: Optional[list[dict]] = None
43
37
  ) -> dict:
44
38
  """
45
39
  Generate content from the specified model. For additional details, see:
46
- <https://ai.google.dev/gemini-api/docs>
40
+ <https://ai.google.dev/gemini-api/docs/text-generation>
47
41
 
48
42
  Request throttling:
49
43
  Applies the rate limit set in the config (section `gemini`, key `rate_limit`). If no rate
@@ -56,38 +50,177 @@ async def generate_content(
56
50
  Args:
57
51
  contents: The input content to generate from.
58
52
  model: The name of the model to use.
59
-
60
- For details on the other parameters, see: <https://ai.google.dev/gemini-api/docs>
53
+ config: Configuration for generation, corresponding to keyword arguments of
54
+ `genai.types.GenerateContentConfig`. For details on the parameters, see:
55
+ <https://googleapis.github.io/python-genai/genai.html#module-genai.types>
56
+ tools: Optional list of Pixeltable tools to use. It is also possible to specify tools manually via the
57
+ `config.tools` parameter, but at most one of `config.tools` or `tools` may be used.
61
58
 
62
59
  Returns:
63
60
  A dictionary containing the response and other metadata.
64
61
 
65
62
  Examples:
66
- Add a computed column that applies the model `gemini-1.5-flash`
63
+ Add a computed column that applies the model `gemini-2.0-flash`
67
64
  to an existing Pixeltable column `tbl.prompt` of the table `tbl`:
68
65
 
69
- >>> tbl.add_computed_column(response=generate_content(tbl.prompt, model='gemini-1.5-flash'))
66
+ >>> tbl.add_computed_column(response=generate_content(tbl.prompt, model='gemini-2.0-flash'))
70
67
  """
71
68
  env.Env.get().require_package('google.genai')
72
69
  from google.genai import types
73
70
 
74
- config = types.GenerateContentConfig(
75
- candidate_count=candidate_count,
76
- stop_sequences=stop_sequences,
77
- max_output_tokens=max_output_tokens,
78
- temperature=temperature,
79
- top_p=top_p,
80
- top_k=top_k,
81
- response_mime_type=response_mime_type,
82
- response_schema=response_schema,
83
- presence_penalty=presence_penalty,
84
- frequency_penalty=frequency_penalty,
85
- )
86
-
87
- response = await _genai_client().aio.models.generate_content(model=model, contents=contents, config=config)
71
+ config_: types.GenerateContentConfig
72
+ if config is None and tools is None:
73
+ config_ = None
74
+ else:
75
+ if config is None:
76
+ config_ = types.GenerateContentConfig()
77
+ else:
78
+ config_ = types.GenerateContentConfig(**config)
79
+ if tools is not None:
80
+ gemini_tools = [__convert_pxt_tool(tool) for tool in tools]
81
+ config_.tools = [types.Tool(function_declarations=gemini_tools)]
82
+
83
+ response = await _genai_client().aio.models.generate_content(model=model, contents=contents, config=config_)
88
84
  return response.model_dump()
89
85
 
90
86
 
87
+ def __convert_pxt_tool(pxt_tool: dict) -> dict:
88
+ return {
89
+ 'name': pxt_tool['name'],
90
+ 'description': pxt_tool['description'],
91
+ 'parameters': {
92
+ 'type': 'object',
93
+ 'properties': pxt_tool['parameters']['properties'],
94
+ 'required': pxt_tool['required'],
95
+ },
96
+ }
97
+
98
+
99
+ def invoke_tools(tools: pxt.func.Tools, response: exprs.Expr) -> exprs.InlineDict:
100
+ """Converts an OpenAI response dict to Pixeltable tool invocation format and calls `tools._invoke()`."""
101
+ return tools._invoke(_gemini_response_to_pxt_tool_calls(response))
102
+
103
+
104
+ @pxt.udf
105
+ def _gemini_response_to_pxt_tool_calls(response: dict) -> Optional[dict]:
106
+ print(response)
107
+ pxt_tool_calls: dict[str, list[dict]] = {}
108
+ for part in response['candidates'][0]['content']['parts']:
109
+ tool_call = part.get('function_call')
110
+ if tool_call is not None:
111
+ tool_name = tool_call['name']
112
+ if tool_name not in pxt_tool_calls:
113
+ pxt_tool_calls[tool_name] = []
114
+ pxt_tool_calls[tool_name].append({'args': tool_call['args']})
115
+ if len(pxt_tool_calls) == 0:
116
+ return None
117
+ return pxt_tool_calls
118
+
119
+
91
120
  @generate_content.resource_pool
92
121
  def _(model: str) -> str:
93
122
  return f'request-rate:gemini:{model}'
123
+
124
+
125
+ @pxt.udf(resource_pool='request-rate:imagen')
126
+ async def generate_images(prompt: str, *, model: str, config: Optional[dict] = None) -> PIL.Image.Image:
127
+ """
128
+ Generates images based on a text description and configuration. For additional details, see:
129
+ <https://ai.google.dev/gemini-api/docs/image-generation>
130
+
131
+ __Requirements:__
132
+
133
+ - `pip install google-genai`
134
+
135
+ Args:
136
+ prompt: A text description of the images to generate.
137
+ model: The model to use.
138
+ config: Configuration for generation, corresponding to keyword arguments of
139
+ `genai.types.GenerateImagesConfig`. For details on the parameters, see:
140
+ <https://googleapis.github.io/python-genai/genai.html#module-genai.types>
141
+
142
+ Returns:
143
+ The generated image.
144
+
145
+ Examples:
146
+ Add a computed column that applies the model `imagen-3.0-generate-002`
147
+ to an existing Pixeltable column `tbl.prompt` of the table `tbl`:
148
+
149
+ >>> tbl.add_computed_column(response=generate_images(tbl.prompt, model='imagen-3.0-generate-002'))
150
+ """
151
+ env.Env.get().require_package('google.genai')
152
+ from google.genai.types import GenerateImagesConfig
153
+
154
+ config_ = GenerateImagesConfig(**config) if config else None
155
+ response = await _genai_client().aio.models.generate_images(model=model, prompt=prompt, config=config_)
156
+ return response.generated_images[0].image._pil_image
157
+
158
+
159
+ @generate_images.resource_pool
160
+ def _(model: str) -> str:
161
+ return f'request-rate:imagen:{model}'
162
+
163
+
164
+ @pxt.udf(resource_pool='request-rate:veo')
165
+ async def generate_videos(
166
+ prompt: Optional[str] = None, image: Optional[PIL.Image.Image] = None, *, model: str, config: Optional[dict] = None
167
+ ) -> pxt.Video:
168
+ """
169
+ Generates videos based on a text description and configuration. For additional details, see:
170
+ <https://ai.google.dev/gemini-api/docs/video-generation>
171
+
172
+ __Requirements:__
173
+
174
+ - `pip install google-genai`
175
+
176
+ Args:
177
+ prompt: A text description of the videos to generate.
178
+ image: An optional image to use as the first frame of the video. At least one of `prompt` or `image` must be
179
+ provided. (It is ok to specify both.)
180
+ model: The model to use.
181
+ config: Configuration for generation, corresponding to keyword arguments of
182
+ `genai.types.GenerateVideosConfig`. For details on the parameters, see:
183
+ <https://googleapis.github.io/python-genai/genai.html#module-genai.types>
184
+
185
+ Returns:
186
+ The generated video.
187
+
188
+ Examples:
189
+ Add a computed column that applies the model `veo-2.0-generate-001`
190
+ to an existing Pixeltable column `tbl.prompt` of the table `tbl`:
191
+
192
+ >>> tbl.add_computed_column(response=generate_videos(tbl.prompt, model='veo-2.0-generate-001'))
193
+ """
194
+ env.Env.get().require_package('google.genai')
195
+ from google.genai import types
196
+
197
+ if prompt is None and image is None:
198
+ raise excs.Error('At least one of `prompt` or `image` must be provided.')
199
+
200
+ image_: Optional[types.Image] = None
201
+ if image is not None:
202
+ with io.BytesIO() as buffer:
203
+ image.save(buffer, format='jpeg')
204
+ image_ = types.Image(image_bytes=buffer.getvalue(), mime_type='image/jpeg')
205
+
206
+ config_ = types.GenerateVideosConfig(**config) if config else None
207
+ operation = await _genai_client().aio.models.generate_videos(
208
+ model=model, prompt=prompt, image=image_, config=config_
209
+ )
210
+ while not operation.done:
211
+ await asyncio.sleep(3)
212
+ operation = await _genai_client().aio.operations.get(operation)
213
+
214
+ video = operation.response.generated_videos[0]
215
+
216
+ video_bytes = await _genai_client().aio.files.download(file=video.video) # type: ignore[arg-type]
217
+ assert video_bytes is not None
218
+
219
+ _, output_filename = tempfile.mkstemp(suffix='.mp4', dir=str(env.Env.get().tmp_dir))
220
+ Path(output_filename).write_bytes(video_bytes)
221
+ return output_filename
222
+
223
+
224
+ @generate_videos.resource_pool
225
+ def _(model: str) -> str:
226
+ return f'request-rate:veo:{model}'
@@ -100,6 +100,69 @@ def _(self: sql.ColumnElement, digits: Optional[sql.ColumnElement] = None) -> sq
100
100
  return sql.func.round(sql.cast(self, sql.Numeric), sql.cast(digits, sql.Integer))
101
101
 
102
102
 
103
+ @pxt.udf(is_method=True)
104
+ def pow(self: int, other: int) -> float:
105
+ """
106
+ Raise `self` to the power of `other`.
107
+
108
+ Equivalent to Python [`self ** other`](https://docs.python.org/3/library/functions.html#pow).
109
+ """
110
+ return self**other
111
+
112
+
113
+ @pow.to_sql
114
+ def _(self: sql.ColumnElement, other: sql.ColumnElement) -> sql.ColumnElement:
115
+ return sql.func.pow(self, other)
116
+
117
+
118
+ @pxt.udf(is_method=True)
119
+ def bitwise_and(self: int, other: int) -> int:
120
+ """
121
+ Bitwise AND of two integers.
122
+
123
+ Equivalent to Python
124
+ [`self & other`](https://docs.python.org/3/library/stdtypes.html#bitwise-operations-on-integer-types).
125
+ """
126
+ return self & other
127
+
128
+
129
+ @bitwise_and.to_sql
130
+ def _(self: sql.ColumnElement, other: sql.ColumnElement) -> sql.ColumnElement:
131
+ return self.bitwise_and(other)
132
+
133
+
134
+ @pxt.udf(is_method=True)
135
+ def bitwise_or(self: int, other: int) -> int:
136
+ """
137
+ Bitwise OR of two integers.
138
+
139
+ Equivalent to Python
140
+ [`self | other`](https://docs.python.org/3/library/stdtypes.html#bitwise-operations-on-integer-types).
141
+ """
142
+ return self | other
143
+
144
+
145
+ @bitwise_or.to_sql
146
+ def _(self: sql.ColumnElement, other: sql.ColumnElement) -> sql.ColumnElement:
147
+ return self.bitwise_or(other)
148
+
149
+
150
+ @pxt.udf(is_method=True)
151
+ def bitwise_xor(self: int, other: int) -> int:
152
+ """
153
+ Bitwise XOR of two integers.
154
+
155
+ Equivalent to Python
156
+ [`self ^ other`](https://docs.python.org/3/library/stdtypes.html#bitwise-operations-on-integer-types).
157
+ """
158
+ return self ^ other
159
+
160
+
161
+ @bitwise_xor.to_sql
162
+ def _(self: sql.ColumnElement, other: sql.ColumnElement) -> sql.ColumnElement:
163
+ return self.bitwise_xor(other)
164
+
165
+
103
166
  __all__ = local_public_names(__name__)
104
167
 
105
168