pixeltable 0.3.14__py3-none-any.whl → 0.5.7__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.
Files changed (220) hide show
  1. pixeltable/__init__.py +42 -8
  2. pixeltable/{dataframe.py → _query.py} +470 -206
  3. pixeltable/_version.py +1 -0
  4. pixeltable/catalog/__init__.py +5 -4
  5. pixeltable/catalog/catalog.py +1785 -432
  6. pixeltable/catalog/column.py +190 -113
  7. pixeltable/catalog/dir.py +2 -4
  8. pixeltable/catalog/globals.py +19 -46
  9. pixeltable/catalog/insertable_table.py +191 -98
  10. pixeltable/catalog/path.py +63 -23
  11. pixeltable/catalog/schema_object.py +11 -15
  12. pixeltable/catalog/table.py +843 -436
  13. pixeltable/catalog/table_metadata.py +103 -0
  14. pixeltable/catalog/table_version.py +978 -657
  15. pixeltable/catalog/table_version_handle.py +72 -16
  16. pixeltable/catalog/table_version_path.py +112 -43
  17. pixeltable/catalog/tbl_ops.py +53 -0
  18. pixeltable/catalog/update_status.py +191 -0
  19. pixeltable/catalog/view.py +134 -90
  20. pixeltable/config.py +134 -22
  21. pixeltable/env.py +471 -157
  22. pixeltable/exceptions.py +6 -0
  23. pixeltable/exec/__init__.py +4 -1
  24. pixeltable/exec/aggregation_node.py +7 -8
  25. pixeltable/exec/cache_prefetch_node.py +83 -110
  26. pixeltable/exec/cell_materialization_node.py +268 -0
  27. pixeltable/exec/cell_reconstruction_node.py +168 -0
  28. pixeltable/exec/component_iteration_node.py +4 -3
  29. pixeltable/exec/data_row_batch.py +8 -65
  30. pixeltable/exec/exec_context.py +16 -4
  31. pixeltable/exec/exec_node.py +13 -36
  32. pixeltable/exec/expr_eval/evaluators.py +11 -7
  33. pixeltable/exec/expr_eval/expr_eval_node.py +27 -12
  34. pixeltable/exec/expr_eval/globals.py +8 -5
  35. pixeltable/exec/expr_eval/row_buffer.py +1 -2
  36. pixeltable/exec/expr_eval/schedulers.py +106 -56
  37. pixeltable/exec/globals.py +35 -0
  38. pixeltable/exec/in_memory_data_node.py +19 -19
  39. pixeltable/exec/object_store_save_node.py +293 -0
  40. pixeltable/exec/row_update_node.py +16 -9
  41. pixeltable/exec/sql_node.py +351 -84
  42. pixeltable/exprs/__init__.py +1 -1
  43. pixeltable/exprs/arithmetic_expr.py +27 -22
  44. pixeltable/exprs/array_slice.py +3 -3
  45. pixeltable/exprs/column_property_ref.py +36 -23
  46. pixeltable/exprs/column_ref.py +213 -89
  47. pixeltable/exprs/comparison.py +5 -5
  48. pixeltable/exprs/compound_predicate.py +5 -4
  49. pixeltable/exprs/data_row.py +164 -54
  50. pixeltable/exprs/expr.py +70 -44
  51. pixeltable/exprs/expr_dict.py +3 -3
  52. pixeltable/exprs/expr_set.py +17 -10
  53. pixeltable/exprs/function_call.py +100 -40
  54. pixeltable/exprs/globals.py +2 -2
  55. pixeltable/exprs/in_predicate.py +4 -4
  56. pixeltable/exprs/inline_expr.py +18 -32
  57. pixeltable/exprs/is_null.py +7 -3
  58. pixeltable/exprs/json_mapper.py +8 -8
  59. pixeltable/exprs/json_path.py +56 -22
  60. pixeltable/exprs/literal.py +27 -5
  61. pixeltable/exprs/method_ref.py +2 -2
  62. pixeltable/exprs/object_ref.py +2 -2
  63. pixeltable/exprs/row_builder.py +167 -67
  64. pixeltable/exprs/rowid_ref.py +25 -10
  65. pixeltable/exprs/similarity_expr.py +58 -40
  66. pixeltable/exprs/sql_element_cache.py +4 -4
  67. pixeltable/exprs/string_op.py +5 -5
  68. pixeltable/exprs/type_cast.py +3 -5
  69. pixeltable/func/__init__.py +1 -0
  70. pixeltable/func/aggregate_function.py +8 -8
  71. pixeltable/func/callable_function.py +9 -9
  72. pixeltable/func/expr_template_function.py +17 -11
  73. pixeltable/func/function.py +18 -20
  74. pixeltable/func/function_registry.py +6 -7
  75. pixeltable/func/globals.py +2 -3
  76. pixeltable/func/mcp.py +74 -0
  77. pixeltable/func/query_template_function.py +29 -27
  78. pixeltable/func/signature.py +46 -19
  79. pixeltable/func/tools.py +31 -13
  80. pixeltable/func/udf.py +18 -20
  81. pixeltable/functions/__init__.py +16 -0
  82. pixeltable/functions/anthropic.py +123 -77
  83. pixeltable/functions/audio.py +147 -10
  84. pixeltable/functions/bedrock.py +13 -6
  85. pixeltable/functions/date.py +7 -4
  86. pixeltable/functions/deepseek.py +35 -43
  87. pixeltable/functions/document.py +81 -0
  88. pixeltable/functions/fal.py +76 -0
  89. pixeltable/functions/fireworks.py +11 -20
  90. pixeltable/functions/gemini.py +195 -39
  91. pixeltable/functions/globals.py +142 -14
  92. pixeltable/functions/groq.py +108 -0
  93. pixeltable/functions/huggingface.py +1056 -24
  94. pixeltable/functions/image.py +115 -57
  95. pixeltable/functions/json.py +1 -1
  96. pixeltable/functions/llama_cpp.py +28 -13
  97. pixeltable/functions/math.py +67 -5
  98. pixeltable/functions/mistralai.py +18 -55
  99. pixeltable/functions/net.py +70 -0
  100. pixeltable/functions/ollama.py +20 -13
  101. pixeltable/functions/openai.py +240 -226
  102. pixeltable/functions/openrouter.py +143 -0
  103. pixeltable/functions/replicate.py +4 -4
  104. pixeltable/functions/reve.py +250 -0
  105. pixeltable/functions/string.py +239 -69
  106. pixeltable/functions/timestamp.py +16 -16
  107. pixeltable/functions/together.py +24 -84
  108. pixeltable/functions/twelvelabs.py +188 -0
  109. pixeltable/functions/util.py +6 -1
  110. pixeltable/functions/uuid.py +30 -0
  111. pixeltable/functions/video.py +1515 -107
  112. pixeltable/functions/vision.py +8 -8
  113. pixeltable/functions/voyageai.py +289 -0
  114. pixeltable/functions/whisper.py +16 -8
  115. pixeltable/functions/whisperx.py +179 -0
  116. pixeltable/{ext/functions → functions}/yolox.py +2 -4
  117. pixeltable/globals.py +362 -115
  118. pixeltable/index/base.py +17 -21
  119. pixeltable/index/btree.py +28 -22
  120. pixeltable/index/embedding_index.py +100 -118
  121. pixeltable/io/__init__.py +4 -2
  122. pixeltable/io/datarows.py +8 -7
  123. pixeltable/io/external_store.py +56 -105
  124. pixeltable/io/fiftyone.py +13 -13
  125. pixeltable/io/globals.py +31 -30
  126. pixeltable/io/hf_datasets.py +61 -16
  127. pixeltable/io/label_studio.py +74 -70
  128. pixeltable/io/lancedb.py +3 -0
  129. pixeltable/io/pandas.py +21 -12
  130. pixeltable/io/parquet.py +25 -105
  131. pixeltable/io/table_data_conduit.py +250 -123
  132. pixeltable/io/utils.py +4 -4
  133. pixeltable/iterators/__init__.py +2 -1
  134. pixeltable/iterators/audio.py +26 -25
  135. pixeltable/iterators/base.py +9 -3
  136. pixeltable/iterators/document.py +112 -78
  137. pixeltable/iterators/image.py +12 -15
  138. pixeltable/iterators/string.py +11 -4
  139. pixeltable/iterators/video.py +523 -120
  140. pixeltable/metadata/__init__.py +14 -3
  141. pixeltable/metadata/converters/convert_13.py +2 -2
  142. pixeltable/metadata/converters/convert_18.py +2 -2
  143. pixeltable/metadata/converters/convert_19.py +2 -2
  144. pixeltable/metadata/converters/convert_20.py +2 -2
  145. pixeltable/metadata/converters/convert_21.py +2 -2
  146. pixeltable/metadata/converters/convert_22.py +2 -2
  147. pixeltable/metadata/converters/convert_24.py +2 -2
  148. pixeltable/metadata/converters/convert_25.py +2 -2
  149. pixeltable/metadata/converters/convert_26.py +2 -2
  150. pixeltable/metadata/converters/convert_29.py +4 -4
  151. pixeltable/metadata/converters/convert_30.py +34 -21
  152. pixeltable/metadata/converters/convert_34.py +2 -2
  153. pixeltable/metadata/converters/convert_35.py +9 -0
  154. pixeltable/metadata/converters/convert_36.py +38 -0
  155. pixeltable/metadata/converters/convert_37.py +15 -0
  156. pixeltable/metadata/converters/convert_38.py +39 -0
  157. pixeltable/metadata/converters/convert_39.py +124 -0
  158. pixeltable/metadata/converters/convert_40.py +73 -0
  159. pixeltable/metadata/converters/convert_41.py +12 -0
  160. pixeltable/metadata/converters/convert_42.py +9 -0
  161. pixeltable/metadata/converters/convert_43.py +44 -0
  162. pixeltable/metadata/converters/util.py +20 -31
  163. pixeltable/metadata/notes.py +9 -0
  164. pixeltable/metadata/schema.py +140 -53
  165. pixeltable/metadata/utils.py +74 -0
  166. pixeltable/mypy/__init__.py +3 -0
  167. pixeltable/mypy/mypy_plugin.py +123 -0
  168. pixeltable/plan.py +382 -115
  169. pixeltable/share/__init__.py +1 -1
  170. pixeltable/share/packager.py +547 -83
  171. pixeltable/share/protocol/__init__.py +33 -0
  172. pixeltable/share/protocol/common.py +165 -0
  173. pixeltable/share/protocol/operation_types.py +33 -0
  174. pixeltable/share/protocol/replica.py +119 -0
  175. pixeltable/share/publish.py +257 -59
  176. pixeltable/store.py +311 -194
  177. pixeltable/type_system.py +373 -211
  178. pixeltable/utils/__init__.py +2 -3
  179. pixeltable/utils/arrow.py +131 -17
  180. pixeltable/utils/av.py +298 -0
  181. pixeltable/utils/azure_store.py +346 -0
  182. pixeltable/utils/coco.py +6 -6
  183. pixeltable/utils/code.py +3 -3
  184. pixeltable/utils/console_output.py +4 -1
  185. pixeltable/utils/coroutine.py +6 -23
  186. pixeltable/utils/dbms.py +32 -6
  187. pixeltable/utils/description_helper.py +4 -5
  188. pixeltable/utils/documents.py +7 -18
  189. pixeltable/utils/exception_handler.py +7 -30
  190. pixeltable/utils/filecache.py +6 -6
  191. pixeltable/utils/formatter.py +86 -48
  192. pixeltable/utils/gcs_store.py +295 -0
  193. pixeltable/utils/http.py +133 -0
  194. pixeltable/utils/http_server.py +2 -3
  195. pixeltable/utils/iceberg.py +1 -2
  196. pixeltable/utils/image.py +17 -0
  197. pixeltable/utils/lancedb.py +90 -0
  198. pixeltable/utils/local_store.py +322 -0
  199. pixeltable/utils/misc.py +5 -0
  200. pixeltable/utils/object_stores.py +573 -0
  201. pixeltable/utils/pydantic.py +60 -0
  202. pixeltable/utils/pytorch.py +5 -6
  203. pixeltable/utils/s3_store.py +527 -0
  204. pixeltable/utils/sql.py +26 -0
  205. pixeltable/utils/system.py +30 -0
  206. pixeltable-0.5.7.dist-info/METADATA +579 -0
  207. pixeltable-0.5.7.dist-info/RECORD +227 -0
  208. {pixeltable-0.3.14.dist-info → pixeltable-0.5.7.dist-info}/WHEEL +1 -1
  209. pixeltable-0.5.7.dist-info/entry_points.txt +2 -0
  210. pixeltable/__version__.py +0 -3
  211. pixeltable/catalog/named_function.py +0 -40
  212. pixeltable/ext/__init__.py +0 -17
  213. pixeltable/ext/functions/__init__.py +0 -11
  214. pixeltable/ext/functions/whisperx.py +0 -77
  215. pixeltable/utils/media_store.py +0 -77
  216. pixeltable/utils/s3.py +0 -17
  217. pixeltable-0.3.14.dist-info/METADATA +0 -434
  218. pixeltable-0.3.14.dist-info/RECORD +0 -186
  219. pixeltable-0.3.14.dist-info/entry_points.txt +0 -3
  220. {pixeltable-0.3.14.dist-info → pixeltable-0.5.7.dist-info/licenses}/LICENSE +0 -0
@@ -1,5 +1,5 @@
1
1
  """
2
- Pixeltable [UDFs](https://pixeltable.readme.io/docs/user-defined-functions-udfs) for `ImageType`.
2
+ Pixeltable UDFs for `ImageType`.
3
3
 
4
4
  Example:
5
5
  ```python
@@ -10,8 +10,7 @@ t.select(t.img_col.convert('L')).collect()
10
10
  ```
11
11
  """
12
12
 
13
- import base64
14
- from typing import Optional
13
+ from typing import Any, Literal
15
14
 
16
15
  import PIL.Image
17
16
 
@@ -19,6 +18,7 @@ import pixeltable as pxt
19
18
  import pixeltable.type_system as ts
20
19
  from pixeltable.exprs import Expr
21
20
  from pixeltable.utils.code import local_public_names
21
+ from pixeltable.utils.image import to_base64
22
22
 
23
23
 
24
24
  @pxt.udf(is_method=True)
@@ -30,42 +30,37 @@ def b64_encode(img: PIL.Image.Image, image_format: str = 'png') -> str:
30
30
  img: image
31
31
  image_format: image format [supported by PIL](https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#fully-supported-formats)
32
32
  """
33
- import io
33
+ return to_base64(img, format=image_format)
34
34
 
35
- bytes_arr = io.BytesIO()
36
- img.save(bytes_arr, format=image_format)
37
- b64_bytes = base64.b64encode(bytes_arr.getvalue())
38
- return b64_bytes.decode('utf-8')
39
35
 
40
-
41
- @pxt.udf(substitute_fn=PIL.Image.alpha_composite, is_method=True)
36
+ @pxt.udf(is_method=True)
42
37
  def alpha_composite(im1: PIL.Image.Image, im2: PIL.Image.Image) -> PIL.Image.Image:
43
38
  """
44
39
  Alpha composite `im2` over `im1`.
45
40
 
46
41
  Equivalent to [`PIL.Image.alpha_composite()`](https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.alpha_composite)
47
42
  """
48
- pass
43
+ return PIL.Image.alpha_composite(im1, im2)
49
44
 
50
45
 
51
- @pxt.udf(substitute_fn=PIL.Image.blend, is_method=True)
46
+ @pxt.udf(is_method=True)
52
47
  def blend(im1: PIL.Image.Image, im2: PIL.Image.Image, alpha: float) -> PIL.Image.Image:
53
48
  """
54
49
  Return a new image by interpolating between two input images, using a constant alpha.
55
50
 
56
51
  Equivalent to [`PIL.Image.blend()`](https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.blend)
57
52
  """
58
- pass
53
+ return PIL.Image.blend(im1, im2, alpha)
59
54
 
60
55
 
61
- @pxt.udf(substitute_fn=PIL.Image.composite, is_method=True)
56
+ @pxt.udf(is_method=True)
62
57
  def composite(image1: PIL.Image.Image, image2: PIL.Image.Image, mask: PIL.Image.Image) -> PIL.Image.Image:
63
58
  """
64
59
  Return a composite image by blending two images using a mask.
65
60
 
66
61
  Equivalent to [`PIL.Image.composite()`](https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.composite)
67
62
  """
68
- pass
63
+ return PIL.Image.composite(image1, image2, mask)
69
64
 
70
65
 
71
66
  # PIL.Image.Image methods
@@ -96,7 +91,7 @@ def _(self: Expr, mode: str) -> ts.ColumnType:
96
91
 
97
92
 
98
93
  # Image.crop()
99
- @pxt.udf(substitute_fn=PIL.Image.Image.crop, is_method=True)
94
+ @pxt.udf(is_method=True)
100
95
  def crop(self: PIL.Image.Image, box: tuple[int, int, int, int]) -> PIL.Image.Image:
101
96
  """
102
97
  Return a rectangular region from the image. The box is a 4-tuple defining the left, upper, right, and lower pixel
@@ -105,7 +100,7 @@ def crop(self: PIL.Image.Image, box: tuple[int, int, int, int]) -> PIL.Image.Ima
105
100
  Equivalent to
106
101
  [`PIL.Image.Image.crop()`](https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.crop)
107
102
  """
108
- pass
103
+ return self.crop(box)
109
104
 
110
105
 
111
106
  @crop.conditional_return_type
@@ -118,7 +113,7 @@ def _(self: Expr, box: tuple[int, int, int, int]) -> ts.ColumnType:
118
113
 
119
114
 
120
115
  # Image.getchannel()
121
- @pxt.udf(substitute_fn=PIL.Image.Image.getchannel, is_method=True)
116
+ @pxt.udf(is_method=True)
122
117
  def getchannel(self: PIL.Image.Image, channel: int) -> PIL.Image.Image:
123
118
  """
124
119
  Return an L-mode image containing a single channel of the original image.
@@ -129,7 +124,7 @@ def getchannel(self: PIL.Image.Image, channel: int) -> PIL.Image.Image:
129
124
  Args:
130
125
  channel: The channel to extract. This is a 0-based index.
131
126
  """
132
- pass
127
+ return self.getchannel(channel)
133
128
 
134
129
 
135
130
  @getchannel.conditional_return_type
@@ -156,7 +151,7 @@ def get_metadata(self: PIL.Image.Image) -> dict:
156
151
 
157
152
  # Image.point()
158
153
  @pxt.udf(is_method=True)
159
- def point(self: PIL.Image.Image, lut: list[int], mode: Optional[str] = None) -> PIL.Image.Image:
154
+ def point(self: PIL.Image.Image, lut: list[int], mode: str | None = None) -> PIL.Image.Image:
160
155
  """
161
156
  Map image pixels through a lookup table.
162
157
 
@@ -203,7 +198,7 @@ def rotate(self: PIL.Image.Image, angle: int) -> PIL.Image.Image:
203
198
  return self.rotate(angle)
204
199
 
205
200
 
206
- @pxt.udf(substitute_fn=PIL.Image.Image.effect_spread, is_method=True)
201
+ @pxt.udf(is_method=True)
207
202
  def effect_spread(self: PIL.Image.Image, distance: int) -> PIL.Image.Image:
208
203
  """
209
204
  Randomly spread pixels in an image.
@@ -214,11 +209,11 @@ def effect_spread(self: PIL.Image.Image, distance: int) -> PIL.Image.Image:
214
209
  Args:
215
210
  distance: The distance to spread pixels.
216
211
  """
217
- pass
212
+ return self.effect_spread(distance)
218
213
 
219
214
 
220
- @pxt.udf(substitute_fn=PIL.Image.Image.transpose, is_method=True)
221
- def transpose(self: PIL.Image.Image, method: int) -> PIL.Image.Image:
215
+ @pxt.udf(is_method=True)
216
+ def transpose(self: PIL.Image.Image, method: Literal[0, 1, 2, 3, 4, 5, 6]) -> PIL.Image.Image:
222
217
  """
223
218
  Transpose the image.
224
219
 
@@ -230,7 +225,7 @@ def transpose(self: PIL.Image.Image, method: int) -> PIL.Image.Image:
230
225
  [Pillow documentation](https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.transpose)
231
226
  for a list of supported methods.
232
227
  """
233
- pass
228
+ return self.transpose(method)
234
229
 
235
230
 
236
231
  @rotate.conditional_return_type
@@ -240,8 +235,8 @@ def _(self: Expr) -> ts.ColumnType:
240
235
  return self.col_type
241
236
 
242
237
 
243
- @pxt.udf(substitute_fn=PIL.Image.Image.entropy, is_method=True)
244
- def entropy(self: PIL.Image.Image, mask: Optional[PIL.Image.Image] = None, extrema: Optional[list] = None) -> float:
238
+ @pxt.udf(is_method=True)
239
+ def entropy(self: PIL.Image.Image, mask: PIL.Image.Image | None = None, extrema: list | None = None) -> float:
245
240
  """
246
241
  Returns the entropy of the image, optionally using a mask and extrema.
247
242
 
@@ -252,22 +247,22 @@ def entropy(self: PIL.Image.Image, mask: Optional[PIL.Image.Image] = None, extre
252
247
  mask: An optional mask image.
253
248
  extrema: An optional list of extrema.
254
249
  """
255
- pass
250
+ return self.entropy(mask, extrema) # type: ignore[arg-type]
256
251
 
257
252
 
258
- @pxt.udf(substitute_fn=PIL.Image.Image.getbands, is_method=True)
259
- def getbands(self: PIL.Image.Image) -> tuple[str]:
253
+ @pxt.udf(is_method=True)
254
+ def getbands(self: PIL.Image.Image) -> tuple[str, ...]:
260
255
  """
261
256
  Return a tuple containing the names of the image bands.
262
257
 
263
258
  Equivalent to
264
259
  [`PIL.Image.Image.getbands()`](https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.getbands)
265
260
  """
266
- pass
261
+ return self.getbands()
267
262
 
268
263
 
269
- @pxt.udf(substitute_fn=PIL.Image.Image.getbbox, is_method=True)
270
- def getbbox(self: PIL.Image.Image, *, alpha_only: bool = True) -> tuple[int, int, int, int]:
264
+ @pxt.udf(is_method=True)
265
+ def getbbox(self: PIL.Image.Image, *, alpha_only: bool = True) -> tuple[int, int, int, int] | None:
271
266
  """
272
267
  Return a bounding box for the non-zero regions of the image.
273
268
 
@@ -277,11 +272,11 @@ def getbbox(self: PIL.Image.Image, *, alpha_only: bool = True) -> tuple[int, int
277
272
  alpha_only: If `True`, and the image has an alpha channel, trim transparent pixels. Otherwise,
278
273
  trim pixels when all channels are zero.
279
274
  """
280
- pass
275
+ return self.getbbox(alpha_only=alpha_only)
281
276
 
282
277
 
283
- @pxt.udf(substitute_fn=PIL.Image.Image.getcolors, is_method=True)
284
- def getcolors(self: PIL.Image.Image, maxcolors: int = 256) -> tuple[tuple[int, int, int], int]:
278
+ @pxt.udf(is_method=True)
279
+ def getcolors(self: PIL.Image.Image, maxcolors: int = 256) -> list[tuple[int, int]]:
285
280
  """
286
281
  Return a list of colors used in the image, up to a maximum of `maxcolors`.
287
282
 
@@ -291,10 +286,10 @@ def getcolors(self: PIL.Image.Image, maxcolors: int = 256) -> tuple[tuple[int, i
291
286
  Args:
292
287
  maxcolors: The maximum number of colors to return.
293
288
  """
294
- pass
289
+ return self.getcolors(maxcolors)
295
290
 
296
291
 
297
- @pxt.udf(substitute_fn=PIL.Image.Image.getextrema, is_method=True)
292
+ @pxt.udf(is_method=True)
298
293
  def getextrema(self: PIL.Image.Image) -> tuple[int, int]:
299
294
  """
300
295
  Return a 2-tuple containing the minimum and maximum pixel values of the image.
@@ -302,11 +297,11 @@ def getextrema(self: PIL.Image.Image) -> tuple[int, int]:
302
297
  Equivalent to
303
298
  [`PIL.Image.Image.getextrema()`](https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.getextrema)
304
299
  """
305
- pass
300
+ return self.getextrema()
306
301
 
307
302
 
308
- @pxt.udf(substitute_fn=PIL.Image.Image.getpalette, is_method=True)
309
- def getpalette(self: PIL.Image.Image, mode: Optional[str] = None) -> tuple[int]:
303
+ @pxt.udf(is_method=True)
304
+ def getpalette(self: PIL.Image.Image, mode: str | None = None) -> list[int] | None:
310
305
  """
311
306
  Return the palette of the image, optionally converting it to a different mode.
312
307
 
@@ -316,7 +311,7 @@ def getpalette(self: PIL.Image.Image, mode: Optional[str] = None) -> tuple[int]:
316
311
  Args:
317
312
  mode: The mode to convert the palette to.
318
313
  """
319
- pass
314
+ return self.getpalette(mode)
320
315
 
321
316
 
322
317
  @pxt.udf(is_method=True)
@@ -334,21 +329,19 @@ def getpixel(self: PIL.Image.Image, xy: list) -> tuple[int]:
334
329
  return self.getpixel(tuple(xy))
335
330
 
336
331
 
337
- @pxt.udf(substitute_fn=PIL.Image.Image.getprojection, is_method=True)
338
- def getprojection(self: PIL.Image.Image) -> tuple[int]:
332
+ @pxt.udf(is_method=True)
333
+ def getprojection(self: PIL.Image.Image) -> tuple[list[int], list[int]]:
339
334
  """
340
335
  Return two sequences representing the horizontal and vertical projection of the image.
341
336
 
342
337
  Equivalent to
343
338
  [`PIL.Image.Image.getprojection()`](https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.getprojection)
344
339
  """
345
- pass
340
+ return self.getprojection()
346
341
 
347
342
 
348
- @pxt.udf(substitute_fn=PIL.Image.Image.histogram, is_method=True)
349
- def histogram(
350
- self: PIL.Image.Image, mask: Optional[PIL.Image.Image] = None, extrema: Optional[list] = None
351
- ) -> list[int]:
343
+ @pxt.udf(is_method=True)
344
+ def histogram(self: PIL.Image.Image, mask: PIL.Image.Image | None = None, extrema: list | None = None) -> list[int]:
352
345
  """
353
346
  Return a histogram for the image.
354
347
 
@@ -359,16 +352,16 @@ def histogram(
359
352
  mask: An optional mask image.
360
353
  extrema: An optional list of extrema.
361
354
  """
362
- pass
355
+ return self.histogram(mask, extrema) # type: ignore[arg-type]
363
356
 
364
357
 
365
- @pxt.udf(substitute_fn=PIL.Image.Image.quantize, is_method=True)
358
+ @pxt.udf(is_method=True)
366
359
  def quantize(
367
360
  self: PIL.Image.Image,
368
361
  colors: int = 256,
369
- method: Optional[int] = None,
362
+ method: Literal[0, 1, 2, 3] | None = None,
370
363
  kmeans: int = 0,
371
- palette: Optional[int] = None,
364
+ palette: PIL.Image.Image | None = None,
372
365
  dither: int = PIL.Image.Dither.FLOYDSTEINBERG,
373
366
  ) -> PIL.Image.Image:
374
367
  """
@@ -388,11 +381,11 @@ def quantize(
388
381
  [Pillow documentation](https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.quantize)
389
382
  for a list of supported methods.
390
383
  """
391
- pass
384
+ return self.quantize(colors, method, kmeans, palette, dither)
392
385
 
393
386
 
394
- @pxt.udf(substitute_fn=PIL.Image.Image.reduce, is_method=True)
395
- def reduce(self: PIL.Image.Image, factor: int, box: Optional[tuple[int, int, int, int]] = None) -> PIL.Image.Image:
387
+ @pxt.udf(is_method=True)
388
+ def reduce(self: PIL.Image.Image, factor: int, box: tuple[int, int, int, int] | None = None) -> PIL.Image.Image:
396
389
  """
397
390
  Reduce the image by the given factor.
398
391
 
@@ -404,24 +397,89 @@ def reduce(self: PIL.Image.Image, factor: int, box: Optional[tuple[int, int, int
404
397
  box: An optional 4-tuple of ints providing the source image region to be reduced. The values must be within
405
398
  (0, 0, width, height) rectangle. If omitted or None, the entire source is used.
406
399
  """
407
- pass
400
+ return self.reduce(factor, box)
401
+
402
+
403
+ @pxt.udf(is_method=True)
404
+ def thumbnail(
405
+ self: PIL.Image.Image,
406
+ size: tuple[int, int],
407
+ resample: int = PIL.Image.Resampling.LANCZOS,
408
+ reducing_gap: float | None = 2.0,
409
+ ) -> PIL.Image.Image:
410
+ """
411
+ Create a thumbnail of the image.
412
+
413
+ Equivalent to
414
+ [`PIL.Image.Image.thumbnail()`](https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.thumbnail)
415
+
416
+ Args:
417
+ size: The size of the thumbnail, as a tuple of (width, height).
418
+ resample: The resampling filter to use. See the
419
+ [Pillow documentation](https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.thumbnail)
420
+ for a list of supported filters.
421
+ reducing_gap: The reducing gap to use.
422
+ """
423
+ result = self.copy()
424
+ result.thumbnail(size, PIL.Image.Resampling(resample), reducing_gap)
425
+ return result
408
426
 
409
427
 
410
428
  @pxt.udf(is_property=True)
411
429
  def width(self: PIL.Image.Image) -> int:
430
+ """
431
+ Return the width of the image.
432
+ """
412
433
  return self.width
413
434
 
414
435
 
415
436
  @pxt.udf(is_property=True)
416
437
  def height(self: PIL.Image.Image) -> int:
438
+ """
439
+ Return the height of the image.
440
+ """
417
441
  return self.height
418
442
 
419
443
 
420
444
  @pxt.udf(is_property=True)
421
445
  def mode(self: PIL.Image.Image) -> str:
446
+ """
447
+ Return the image mode.
448
+ """
422
449
  return self.mode
423
450
 
424
451
 
452
+ def tile_iterator(
453
+ image: Any, tile_size: tuple[int, int], *, overlap: tuple[int, int] = (0, 0)
454
+ ) -> tuple[type[pxt.iterators.ComponentIterator], dict[str, Any]]:
455
+ """
456
+ Iterator over tiles of an image. Each image will be divided into tiles of size `tile_size`, and the tiles will be
457
+ iterated over in row-major order (left-to-right, then top-to-bottom). An optional `overlap` parameter may be
458
+ specified. If the tiles do not exactly cover the image, then the rightmost and bottommost tiles will be padded with
459
+ blackspace, so that the output images all have the exact size `tile_size`.
460
+
461
+ Args:
462
+ image: Image to split into tiles.
463
+ tile_size: Size of each tile, as a pair of integers `[width, height]`.
464
+ overlap: Amount of overlap between adjacent tiles, as a pair of integers `[width, height]`.
465
+
466
+ Examples:
467
+ This example assumes an existing table `tbl` with a column `img` of type `pxt.Image`.
468
+
469
+ Create a view that splits all images into 256x256 tiles with 32 pixels of overlap:
470
+
471
+ >>> pxt.create_view(
472
+ ... 'image_tiles',
473
+ ... tbl,
474
+ ... iterator=image_tile_iterator(tbl.img, tile_size=(256, 256), overlap=(32, 32))
475
+ ... )
476
+ """
477
+ kwargs: dict[str, Any] = {}
478
+ if overlap != (0, 0):
479
+ kwargs['overlap'] = overlap
480
+ return pxt.iterators.image.TileIterator._create(image=image, tile_size=tile_size, **kwargs)
481
+
482
+
425
483
  __all__ = local_public_names(__name__)
426
484
 
427
485
 
@@ -1,5 +1,5 @@
1
1
  """
2
- Pixeltable [UDFs](https://pixeltable.readme.io/docs/user-defined-functions-udfs) for `JsonType`.
2
+ Pixeltable UDFs for `JsonType`.
3
3
 
4
4
  Example:
5
5
  ```python
@@ -1,5 +1,12 @@
1
+ """
2
+ Pixeltable UDFs for llama.cpp models.
3
+
4
+ Provides integration with llama.cpp for running quantized language models locally,
5
+ supporting chat completions and embeddings with GGUF format models.
6
+ """
7
+
1
8
  from pathlib import Path
2
- from typing import TYPE_CHECKING, Any, Optional
9
+ from typing import TYPE_CHECKING, Any
3
10
 
4
11
  import pixeltable as pxt
5
12
  import pixeltable.exceptions as excs
@@ -14,10 +21,10 @@ if TYPE_CHECKING:
14
21
  def create_chat_completion(
15
22
  messages: list[dict],
16
23
  *,
17
- model_path: Optional[str] = None,
18
- repo_id: Optional[str] = None,
19
- repo_filename: Optional[str] = None,
20
- args: Optional[dict[str, Any]] = None,
24
+ model_path: str | None = None,
25
+ repo_id: str | None = None,
26
+ repo_filename: str | None = None,
27
+ model_kwargs: dict[str, Any] | None = None,
21
28
  ) -> dict:
22
29
  """
23
30
  Generate a chat completion from a list of messages.
@@ -35,14 +42,14 @@ def create_chat_completion(
35
42
  repo_id: The Hugging Face model repo id (if using a pretrained model).
36
43
  repo_filename: A filename or glob pattern to match the model file in the repo (optional, if using a
37
44
  pretrained model).
38
- args: Additional arguments to pass to the `create_chat_completions` call, such as `max_tokens`, `temperature`,
39
- `top_p`, and `top_k`. For details, see the
45
+ model_kwargs: Additional keyword args for the llama_cpp `create_chat_completions` API, such as `max_tokens`,
46
+ `temperature`, `top_p`, and `top_k`. For details, see the
40
47
  [llama_cpp create_chat_completions documentation](https://llama-cpp-python.readthedocs.io/en/latest/api-reference/#llama_cpp.Llama.create_chat_completion).
41
48
  """
42
49
  Env.get().require_package('llama_cpp', min_version=[0, 3, 1])
43
50
 
44
- if args is None:
45
- args = {}
51
+ if model_kwargs is None:
52
+ model_kwargs = {}
46
53
 
47
54
  if (model_path is None) == (repo_id is None):
48
55
  raise excs.Error('Exactly one of `model_path` or `repo_id` must be provided.')
@@ -56,7 +63,7 @@ def create_chat_completion(
56
63
  else:
57
64
  Env.get().require_package('huggingface_hub')
58
65
  llm = _lookup_pretrained_model(repo_id, repo_filename, n_gpu_layers)
59
- return llm.create_chat_completion(messages, **args) # type: ignore
66
+ return llm.create_chat_completion(messages, **model_kwargs) # type: ignore
60
67
 
61
68
 
62
69
  def _is_gpu_available() -> bool:
@@ -81,7 +88,7 @@ def _lookup_local_model(model_path: str, n_gpu_layers: int) -> 'llama_cpp.Llama'
81
88
  return _model_cache[key]
82
89
 
83
90
 
84
- def _lookup_pretrained_model(repo_id: str, filename: Optional[str], n_gpu_layers: int) -> 'llama_cpp.Llama':
91
+ def _lookup_pretrained_model(repo_id: str, filename: str | None, n_gpu_layers: int) -> 'llama_cpp.Llama':
85
92
  import llama_cpp
86
93
 
87
94
  key = (repo_id, filename, n_gpu_layers)
@@ -93,8 +100,16 @@ def _lookup_pretrained_model(repo_id: str, filename: Optional[str], n_gpu_layers
93
100
  return _model_cache[key]
94
101
 
95
102
 
96
- _model_cache: dict[tuple[str, str, int], Any] = {}
97
- _IS_GPU_AVAILABLE: Optional[bool] = None
103
+ _model_cache: dict[tuple[str, str, int], 'llama_cpp.Llama'] = {}
104
+ _IS_GPU_AVAILABLE: bool | None = None
105
+
106
+
107
+ def cleanup() -> None:
108
+ for model in _model_cache.values():
109
+ if model._sampler is not None:
110
+ model._sampler.close()
111
+ model.close()
112
+ _model_cache.clear()
98
113
 
99
114
 
100
115
  __all__ = local_public_names(__name__)
@@ -1,5 +1,5 @@
1
1
  """
2
- Pixeltable [UDFs](https://pixeltable.readme.io/docs/user-defined-functions-udfs) for mathematical operations.
2
+ Pixeltable UDFs for mathematical operations.
3
3
 
4
4
  Example:
5
5
  ```python
@@ -12,7 +12,6 @@ t.select(t.float_col.floor()).collect()
12
12
 
13
13
  import builtins
14
14
  import math
15
- from typing import Optional
16
15
 
17
16
  import sqlalchemy as sql
18
17
 
@@ -80,7 +79,7 @@ def _(self: sql.ColumnElement) -> sql.ColumnElement:
80
79
 
81
80
 
82
81
  @pxt.udf(is_method=True)
83
- def round(self: float, digits: Optional[int] = None) -> float:
82
+ def round(self: float, digits: int | None = None) -> float:
84
83
  """
85
84
  Round a number to a given precision in decimal digits.
86
85
 
@@ -93,11 +92,74 @@ def round(self: float, digits: Optional[int] = None) -> float:
93
92
 
94
93
 
95
94
  @round.to_sql
96
- def _(self: sql.ColumnElement, digits: Optional[sql.ColumnElement] = None) -> sql.ColumnElement:
95
+ def _(self: sql.ColumnElement, digits: sql.ColumnElement | None = None) -> sql.ColumnElement:
97
96
  if digits is None:
98
97
  return sql.func.round(self)
99
98
  else:
100
- return sql.func.round(sql.cast(self, sql.Numeric), sql.cast(digits, sql.Integer))
99
+ return sql.cast(sql.func.round(sql.cast(self, sql.Numeric), sql.cast(digits, sql.Integer)), sql.Float)
100
+
101
+
102
+ @pxt.udf(is_method=True)
103
+ def pow(self: int, other: int) -> float:
104
+ """
105
+ Raise `self` to the power of `other`.
106
+
107
+ Equivalent to Python [`self ** other`](https://docs.python.org/3/library/functions.html#pow).
108
+ """
109
+ return self**other
110
+
111
+
112
+ @pow.to_sql
113
+ def _(self: sql.ColumnElement, other: sql.ColumnElement) -> sql.ColumnElement:
114
+ return sql.func.pow(self, other)
115
+
116
+
117
+ @pxt.udf(is_method=True)
118
+ def bitwise_and(self: int, other: int) -> int:
119
+ """
120
+ Bitwise AND of two integers.
121
+
122
+ Equivalent to Python
123
+ [`self & other`](https://docs.python.org/3/library/stdtypes.html#bitwise-operations-on-integer-types).
124
+ """
125
+ return self & other
126
+
127
+
128
+ @bitwise_and.to_sql
129
+ def _(self: sql.ColumnElement, other: sql.ColumnElement) -> sql.ColumnElement:
130
+ return self.bitwise_and(other)
131
+
132
+
133
+ @pxt.udf(is_method=True)
134
+ def bitwise_or(self: int, other: int) -> int:
135
+ """
136
+ Bitwise OR of two integers.
137
+
138
+ Equivalent to Python
139
+ [`self | other`](https://docs.python.org/3/library/stdtypes.html#bitwise-operations-on-integer-types).
140
+ """
141
+ return self | other
142
+
143
+
144
+ @bitwise_or.to_sql
145
+ def _(self: sql.ColumnElement, other: sql.ColumnElement) -> sql.ColumnElement:
146
+ return self.bitwise_or(other)
147
+
148
+
149
+ @pxt.udf(is_method=True)
150
+ def bitwise_xor(self: int, other: int) -> int:
151
+ """
152
+ Bitwise XOR of two integers.
153
+
154
+ Equivalent to Python
155
+ [`self ^ other`](https://docs.python.org/3/library/stdtypes.html#bitwise-operations-on-integer-types).
156
+ """
157
+ return self ^ other
158
+
159
+
160
+ @bitwise_xor.to_sql
161
+ def _(self: sql.ColumnElement, other: sql.ColumnElement) -> sql.ColumnElement:
162
+ return self.bitwise_xor(other)
101
163
 
102
164
 
103
165
  __all__ = local_public_names(__name__)