diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ddeb5633f..07f05262f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -113,7 +113,7 @@ jobs: - name: Install dependencies working-directory: ./projects/pgai - run: uv sync + run: uv sync --all-extras - name: Lint run: just pgai lint diff --git a/docs/python-integration.md b/docs/python-integration.md new file mode 100644 index 000000000..4b92ddcd5 --- /dev/null +++ b/docs/python-integration.md @@ -0,0 +1,184 @@ +# SQLAlchemy Integration with pgai Vectorizer + +The `vectorizer_relationship` is a SQLAlchemy helper that integrates pgai's vectorization capabilities directly into your SQLAlchemy models. +Think of it as a normal SQLAlchemy [relationship](https://docs.sqlalchemy.org/en/20/orm/basic_relationships.html), but with a preconfigured model instance under the hood. +This allows you to easily query vector embeddings created by pgai using familiar SQLAlchemy patterns. + +## Installation + +To use the SQLAlchemy integration, install pgai with the SQLAlchemy extras: + +```bash +pip install "pgai[sqlalchemy]" +``` + +## Basic Usage + +Here's a basic example of how to use the `vectorizer_relationship`: + +```python +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column +from pgai.sqlalchemy import vectorizer_relationship + +class Base(DeclarativeBase): + pass + +class BlogPost(Base): + __tablename__ = "blog_posts" + + id: Mapped[int] = mapped_column(primary_key=True) + title: Mapped[str] + content: Mapped[str] + + # Add vector embeddings for the content field + content_embeddings = vectorizer_relationship( + dimensions=768 + ) +``` +Note if you work with alembics autogenerate functionality for migrations, also check [Working with alembic](#working-with-alembic). + +### Semantic Search + +You can then perform semantic similarity search on the field using [pgvector-python's](https://github.com/pgvector/pgvector-python) distance functions: + +```python +from sqlalchemy import func, text + +similar_posts = ( + session.query(BlogPost.content_embeddings) + .order_by( + BlogPost.content_embeddings.embedding.cosine_distance( + func.ai.openai_embed( + "text-embedding-3-small", + "search query", + text("dimensions => 768") + ) + ) + ) + .limit(5) + .all() +) +``` + +Or if you already have the embeddings in your application: + +```python +similar_posts = ( + session.query(BlogPost.content_embeddings) + .order_by( + BlogPost.content_embeddings.embedding.cosine_distance( + [3, 1, 2] + ) + ) + .limit(5) + .all() +) +``` + +## Configuration + +The `vectorizer_relationship` accepts the following parameters: + +- `dimensions` (int): The size of the embedding vector (required) +- `target_schema` (str, optional): Override the schema for the embeddings table. If not provided, inherits from the parent model's schema +- `target_table` (str, optional): Override the table name for embeddings. Default is `{table_name}_embedding_store` + +Additional parameters are simply forwarded to the underlying [SQLAlchemy relationship](https://docs.sqlalchemy.org/en/20/orm/relationships.html) so you can configure it as you desire. + +Think of the `vectorizer_relationship` as a normal SQLAlchemy relationship, but with a preconfigured model instance under the hood. + + +## Setting up the Vectorizer + +After defining your model, you need to create the vectorizer using pgai's SQL functions: + +```sql +SELECT ai.create_vectorizer( + 'blog_posts'::regclass, + embedding => ai.embedding_openai('text-embedding-3-small', 768), + chunking => ai.chunking_recursive_character_text_splitter( + 'content', + 50, -- chunk_size + 10 -- chunk_overlap + ) +); +``` + +We recommend adding this to a migration script and run it via alembic. + + +## Querying Embeddings + +The `vectorizer_relationship` provides several ways to work with embeddings: + +### 1. Direct Access to Embeddings + +If you access the class proeprty of your model the `vectorizer_relationship` provide a SQLAlchemy model that you can query directly: + +```python +# Get all embeddings +embeddings = session.query(BlogPost.content_embeddings).all() + +# Access embedding properties +for embedding in embeddings: + print(embedding.embedding) # The vector embedding + print(embedding.chunk) # The text chunk +``` +The model will have the primary key fields of the parent model as well as the following fields: +- `chunk` (str): The text chunk that was embedded +- `embedding` (Vector): The vector embedding +- `chunk_seq` (int): The sequence number of the chunk +- `embedding_uuid` (str): The UUID of the embedding +- `parent` (ParentModel): The parent model instance + +### 2. Relationship Access + + +```python +blog_post = session.query(BlogPost).first() +for embedding in blog_post.content_embeddings: + print(embedding.chunk) +``` +Access the original posts through the parent relationship +```python +for embedding in similar_posts: + print(embedding.parent.title) +``` + +### 3. Join Queries + +You can combine embedding queries with regular SQL queries using the relationship: + +```python +results = ( + session.query(BlogPost, BlogPost.content_embeddings) + .join(BlogPost.content_embeddings) + .filter(BlogPost.title.ilike("%search term%")) + .all() +) + +for post, embedding in results: + print(f"Title: {post.title}") + print(f"Chunk: {embedding.chunk}") +``` + +## Working with alembic + + +The `vectorizer_relationship` generates a new SQLAlchemy model, that is available under the attribute that you specify. If you are using alembic's autogenerate functionality to generate migrations, you will need to exclude these models from the autogenerate process. +These are added to a list in your metadata called `pgai_managed_tables` and you can exclude them by adding the following to your `env.py`: + +```python +def include_object(object, name, type_, reflected, compare_to): + if type_ == "table" and name in target_metadata.info.get("pgai_managed_tables", set()): + return False + return True + +context.configure( + connection=connection, + target_metadata=target_metadata, + include_object=include_object + ) +``` + +This should now prevent alembic from generating tables for these models when you run `alembic revision --autogenerate`. diff --git a/projects/pgai/pgai/sqlalchemy/__init__.py b/projects/pgai/pgai/sqlalchemy/__init__.py new file mode 100644 index 000000000..a669bbea6 --- /dev/null +++ b/projects/pgai/pgai/sqlalchemy/__init__.py @@ -0,0 +1,184 @@ +from typing import Any, Generic, TypeVar, overload + +from pgvector.sqlalchemy import Vector # type: ignore +from sqlalchemy import ForeignKeyConstraint, Integer, Text, event, inspect +from sqlalchemy.orm import ( + DeclarativeBase, + Mapped, + Mapper, + Relationship, + RelationshipProperty, + backref, + mapped_column, + relationship, +) + +# Type variable for the parent model +T = TypeVar("T", bound=DeclarativeBase) + + +def to_pascal_case(text: str): + # Split on any non-alphanumeric character + words = "".join(char if char.isalnum() else " " for char in text).split() + # Capitalize first letter of all words + return "".join(word.capitalize() for word in words) + + +class EmbeddingModel(DeclarativeBase, Generic[T]): + """Base type for embedding models with required attributes""" + + embedding_uuid: Mapped[str] + chunk: Mapped[str] + embedding: Mapped[Vector] + chunk_seq: Mapped[int] + parent: T # Type of the parent model + + +class _Vectorizer: + def __init__( + self, + dimensions: int, + target_schema: str | None = None, + target_table: str | None = None, + **kwargs: Any, + ): + self.dimensions = dimensions + self.target_schema = target_schema + self.target_table = target_table + self.owner: type[DeclarativeBase] | None = None + self.name: str | None = None + self._embedding_class: type[EmbeddingModel[Any]] | None = None + self._relationship: RelationshipProperty[Any] | None = None + self._initialized = False + self.relationship_args = kwargs + event.listen(Mapper, "after_configured", self._initialize_all) + + def _initialize_all(self): + """Force initialization during mapper configuration""" + if not self._initialized and self.owner is not None: + self.__get__(None, self.owner) + + def set_schemas_correctly(self, owner: type[DeclarativeBase]) -> None: + table_args_schema_name = getattr(owner, "__table_args__", {}).get("schema") + self.target_schema = ( + self.target_schema + or table_args_schema_name + or owner.registry.metadata.schema + or "public" + ) + + def create_embedding_class( + self, owner: type[DeclarativeBase] + ) -> type[EmbeddingModel[Any]]: + assert self.name is not None + table_name = self.target_table or f"{owner.__tablename__}_embedding_store" + self.set_schemas_correctly(owner) + class_name = f"{to_pascal_case(self.name)}Embedding" + registry_instance = owner.registry + base: type[DeclarativeBase] = owner.__base__ # type: ignore + + # Check if table already exists in metadata + # There is probably a better way to do this + # than accessing the internal _class_registry + # Not doing this ends up in a recursion because + # creating the new class reconfigures tha parent mapper + # again triggering the after_configured event + key = f"{self.target_schema}.{table_name}" + if key in owner.metadata.tables: + # Find the mapped class in the registry + for cls in owner.registry._class_registry.values(): # type: ignore + if hasattr(cls, "__table__") and cls.__table__.fullname == key: # type: ignore + return cls # type: ignore + + # Get primary key information from the fully initialized model + mapper = inspect(owner) + pk_cols = mapper.primary_key + + # Create the complete class dictionary + class_dict: dict[str, Any] = { + "__tablename__": table_name, + "registry": registry_instance, + # Add all standard columns + "embedding_uuid": mapped_column(Text, primary_key=True), + "chunk": mapped_column(Text, nullable=False), + "embedding": mapped_column(Vector(self.dimensions), nullable=False), + "chunk_seq": mapped_column(Integer, nullable=False), + } + + # Add primary key columns to the dictionary + for col in pk_cols: + class_dict[col.name] = mapped_column(col.type, nullable=False) + + # Create the table args with foreign key constraint + table_args_dict: dict[str, Any] = dict() + if self.target_schema and self.target_schema != owner.registry.metadata.schema: + table_args_dict["schema"] = self.target_schema + + # Create the composite foreign key constraint + fk_constraint = ForeignKeyConstraint( + [col.name for col in pk_cols], # Local columns + [ + f"{owner.__tablename__}.{col.name}" for col in pk_cols + ], # Referenced columns + ondelete="CASCADE", + ) + + # Add table args to class dictionary + class_dict["__table_args__"] = (fk_constraint, table_args_dict) + + # Create the class using type() + Embedding = type(class_name, (base,), class_dict) + + return Embedding # type: ignore + + @overload + def __get__( + self, obj: None, objtype: type[DeclarativeBase] + ) -> type[EmbeddingModel[Any]]: ... + + @overload + def __get__( + self, obj: DeclarativeBase, objtype: type[DeclarativeBase] | None = None + ) -> Relationship[EmbeddingModel[Any]]: ... + + def __get__( + self, obj: DeclarativeBase | None, objtype: type[DeclarativeBase] | None = None + ) -> Relationship[EmbeddingModel[Any]] | type[EmbeddingModel[Any]]: + assert self.name is not None + relationship_name = f"_{self.name}_relationship" + if not self._initialized and objtype is not None: + self._embedding_class = self.create_embedding_class(objtype) + + mapper = inspect(objtype) + assert mapper is not None + pk_cols = mapper.primary_key + if not hasattr(objtype, relationship_name): + self.relationship_instance = relationship( + self._embedding_class, + foreign_keys=[ + getattr(self._embedding_class, col.name) for col in pk_cols + ], + backref=self.relationship_args.pop( + "backref", backref("parent", lazy="select") + ), + **self.relationship_args, + ) + setattr(objtype, f"{self.name}_model", self._embedding_class) + setattr(objtype, relationship_name, self.relationship_instance) + self._initialized = True + if obj is None and self._initialized: + return self._embedding_class # type: ignore + + return getattr(obj, relationship_name) + + def __set_name__(self, owner: type[DeclarativeBase], name: str): + self.owner = owner + self.name = name + + metadata = owner.registry.metadata + if not hasattr(metadata, "info"): + metadata.info = {} + metadata.info.setdefault("pgai_managed_tables", set()).add(self.target_table) + + +vectorizer_relationship = _Vectorizer diff --git a/projects/pgai/pyproject.toml b/projects/pgai/pyproject.toml index 5d6da0d31..7819d9514 100644 --- a/projects/pgai/pyproject.toml +++ b/projects/pgai/pyproject.toml @@ -43,6 +43,11 @@ classifiers = [ "Operating System :: POSIX :: Linux", ] +[project.optional-dependencies] +sqlalchemy=[ + "sqlalchemy>=2.0.36", +] + [project.urls] Homepage = "https://github.com/timescale/pgai" Repository = "https://github.com/timescale/pgai" @@ -110,4 +115,5 @@ dev-dependencies = [ "testcontainers==4.8.1", "build==1.2.2.post1", "twine==5.1.1", + "psycopg2==2.9.10", ] diff --git a/projects/pgai/tests/vectorizer/cassettes/test_joined_loading.yaml b/projects/pgai/tests/vectorizer/cassettes/test_joined_loading.yaml new file mode 100644 index 000000000..b6e0ad07a --- /dev/null +++ b/projects/pgai/tests/vectorizer/cassettes/test_joined_loading.yaml @@ -0,0 +1,298 @@ +interactions: +- request: + body: '{"input": [[2028, 374, 1296, 2262, 220, 15, 430, 690, 387, 23711, 13], + [2028, 374, 1296, 2262, 220, 16, 430, 690, 387, 23711, 13], [2028, 374, 1296, + 2262, 220, 17, 430, 690, 387, 23711, 13]], "model": "text-embedding-3-small", + "dimensions": 768, "encoding_format": "float"}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '273' + content-type: + - application/json + host: + - api.openai.com + user-agent: + - AsyncOpenAI/Python 1.53.0 + x-stainless-arch: + - arm64 + x-stainless-async: + - async:asyncio + x-stainless-lang: + - python + x-stainless-os: + - MacOS + x-stainless-package-version: + - 1.53.0 + x-stainless-retry-count: + - '0' + x-stainless-runtime: + - CPython + x-stainless-runtime-version: + - 3.10.15 + method: POST + uri: https://api.openai.com/v1/embeddings + response: + body: + string: !!binary | + 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 + vZyDtCbbMlkxLF+cY2/tvA8cL501mDgr1bo4dazEzZDBf8Mgei/9joVPuNp18xaceNogIPnGCc9H + Mm03eXzjYuwCTB4djbSQrhOj2kN6UtAyumEDBtWuJcIc+X4lCFiIZj9nX+86W9WKcfJneiNHx4np + trpJTg0J1t2crXtnUOSWNHSZq9pv4NSrLnLTVRwM0Zk1Xw+bndcQ8MgrbMq02XiyMJY9mxfaMA1P + W+uRLXibKRXDlEclwnn+ZVMyyppNskxZDG+5nNg5wlf18gjVNmNMAKqRG+uo75D4slwh9CRePs2G + zWfdL9I5KqlRnJANkzxa+hTsN1ANtlM+Rpxtc6DDY8qd6x6J0IntatwsdVMg1BZ3zFfR1yZqL8Ih + X1aA4DTiTBvPDiYz5aTksRFFmv6kqzcFPjdHN5t7PEQ0pGn9fcZnigHPxo285zDPjW6f8L0N52hg + MZtNYRScAtNFtek4Hq17pztPhbeLMDhuVuBGVrUHTGs/xWKk7YPpItI7UQU1lyuf3yKzdyxz9Kyn + svFWbWDV49vdONsoDQd4ImQtLazTq7Ky2LjoKicnRWO9rD5MjWNsbxXk09Rw5LWjRU04N3VqxzPa + cDf7jtEOOucbjp8jC8QVdjrza5588tIoHONWBm2cXYCZmJxxnPbNZck2Bo4p8Gsjb3sz9Xju0Fw/ + hwApYgPCHGWWdQxplfbR+bWXHbpyymdfrshH0vV9HJfQD0+NNkCII3WrdvLNL2JMASeGj9iYw5Hs + scen2bbWPabHnVvDr0/q2tyum+GjaieXU7MqhmPX1sH4pzOVJ9JyDsU7nQ9VO8K21w9nh35fxjjZ + hYThg+3Tfd+72ZeuhGKEO7zcTMHpdSiV5t3VKkxz1EZ3UM8UYvUqZxb3bZjS/PDq0prBhAE7PT9b + q1rLAobNL5eiHJajbD695WZ2r+q+jnLek/uYY2vHOAv5SwTfmndeBiCvzIdkjMXOydi//AQZd9D2 + ZoEbMT/vruhagsMhyejmNPcqManbx/Z4Ns3FfPZFG7BVHX6mivetzG9bKM2vGfxKmLg6tBifdZtp + 5g3pB6eQMLUZCFprhXsf48x3iE6MyXRciQZpbw6HXxYsGcth3fONM/MWbsbR8rxFuH4/v2i0Segb + eVp2JHGocHzwUjYIGF13BqbG1u62I7E5kcpPOm37lveZQe0I61i7kcpRvI0Zb+yqfstO+Zb9LkDP + ix2DyUMmNU6XXN/s8bLK/wEAAP//nJxLbmS5EkM31AOF4r+YXsrbe4NKD9pkNgp4owI8KBuZ90oR + 5CHf8bYqHf4Hj1mGYKOKVInhl2/UODNskGBAPM2bD74vvhNhWZjxjBnXs4Kx5sWWkmy4g6luOTIs + jOcZeYY+rwaMdBZKXliEVRbojuzCw9xtF3N/bZPxHIB4bETdkzVK/QUik/yteNgTCemTwv3AD0Ag + AXhomMd7XXYF8wV+LEOqLVLcLaJExiFFNadWtomv4QXLMPC0dMvby9H+wbJ6LGFt7jJbwdn4n8UR + 6tWqdhdX3vYn9fNzcWCN5+UlNzr89M/P/n7//u+v/6OOwP5cR4AIpxJmyEDgSQyh1V8SlDk9B04y + grQZspyswjRUxGu8l5ZmCa5v8rIDE6eqRZ0DJ7C/p0XQwp2UEbxpLRsIArq2PJAE1L0QJm0fVn0l + eX+TObXEqUnT5qmGssYXxLv72GmOm9CrGHOBN6TwGUxSSUh0RPEHcD2sm1+Zly4LyfKCvxQq+IXX + GVWuRlKffheSiM5DYTVsQqbHaoHEyJgVHAOAzQlMTMZqz+HL8NptxDZYs+67RYs5fIkcWu6Aqou5 + NoOWCZGQpkCXyw1vyJisDKqecj6cfpLJcd4v8xRTidbX/NJ3EHk2XQhAXDIaxpgcFyzv84UvOVEG + Botv47O98hrtAfwx4rp5ByeCsHjvFYsuEbSf4cIIg/AlsRczhj0qZiXV+6A2+f1bJQRiwqFQL63f + 4su3bFtzTjfGRAhpYAWp2xIaLCSnD8VqRcnaA9iL3DUIVny2dOa5xvBNwsvhMCycMLarSgIXHjvj + er/dyVR3Ffsuj+Tx2c75bd00KIGSR98z8vW1hXHTwvF1HxrSoNlwwrcH7RXLP6xcSWkHcBuW3A+6 + czhTbjc7kj79e06ubAnuUaZHGCAnvlliskwKGbJvhGvOWw6xz6qTOZeViAyES1gKrAKuz2z2vrNJ + JkW0fRz9FqOc6eiA/RXkhsAgDqkLQU/BGEds0qGTLY9fe5n5r4hufooLuXY2H222zEUd2Zo6IwGZ + W6wloT4iKuTSRbGEyUW0CD3wL4Ptywr9mfBh9c59O7e12uWuMzEEhLFKKUhpCwHbtKbtExdHW2gJ + 0QrGNe6HyUjEDcTS7ckriqTVtRx+4MGgs3N3o24c8QJw3kr8dmdPj7jht8XOtjfQshYPyOMGSzPn + ApilPCYGRJfCCjRIDONLcc6Xtp3hhOd5PkgIJdQz5HuG2fg5HEwoOG6C0LUvL8SxN0ZCDHDuWxEb + kEfL1v16fOljyPlt3H6dAD7Lf1/Z8g36V67mdDHHKbJoLvEyrNnLz5Tlo5vZddqXJaFz8fVqMX3g + CRWPvWDvo7RzYopg1xYXuPEIkC0qi6W7lLcgMyikbKDAhOXpRrSrmZHAjs15HdB0VhzCiRdG5xt4 + r0FwVaj34RvSMdAtFU6JjDm7OQfz14xUu/ir4eLZ1gqFK1KAM+3wOvi0Rd2ORKI7jNVZHAox9Gg3 + DmV2vk5dRgoBHo20qgAiXQ5NzZN6uEDFBw4pjYaeoN9chiBfp2/2YmWbZK4cMW/TYrybyTcYVjEE + sIVvxsNOR0vddq6mMrAAG2K9PbmRRz6E9eU/5cn8k45CiRKNCmf5gzofYTi5gS13SSRCBE24QVyc + IOPJSxyAwSK1/6ZBP4FdeHy8Wzesbb7mYE+69mzdvM7OigFp5xAMYO1toUt81/mtBl4B6kO0U3xa + cvzZRTqL171Thbo5Ma7uGCKmJFbGpnTLgV5S/RgCBaFnx7DhLy92kDzo/tzoFMa0WkmOi2APyxgZ + JchGNSrRJDCLSIOEWAPyOyOmhhycdDHMigoERbbRSybFgsAm1K5KV3bXPZypDTsDzUSaWzxbTkSo + 8usuPXiJzkPxUdIDuUFpUduyJqoMY+Vd/mxuutu4OKLryVIGGus0jiCj/U8NVUlmTia7j6l9r5QT + otaEpBxQOzslljjyWclmy6K7gMmpRh8ER4k7jjTyVB+dqk/Djmb0dsBI0XJ+AyGuLzyodQoRfN2r + uXERYdrl56J7Twh7CnIGD6iQ+WEWWmV50XrafxbOzsT6Ej+IG8BD9gXDt0BvjH5YPzWEsGMvx5Hh + rLG7d8Z3+GSqnpAsmmE4Nv68c7D1s8xXQGClGqhh+bBbsXVUpmUt5lNXhCWIf1Pak314vLz2u5Dh + A2Dsy46z7YriWWe2dLxTaBUeeT8Oc1lJUwcUTR6Ob3qvKKLuDwLliC/KCxhI2KyK0gzCK3jkjTOu + kFbfNl69CD9bLLhQ6TNAMIQTRmD/RGQ+a53kLEWgxIqfYLTessrunYZODT5Bq5OOSpuLUXxYNsJu + Q6Cn3/rWm5AouxP6Zq797mP46HZu/AeAtcKbIpy7dbUkn8sxChQ33YC/bC6CmgkuL2lH0wZd5RgY + vnSpznZwdA3LpXwEiS/G2PCbFRWhTxaD5ahGXVt6+k5ktzMOozNM4EZyPibk8PzsSzGVV5msMnn6 + HPOF+JpXearvFy2S8GkcBW84HMvRzGn58xFtZyoAs8b5d1LqHwAAAP//pJ3NqmVHdoTnegqhuSDX + yr+V/S7GNFh4YMlqLBl64nc3X57Ttk/ELm6Bp0VRde85e2eun4gvXoX5xKdgGuUKQ3g9HjLZLnUo + vqNM6IPtrbxk/PgxfFHcoyk0pPpsWqTs6+HTlga3q47Bx+6rDZ9rIMQJVS2PpcbkmWufkyo+yDpp + NVLGCV1YRatjmDI2PbuHGXzGsLYiY6dBsGHeHLW0jVjX/WZ7wDvqlF8qVxnU93mA0OME7i19yiuw + IJuy56CikcEWDiP5VEGrWLE/Tswd6izHupI6FstYionEFGkDCV/E3hLnHrAqUI7semiNzURkPTCn + unsqKQ90LbjCrP4sl9E9S5e9sI/aAKnvXfpM+fjvjbXf+4SpwpDpqDx81jzOs6RusyXMQDSuHlZ2 + /n0vVcTO2mOZ8SNBA203DQwtB2lHzzyKEcppO5jHYi5xdi/1eeKlWGu74rEvpSeuGWH7snEXxqY3 + 7AUfyPQYe4F3mN+jWwjoHC4LejiVsaK0bsibfo+WbS6zwH+oi4VZbVsDiaL/DK1UqIma4eWZY7ij + 5NwRntAqH+6qmd2wQ7SfvPA6Rj+9mqorJ1TYY1Lr+ORYvFZjmYxyv9rlv/AcNVRovq8gWNXjWjrT + EKAlNnxoGxsWjwrA+bZlYxqMCvY07fI6uQV60BA5d2VPUpEMvVZhoxwbK0D1TCWYJ6dbN9DjY+0I + oSVy+c67h3p/2l6b8YiijalNQhulUyvM0oknq+lY4bEpGwjDojszHsqZMs5e/5m20IFowYmzAfrJ + +PiZW03QDaesDXI6Td3QV76jOzYo3OMg99a1UzVJu2tCyeMcGv/U0ikeNttSX1+ctdzS1S9hJr/n + 1kseAe0KNj4luTF6jvmpuH0xSEeNrksvG6O/JAobOvZQSse00+7ucbRVwCqjQwmKdzgstvICpiU2 + uRLv9Ov75Ia3EVJnY2USynWLAf1GDxf0NvMV/ifVY6EadwM8mj5DAIxtPeEYL6u3NJWzj1gGLuNk + E5XeNV+EW/XBxG0zGqJl0o05aGYjKxCbUWFGTdlYv6N46iwDdJ3sJqaKQj7nR/PE1Ff9q2Xs6xAi + o8M84FAEyiycD0PQmy9gc2u8I3IGein+ZqWyz9h6N51xSq+Gs+fyb6Bvk7mxRlAOPVEQrp6LGJBH + Us+km7Kk78CrQDSV0QkHRiBy0wI/meIYOSV54EzgcgZQnG6nFRjaLkbuswyoBVaVQawBADBb6sR8 + 58p0St20ec/g8WnaJDAtUtgumNN4kHSdte13fRRInAVB2Fq8c61GOgYuphZfTqLfYQLrrKHbTF4s + A82h1hzGgSgM4rqSY8U+dLoGSmbuVIc/MSVq2OQkrakqjQEMvGkiGFhE3fMwtNn2S8k6/B2Iwn7M + TPfwE7dCLYm60s4Ry3w4sDozz7ZKFsKKSg9QPXz+o5XQUQwi0fuIttWAttcatuMfawORtR0/dg7N + fztZ1BbS+4I40NaLDXN/ELqdXbXlcKGE2pam87zMYPcamnJzrxF111euWfYSW2n1Ts6ZTaWCOxJG + j4UnFTh0YxTxDug5COLAS9GRp7mTEsO51bJztGGzAlyLRuO5baZKGB8b9ZsfVaWtPp7nsqSofcD7 + qtCK3yy0QpwMBc3gTi2zTSkIQ9TR8deLPMd3LA4muDIl0K3e/N6PtdOkRm2tRQiUIU/3UcjFbIat + GWca7Cwhrj/0zUzDBXExNzYzq6Vm/2TYXk30uAFEtlJeZ4cSp3esrSr8Ub2rpiJPIkDQ548paZih + 7El/yqlsePbH/cyE1decrd0pHNUwUmcclZ9Vb8deQB8fvU771R4ATZ0L0/zJNybGA1nic6H6otWe + 5Wv2S8tzFPfTt92QMHRFzmKkXcvAS3uNoQaR3oDbxldTltfwhsGggjNmsxbt8HOaLpCgnTp2t5Mz + YhPA7pCYFit6E/uY6z9fv6c7yuAFt8976FFv/gbQDfcf+uX0UhDjGLDrzX1H33izIbXtXXo59X5z + JFUwsifmCLmH7rxdO29mTyJCueCR0KpjZpBKtb9HrP10X2DjmWmv1hnDDLd59jb9wtnTekz4+u2B + ZQntrxvcNXmPFOmzQNz7uHURV1ZfeUNeAxXk/e7uIN3VEHzjkFtnDwGXyNKVEWs9myEGURHaEnYG + kz2/o0DJgbQlLDbvwj7G91h8OkQAnd9g0jgjzDYA8clHm5FqX5sM+2wBT+ZOKuxtdSiIruG4lZfp + E5En7uPVwCAEwn61sc5ShzKxZ80OyMCNrDItap/uo8grhdKFAgFjFvGEnI2pr84HBxlpxswb1T6n + Xu+QqK3G1TGm+dRjDNO4T3QU6h5C79K07ol79eqSxTZ33/ysyK+Ymp2YsVvYz9RuPJkakpAe2+Kj + goWodLCrz4dE28l4SDXSMpl6R9kpa6qP3d1RuuPoynNlNLNtXXeI7BYZ1lmTfdXp1SvtzxdJG1pM + 9Nv7NVt7Makw5Sdq9uPDCtzNppEfYI1MmxO7LaOAMbNbzbF5oDJ0z8hf3irPmlWVHnx62h4W60Fr + mba3R6NgrI+nv2sL3Zdtv4YmiBBAkSvWFyrhd1bJ6uYhvnCk44GGQM0/VWNvrsbau+KLue/LMRq8 + xdYvUz9rXzYiZ8jiY8YxOhkXRG8WSIYkkb5MDyZrDL5hTfP140vmAfvPts0IuOkB+9d79ZE95sNN + X7CsbcR3OHectRvTyHEd06HOl4JJTqkeCS/jiAfKGFxKY7qutS0stFpFaGY3trgyb4wq89/p1mXq + RZ3QvawZmMHlkb8ETDvcZz8eOtNPP9ruPPuTCYDWtN8bjmOpUxPcypz/fyRBfo0koCpMFeug9jAI + PyOXHaaKPXs3m2K85hXaBQauBtWbz9sCeH5drz31LmQerQcJKcZjykd4apFFIm8WugKLbADYf0xF + QQ/o8Q59D9MF3OKmq9CPpEqPp4fUrAI2+tWmjAKOhmaxRYst3bLtfY/0WTCBj0efthU3ilkrjDVN + Ebr3cXMEEcB99WNOjEBGJCV1xQjtIHZdEZqFi5e5ihAkHjVs7Rou7egEgWjVedoTp5mRraJOxp3O + bVOGDRObcQGctc+DB6iQAlnhQECGXrsb/fbDF4uQ/ajYcNmVx22ubUJmZ0Rtcr11BfO2uwFboMQk + doJrWrYytmkTpXI52DAYKrLx6WNeUoVuSwE42qs18H2IimMsTlL9GvbLui9fWKci2uZFIaVFSwmS + 3S1TsX3mJrxwOcxxukpqj1mmsHpplhXJJs0hq3ijnWI152fp+mrdSJ4Mlfqjqd7HwD65lSk5UKmH + msA6+S6uXj8tFJPbVhmRHQNb0//96m+d57JRJJs3ilfi2KLXPumXKB8s0fLTfqlnF3Dnlocv2k1E + 1CIIb2xoLYpesmWZDG6FRkj3NqduFzquHNvcnpkPEY+5s4aJsoh2CZOhrtpptiBcCdsMQKznbGYc + xX2lLnhsZcNWysiqLO5gTkUxUK7kUlT5vC+6fCfFFsRy+wDlZ1lE3Yk9dFjG4ljrcGQy2xKqmPzs + MnLP7sfjGCFibu0ubq2jGmgUEW1ty2hr0zJNL+x0lGGx8VynwhF6WbL8JN1nOq+O9b+81Nii3N29 + qQt0HXr5qWbWJWjB9DvQCc9IM9CYgu9uEuPYoIy6vnS80nfoM3UlYdogB5Qmb5AZFWhdeeijXFx9 + m2kttiiVzjkWt8yzbpqSmgGMQwbhkDvTfIDUy+K02RAr7GPpfF8PSVQ79QwFJmTURAYdaRyFxxoQ + jIQtN24a21Kk9DkzrISEwTBcVDZNKpTMxefUhKIJTEk9DP2SzvXXR17frV9CWqkgBKyOai2gcrBu + hSmg5RRvKMs2IhunN5WM4z0zlM2E0uyLCUCgxgDuAdXYJg6swcxxuq8oTD+/ccwYmUBMjFoEWmmZ + fCyJJVGE8oTdbiMqvmb1b93dtM8x+AatrM1rvC0d8oKBDJuPXKebLWcI/jzKGHruF7DhzNOdGnJm + NZNbIfhrOr56vJ1w9kx1Dg+8pPVFHfTqrRgWyo2z5/BfFQ227oLp7psjN7HiWxuzTvU+TE1xYe/K + xNvbgsoYpi1Ls1yFPHl+0vtQyilT33qFl+4DoYy+GBNRYMiHN/Y5TV/BxTx9yVh409irLe8uNDS2 + cbMpUgzMwQSsh0JW1F6qiudDGbYE5QXydet2hg9WNZsV5PXaWhTaw+1BwCSSuM+HEQfBNIho5DLc + EAVJ393RrudEWUowHFP1G5DB5cQi9n3LE/Ggy9pqFG2/1urvBtL+2bnKaG6TdkGlCAhOtP/Ckdjq + y8/l1VWPZnErCxRE9zTeKpOlx1inpo3j0evrwpX2VSndJGzXdIwwo007QG3c8jopOxR5fQEX0GCX + ny/yivSz3pg4DMNPnOOu5d5UdKkef3q6InqA2U7LNgj6mG2ZL7k/bfOvCfVc2/Brq5hx6X0xTzXj + UQ3WH8qNJVzDhAsMl9XEvFH+GEo2x5xdE+RB46fFateNmlbdyJzjkz3x+mpg1Oh8HC2DXJg1XON1 + WfPLZFcnaVgsO5Xx/DDh141sUyjfoRIz/jpDR5tvroPC3clx/TO04I1vWTqwuYmi1VS3weZGT0I4 + uJYUiW8xfOc3cG+pzOQKIFUVmOOwudBR5vbIsqsGCedxQ5kwm+SNYRm+Oego7OUkm8jWtTBBPra3 + we/W0ekUUYgPT9saGHTsfI+atnugjdhmEKDrXl//xTXmUMd4zLo8IhMZAZ9Tm+E67ehnMsik1Vs3 + JpBA7Y729Q5rktXJhxSjYu7vPtHHu3yniRU6WE6Tq5/7Adgc5JSCAAauPV1jIwsZZnHuOQ3WDDa8 + DLzzUFnnycxSJzgpYvZjMhebFnpma4D/zQBJ8zXQc3lSAykcFrQe6ykLk+lKS3spx6jUposfopmC + ezaHYO/Th2qtx77psSbBnycUXbVIPdWR2cYEoj0ITVAzHhYreT5ute3fiBpbvAJZ++pffb99oxkk + srfdhk0yEpzUMJsr56KNbG4aq5nks2/dOVRP0plELH7Ha+qvWuiVbJYG8WFoIQ+/2OCfObM86aKj + BJlaoAdRYLY5JQN6WZ5fY+xg+MQx7VSgZzo6SJ2zKWeYtGZ9UlAJNcu2IcLOYrByns/19Ldm8/0k + QsDvuTo4D5WR1WOReqiv71WG6ROJqcSWOI0OvEll2/GapBQlk8DXYbst6q9psiLOybOPLbN7WUxI + kFFuIlVQSqWLdzrWwWcjP9i+yRGff8jQ0WSA+FQ01Prx9b0b2zRPyricTFtPwtMz4E4otgoUhVrU + Z/b41PK+WWJzWjLsWhwgeqcwM23WGxJuq7EXeSUiHvLuHXNw9dcDCnKh39EQOYo/XZnszaGQ7oHr + 5Sun6jE9aaZfY5VljR/2Vlru8sGWybii75vzpTrtiR1VprZkoA/dZZPyJZeNba1eHVAsHQJxA0Ua + I6yOALpepR5U8nBJUp5YvszhnbeGbQGrsMEzKaFLnZc+uP75W9vvgPtlCeKdDttNZ4fvwdW/g3m0 + slXXcNVhJ/vZ/PNzkp2oUzvMNeqpx7Cm8iNi6JsCDcYV66SqT1DfmPOWrLetjdTa3A6mijkUcxpL + XtmMPwBrd7mP6maByfV0kLvqRvjyfkP3zAQyG/usFoafbTFrTJVFZjl7O+oWIoytNLkUAkvaQLld + Lah8qH2UrgOQxLvtvmflOdbzgobcFj2NSKTUBsYlnlp0NzbPy6yAgG2uO0JfRBpc/cVICNkR9r5s + 9pU6fGUD3R0PRKqfLete36KR87nRnY+ynOZfi2BrlZ9HLfPMjMuwsAcGvI7BjDcm9vi6xY+9ajeT + EPHjH02l3FnL1pp9nuEOgDkRtOrTMaENyloV/JnO+LH+nqWzr+KWUg3Y423Uah7emc//iLWIdhjE + Qmmayct9r2wjstRWGFDiGDF89Qsa00FAzUrLsEbQcD6HRG8uDNt6l6eeTJNVPCnLYF6niRiCXdu0 + HKagmXfJKEPctACeuk3x+FrFESSOTYcAPpUvscZSIw7eGk8Q3r3qYx7wUowCojeD1Z6fivx3hrHn + kG2u7TQ0DWYNm4dQ0NiiifPG3naGpFUmvw9DLLdz0DAZdHbn2qGKv4SmZYkYxBrrRJWcER3M7yJR + xXofeB96uK4ZO5uVU7wcdjLWZNCqwEUAhGkkJAIdzSM7ZyvLPoSC00c4CxkpnKHvq7dhWa7ZwNNM + U8N2ie26+77Tls56D1fxMYqEtJXfksY9D2WvB4PYedstsvdxUnOFa0lq7jItD747XXsvUkH1eY1R + EbbHoCM3Sfy4EfGWL0zxrdBOPF9pfM6Row+dl2Guanrp3j/tGgqAGr5UoONd7EuguVbXlwsWUanP + FDHf8BlYz9XTErt6TUaTZlTEfq3T5jyHm0IsifxuLR+QyPpp0RawdFbGCjIrLf+fliOVte2GHrCA + uozGIEeuY5P5utvk4ZaZFkvfLTZkdZQUDaHGfQIHhHe3kO1Lw5CZAyoRezg7tnZPAyZeV8vaWWPM + rVujefCLTCNDklJsceZg7PM7VudYwT6jTV8WJX5S2fHryuvtMRzDYxGJcrNggjG2yYRNZvoP7eUJ + reeIkJ12ZqKqL8WvRRbXhP1UtVIXATeGJEKZYmB606jUHPBO27sQS9VEAvMxmyYZCFqondynUtnL + 0ZpHDucYaeyhx7EZp4MO3c5wtgkid5PIxES5JNdAMjRrCuE4bqflIjYKyDq1l9FfwX6nJbrOnJrq + lqSQjTR8J/uu79iWdPJ/Q6VMEQbq97vylQkHJX46xWktYeR2BJphoI+NwF775lPTZMtkP6QP4Yiz + UZZ6TNxuvi2fRFDIB3UwM3aL7gBQbs6VWx5vT2+gAtF5f79bNDvn1sEgLBuPYLNQXwiSX2sgQMmy + LSsmMgqvrNFHU4Fhct3rutCMG29Q6NhrWRJorGmH/5WzhIkxCsC5n6jMgKXkG9WOJz2D2jBHeyIE + 8DT6G2Ion1Wfc7fYqjynjbEWV8YfbyJADFP5sMBF42k24qa0WCIge/qDBTxyKw+PNZhlGkzQb6kA + lcUfq8aq77mNG3+jK6xv593UUU+fM/3Lton/O+18WK4KU0kCCbReg41ikoVTg3h11Uc8niMIVNCl + 1wM1yDsaurRVJotfCCiVdZ/4zi2zLi+wVc8dlo/5lSzztWIn/9S2/oDWjVndR5oqeFzavMpEktP0 + pL+hF0OvX1pyqMoFU4XpdJjZh+Gm3IRxiM6xuwgqnRV9j1PnO2M3Fjmez1AIXr9CvLII4WyW0YN+ + c2UuD//Jz8iJn1+DoBxbM4TJzwwX0qMid3RSu+syLceoR01d13uavm8U6A5LrUhE/xZ3S0/igc++ + rYTF0Yx7H3UnORrI9+JISJuyex0Ta21aMEUtRA0rXm7Gkfva4QFrA+lbivcYoLoDE2C76UD6eQF9 + aTBdaxU16L2Z1FtjV16KSU25o+ptpivJdny2ZAa/fwAOUNZ4xAYZKeFuPJgs9cVK4p1KT6KIzX2h + cRp0LoD6azJizeimck+MhuGxSBXdIlsXdaWHNvdtjF6/116vZ42mvC/42du8C2sGceZyGKEDMUop + MNClcLg+0y7bnneXbbEKo7q+cMnYKtW8FTzdGt7D/HcYCMXdm9/cGEY28KHzu7T3A0+H7tA66yJV + fYwxSPrQ/2sTjTS+Q6j9JPJnYFLGU310v0JG58I3+fnIfgxPdWN09TCNsShk+pcWjvcoA2STTtbv + Y2D6h96Jo5O7rjMWNopxTBC6ep5A4lKSGPJ/mW1cKpF8gid2KNeAu7MZprZGX90qjcDarKPnslad + csICRxdl/OmfXIIffvzxn/hrP/32+7/88itAgj9/+fufP/8PcODn/vMfv/31118vneCn//zjr//6 + y09/eXMMfvrbf/z+29/+/Oc/f/+3X/79j5/+8uM/3rmf/vz9z7/++n///Af+q//64b8BAAD//wMA + XPWY20jCAAA= + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 8f0d5b4bce32e506-TXL + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Thu, 12 Dec 2024 11:25:56 GMT + Server: + - cloudflare + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-allow-origin: + - '*' + access-control-expose-headers: + - X-Request-ID + alt-svc: + - h3=":443"; ma=86400 + openai-model: + - text-embedding-3-small + openai-organization: + - timescale-team + openai-processing-ms: + - '286' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-ratelimit-limit-requests: + - '10000' + x-ratelimit-limit-tokens: + - '5000000' + x-ratelimit-remaining-requests: + - '9999' + x-ratelimit-remaining-tokens: + - '4999967' + x-ratelimit-reset-requests: + - 6ms + x-ratelimit-reset-tokens: + - 0s + x-request-id: + - req_15d2bd3367c52a87ed911e9896064d5d + status: + code: 200 + message: OK +version: 1 diff --git a/projects/pgai/tests/vectorizer/cassettes/test_sqlalchemy.yaml b/projects/pgai/tests/vectorizer/cassettes/test_sqlalchemy.yaml new file mode 100644 index 000000000..1393f1148 --- /dev/null +++ b/projects/pgai/tests/vectorizer/cassettes/test_sqlalchemy.yaml @@ -0,0 +1,825 @@ +interactions: +- request: + body: '{"input": [[22333, 6975, 374, 264, 27084, 315, 21075], [93375, 430, 20682, + 6067, 311, 4048, 323], [12964, 323, 7417, 505, 3217], [13], [31380, 374, 264, + 1579, 11852, 15840, 4221, 3967], [5391, 369, 1202, 40075, 323, 92594], [13], + [1061, 8198, 33511, 13443, 11, 15840, 11, 323], [438, 8106, 19248, 311, 8819, + 26793, 505], [1527, 828], [13]], "model": "text-embedding-3-small", "dimensions": + 768, "encoding_format": "float"}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '422' + content-type: + - application/json + host: + - api.openai.com + user-agent: + - AsyncOpenAI/Python 1.53.0 + x-stainless-arch: + - arm64 + x-stainless-async: + - async:asyncio + x-stainless-lang: + - python + x-stainless-os: + - MacOS + x-stainless-package-version: + - 1.53.0 + x-stainless-retry-count: + - '0' + x-stainless-runtime: + - CPython + x-stainless-runtime-version: + - 3.10.15 + method: POST + uri: https://api.openai.com/v1/embeddings + response: + body: + string: !!binary | + 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 + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 8f0d4ed7eb6ee506-TXL + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Thu, 12 Dec 2024 11:17:26 GMT + Server: + - cloudflare + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-allow-origin: + - '*' + access-control-expose-headers: + - X-Request-ID + alt-svc: + - h3=":443"; ma=86400 + openai-model: + - text-embedding-3-small + openai-organization: + - timescale-team + openai-processing-ms: + - '120' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-ratelimit-limit-requests: + - '10000' + x-ratelimit-limit-tokens: + - '5000000' + x-ratelimit-remaining-requests: + - '9999' + x-ratelimit-remaining-tokens: + - '4999947' + x-ratelimit-reset-requests: + - 6ms + x-ratelimit-reset-tokens: + - 0s + x-request-id: + - req_697988508541f06ac9f5552ab4bf5c9e + status: + code: 200 + message: OK +version: 1 diff --git a/projects/pgai/tests/vectorizer/cassettes/test_vectorizer_composite_key.yaml b/projects/pgai/tests/vectorizer/cassettes/test_vectorizer_composite_key.yaml new file mode 100644 index 000000000..669987ea6 --- /dev/null +++ b/projects/pgai/tests/vectorizer/cassettes/test_vectorizer_composite_key.yaml @@ -0,0 +1,428 @@ +interactions: +- request: + body: '{"input": [[63602, 374, 459, 27332, 32185, 304, 21075], [93375, 323, 5780, + 6975], [13, 3005, 706, 4756, 12387, 16064, 389, 30828], [263, 30828, 14488], + [13]], "model": "text-embedding-3-small", "dimensions": 768, "encoding_format": + "float"}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '240' + content-type: + - application/json + host: + - api.openai.com + user-agent: + - AsyncOpenAI/Python 1.53.0 + x-stainless-arch: + - arm64 + x-stainless-async: + - async:asyncio + x-stainless-lang: + - python + x-stainless-os: + - MacOS + x-stainless-package-version: + - 1.53.0 + x-stainless-retry-count: + - '0' + x-stainless-runtime: + - CPython + x-stainless-runtime-version: + - 3.10.15 + method: POST + uri: https://api.openai.com/v1/embeddings + response: + body: + string: !!binary | + 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 + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 8f0d51facf49e50d-TXL + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Thu, 12 Dec 2024 11:19:35 GMT + Server: + - cloudflare + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-allow-origin: + - '*' + access-control-expose-headers: + - X-Request-ID + alt-svc: + - h3=":443"; ma=86400 + openai-model: + - text-embedding-3-small + openai-organization: + - timescale-team + openai-processing-ms: + - '299' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-ratelimit-limit-requests: + - '10000' + x-ratelimit-limit-tokens: + - '5000000' + x-ratelimit-remaining-requests: + - '9999' + x-ratelimit-remaining-tokens: + - '4999977' + x-ratelimit-reset-requests: + - 6ms + x-ratelimit-reset-tokens: + - 0s + x-request-id: + - req_d18a2d8b770a0cf4e21d1f57f8b16634 + status: + code: 200 + message: OK +version: 1 diff --git a/projects/pgai/tests/vectorizer/cassettes/test_vectorizer_embedding_creation_relationship.yaml b/projects/pgai/tests/vectorizer/cassettes/test_vectorizer_embedding_creation_relationship.yaml new file mode 100644 index 000000000..09b987c4c --- /dev/null +++ b/projects/pgai/tests/vectorizer/cassettes/test_vectorizer_embedding_creation_relationship.yaml @@ -0,0 +1,362 @@ +interactions: +- request: + body: '{"input": [[22333, 6975, 374, 264, 27084, 315, 21075], [93375, 430, 20682, + 6067, 311, 4048, 323], [12964, 323, 7417, 505, 3217], [13]], "model": "text-embedding-3-small", + "dimensions": 768, "encoding_format": "float"}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '217' + content-type: + - application/json + host: + - api.openai.com + user-agent: + - AsyncOpenAI/Python 1.53.0 + x-stainless-arch: + - arm64 + x-stainless-async: + - async:asyncio + x-stainless-lang: + - python + x-stainless-os: + - MacOS + x-stainless-package-version: + - 1.53.0 + x-stainless-retry-count: + - '0' + x-stainless-runtime: + - CPython + x-stainless-runtime-version: + - 3.10.15 + method: POST + uri: https://api.openai.com/v1/embeddings + response: + body: + string: !!binary | + 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 + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 8f0d5b51eec9e506-TXL + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Thu, 12 Dec 2024 11:25:57 GMT + Server: + - cloudflare + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-allow-origin: + - '*' + access-control-expose-headers: + - X-Request-ID + alt-svc: + - h3=":443"; ma=86400 + openai-model: + - text-embedding-3-small + openai-organization: + - timescale-team + openai-processing-ms: + - '69' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-ratelimit-limit-requests: + - '10000' + x-ratelimit-limit-tokens: + - '5000000' + x-ratelimit-remaining-requests: + - '9999' + x-ratelimit-remaining-tokens: + - '4999980' + x-ratelimit-reset-requests: + - 6ms + x-ratelimit-reset-tokens: + - 0s + x-request-id: + - req_08270a0bc83d801816946166857c9ee0 + status: + code: 200 + message: OK +version: 1 diff --git a/projects/pgai/tests/vectorizer/cassettes/test_vectorizer_large_mbedding_creation.yaml b/projects/pgai/tests/vectorizer/cassettes/test_vectorizer_large_mbedding_creation.yaml new file mode 100644 index 000000000..6a5f7422d --- /dev/null +++ b/projects/pgai/tests/vectorizer/cassettes/test_vectorizer_large_mbedding_creation.yaml @@ -0,0 +1,229 @@ +interactions: +- request: + body: '{"input": [[22333, 6975, 374, 264, 27084, 315, 21075, 11478, 430, 20682, + 6067, 311, 4048, 323, 7417, 505, 3217, 13]], "model": "text-embedding-3-large", + "dimensions": 1536, "encoding_format": "float"}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '200' + content-type: + - application/json + host: + - api.openai.com + user-agent: + - AsyncOpenAI/Python 1.53.0 + x-stainless-arch: + - arm64 + x-stainless-async: + - async:asyncio + x-stainless-lang: + - python + x-stainless-os: + - MacOS + x-stainless-package-version: + - 1.53.0 + x-stainless-retry-count: + - '0' + x-stainless-runtime: + - CPython + x-stainless-runtime-version: + - 3.10.15 + method: POST + uri: https://api.openai.com/v1/embeddings + response: + body: + string: !!binary | + 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 + +8+//d+f/4A/9a8f/g0AAP//AwBHX2NkE4IAAA== + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 8f0d577a0d31e50a-TXL + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Thu, 12 Dec 2024 11:23:20 GMT + Server: + - cloudflare + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-allow-origin: + - '*' + access-control-expose-headers: + - X-Request-ID + alt-svc: + - h3=":443"; ma=86400 + openai-model: + - text-embedding-3-large + openai-organization: + - timescale-team + openai-processing-ms: + - '70' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-ratelimit-limit-requests: + - '10000' + x-ratelimit-limit-tokens: + - '5000000' + x-ratelimit-remaining-requests: + - '9999' + x-ratelimit-remaining-tokens: + - '4999981' + x-ratelimit-reset-requests: + - 6ms + x-ratelimit-reset-tokens: + - 0s + x-request-id: + - req_ea6c79e762c2ef542d4a6f551052f7c5 + status: + code: 200 + message: OK +version: 1 diff --git a/projects/pgai/tests/vectorizer/conftest.py b/projects/pgai/tests/vectorizer/conftest.py index 2ac1f3dc8..23b593535 100644 --- a/projects/pgai/tests/vectorizer/conftest.py +++ b/projects/pgai/tests/vectorizer/conftest.py @@ -60,7 +60,6 @@ def vcr_(): def postgres_container_manager() -> ( Generator[Callable[[bool], PostgresContainer], None, None] ): - load_dotenv() extension_dir = os.path.abspath( os.path.join(os.path.dirname(__file__), "../../../extension/") ) @@ -84,6 +83,7 @@ def get_container(load_openai_key: bool = True) -> PostgresContainer: ) if load_openai_key: + load_dotenv() openai_api_key = os.environ["OPENAI_API_KEY"] container = container.with_env("OPENAI_API_KEY", openai_api_key) diff --git a/projects/pgai/tests/vectorizer/extensions/__init__.py b/projects/pgai/tests/vectorizer/extensions/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/projects/pgai/tests/vectorizer/extensions/conftest.py b/projects/pgai/tests/vectorizer/extensions/conftest.py new file mode 100644 index 000000000..3733575f2 --- /dev/null +++ b/projects/pgai/tests/vectorizer/extensions/conftest.py @@ -0,0 +1,46 @@ +from collections.abc import Generator +from pathlib import Path + +import pytest +from sqlalchemy import Engine, create_engine, text +from testcontainers.postgres import PostgresContainer # type: ignore + +# Get the path to the fixtures directory relative to this file +FIXTURES_DIR = Path(__file__).parent / "fixtures" + + +def drop_vectorizer_if_exists(id: int, engine: Engine): + with engine.connect() as conn: + vectorizer_exists = conn.execute( + text(f"SELECT EXISTS (SELECT 1 FROM ai.vectorizer WHERE id = {id})") + ).scalar() + + if vectorizer_exists: + conn.execute(text(f"SELECT ai.drop_vectorizer({id}, drop_all=>true);")) + conn.commit() + + +@pytest.fixture +def initialized_engine( + postgres_container: PostgresContainer, +) -> Generator[Engine, None, None]: + """Create a SQLAlchemy engine with the AI extension enabled. + + Args: + postgres_container: Postgres test container fixture + + Returns: + Engine: Configured SQLAlchemy engine + """ + engine = create_engine(postgres_container.get_connection_url()) + with engine.connect() as conn: + conn.execute(text("CREATE EXTENSION IF NOT EXISTS ai CASCADE;")) + conn.commit() + + yield engine + + drop_vectorizer_if_exists(1, engine) + drop_vectorizer_if_exists(2, engine) + with engine.connect() as conn: + conn.execute(text("DROP SCHEMA public CASCADE; CREATE SCHEMA public;")) + conn.commit() diff --git a/projects/pgai/tests/vectorizer/extensions/test_sqlalchemy.py b/projects/pgai/tests/vectorizer/extensions/test_sqlalchemy.py new file mode 100644 index 000000000..570d766a3 --- /dev/null +++ b/projects/pgai/tests/vectorizer/extensions/test_sqlalchemy.py @@ -0,0 +1,129 @@ +from typing import Any + +from sqlalchemy import Column, Engine, Integer, Text +from sqlalchemy.orm import Session, declarative_base +from sqlalchemy.sql import text +from testcontainers.postgres import PostgresContainer # type: ignore + +from pgai.sqlalchemy import vectorizer_relationship +from tests.vectorizer.extensions.utils import run_vectorizer_worker + + +def test_sqlalchemy( + postgres_container: PostgresContainer, initialized_engine: Engine, vcr_: Any +): + db_url = postgres_container.get_connection_url() + # Create engine and base + Base = declarative_base() + + class BlogPost(Base): + __tablename__ = "blog_posts" + + id = Column(Integer, primary_key=True) + title = Column(Text, nullable=False) + content = Column(Text, nullable=False) + + content_embeddings = vectorizer_relationship( + dimensions=768, + ) + + # Create tables + Base.metadata.drop_all(initialized_engine) + Base.metadata.create_all( + initialized_engine, tables=[Base.metadata.sorted_tables[0]] + ) + + # Create vectorizer + with initialized_engine.connect() as conn: + conn.execute( + text(""" + SELECT ai.create_vectorizer( + 'blog_posts'::regclass, + embedding => ai.embedding_openai('text-embedding-3-small', 768), + chunking => ai.chunking_recursive_character_text_splitter('content', + 50, + 10) + ); + """) + ) + conn.commit() + + # Insert test data + with Session(initialized_engine) as session: + posts = [ + BlogPost( + title="Introduction to Machine Learning", + content="Machine learning is a subset of artificial intelligence that enables systems to learn and improve from experience.", # noqa + ), + BlogPost( + title="Python Programming", + content="Python is a high-level programming language known for its simplicity and readability.", # noqa + ), + BlogPost( + title="Data Science Basics", + content="Data science combines statistics, programming, and domain expertise to extract insights from data.", # noqa + ), + ] + session.add_all(posts) + session.commit() + + with vcr_.use_cassette("test_sqlalchemy.yaml"): + run_vectorizer_worker(db_url, 1) + + with Session(initialized_engine) as session: + # Test 1: Access embedding class directly + assert BlogPost.content_embeddings.__name__ == "ContentEmbeddingsEmbedding" + + # Get all embeddings directly + all_embeddings = session.query(BlogPost.content_embeddings).all() + assert len(all_embeddings) > 0 + assert hasattr(all_embeddings[0], "embedding") + assert hasattr(all_embeddings[0], "chunk") + + # Test 2: Access embeddings through relationship + blog_post = session.query(BlogPost).first() + assert blog_post is not None + + embedding = session.query(BlogPost.content_embeddings).first() + assert embedding is not None + assert embedding.chunk in blog_post.content + + # Test 4: Semantic search functionality + from sqlalchemy import func + + # Search for content similar to "artificial intelligence" + similar_embeddings = ( + session.query(BlogPost.content_embeddings) + .order_by( + BlogPost.content_embeddings.embedding.cosine_distance( + func.ai.openai_embed( + "text-embedding-3-small", + "artificial intelligence", + text("dimensions => 768"), + ) + ) + ) + .limit(2) + .all() + ) + + assert len(similar_embeddings) > 0 + # The ML post should be most similar to "artificial intelligence" + assert "Machine learning" in similar_embeddings[0].parent.content + + # Test 5: Join query example + # Find all blog posts with their embeddings where title contains "Python" + python_posts = ( + session.query(BlogPost, BlogPost.content_embeddings) + .join( + BlogPost.content_embeddings, + BlogPost.id == BlogPost.content_embeddings.id, # type: ignore + ) + .filter(BlogPost.title.ilike("%Python%")) + .all() + ) + + assert len(python_posts) > 0 + post, embedding = python_posts[0] + assert "Python" in post.title + assert hasattr(embedding, "embedding") diff --git a/projects/pgai/tests/vectorizer/extensions/test_sqlalchemy_composite_primary.py b/projects/pgai/tests/vectorizer/extensions/test_sqlalchemy_composite_primary.py new file mode 100644 index 000000000..f38347007 --- /dev/null +++ b/projects/pgai/tests/vectorizer/extensions/test_sqlalchemy_composite_primary.py @@ -0,0 +1,121 @@ +from typing import Any + +import numpy as np +from sqlalchemy import Column, Engine, Text +from sqlalchemy.orm import DeclarativeBase, Session +from sqlalchemy.sql import text +from testcontainers.postgres import PostgresContainer # type: ignore + +from pgai.sqlalchemy import vectorizer_relationship +from tests.vectorizer.extensions.utils import run_vectorizer_worker + + +class Base(DeclarativeBase): + pass + + +class Author(Base): + __tablename__ = "authors" + first_name = Column(Text, primary_key=True) + last_name = Column(Text, primary_key=True) + bio = Column(Text, nullable=False) + bio_embeddings = vectorizer_relationship( + dimensions=768, + ) + + +def test_vectorizer_composite_key( + postgres_container: PostgresContainer, + initialized_engine: Engine, + vcr_: Any, +): + """Test vectorizer with a composite primary key.""" + db_url = postgres_container.get_connection_url() + + # Create tables + metadata = Author.metadata + metadata.create_all(initialized_engine, tables=[metadata.sorted_tables[0]]) + + # Create vectorizer + with initialized_engine.connect() as conn: + conn.execute( + text(""" + SELECT ai.create_vectorizer( + 'authors'::regclass, + embedding => ai.embedding_openai('text-embedding-3-small', 768), + chunking => + ai.chunking_recursive_character_text_splitter('bio', 50, 10) + ); + """) + ) + conn.commit() + + # Insert test data + with Session(initialized_engine) as session: + author = Author( + first_name="Jane", + last_name="Doe", + bio="Jane is an accomplished researcher in artificial intelligence and machine learning. She has published numerous papers on neural networks.", # noqa + ) + session.add(author) + session.commit() + + # Run vectorizer worker + with vcr_.use_cassette("test_vectorizer_composite_key.yaml"): + run_vectorizer_worker(db_url, 1) + + # Verify embeddings were created + with Session(initialized_engine) as session: + assert Author.bio_embeddings.__name__ == "BioEmbeddingsEmbedding" + + # Check embeddings exist and have correct properties + embedding = session.query(Author.bio_embeddings).first() + assert embedding is not None + assert isinstance(embedding.embedding, np.ndarray) + assert len(embedding.embedding) == 768 + assert embedding.chunk is not None + assert isinstance(embedding.chunk, str) + + # Check composite key fields were created + assert hasattr(embedding, "first_name") + assert hasattr(embedding, "last_name") + assert embedding.first_name == "Jane" # type: ignore + assert embedding.last_name == "Doe" # type: ignore + + # Verify relationship works + author = session.query(Author).first() + assert author is not None + assert hasattr(author, "bio_embeddings") + assert author.bio_embeddings is not None + assert len(author.bio_embeddings) > 0 # type: ignore + assert author.bio_embeddings[0].chunk in author.bio + + # Test that parent relationship works + embedding_entity = session.query(Author.bio_embeddings).first() + assert embedding_entity is not None + assert embedding_entity.chunk in author.bio + assert embedding_entity.parent is not None + assert embedding_entity.parent.first_name == "Jane" + assert embedding_entity.parent.last_name == "Doe" + + # Test semantic search with composite keys + from sqlalchemy import func + + # Search for content similar to "machine learning" + similar_embeddings = ( + session.query(Author.bio_embeddings) + .order_by( + Author.bio_embeddings.embedding.cosine_distance( + func.ai.openai_embed( + "text-embedding-3-small", + "machine learning", + text("dimensions => 768"), + ) + ) + ) + .all() + ) + + assert len(similar_embeddings) > 0 + # The bio should contain machine learning related content + assert "machine learning" in similar_embeddings[0].parent.bio diff --git a/projects/pgai/tests/vectorizer/extensions/test_sqlalchemy_large_embeddings.py b/projects/pgai/tests/vectorizer/extensions/test_sqlalchemy_large_embeddings.py new file mode 100644 index 000000000..7fd7ac44f --- /dev/null +++ b/projects/pgai/tests/vectorizer/extensions/test_sqlalchemy_large_embeddings.py @@ -0,0 +1,76 @@ +from typing import Any + +import numpy as np +from sqlalchemy import Column, Engine, Integer, Text +from sqlalchemy.orm import DeclarativeBase, Session +from sqlalchemy.sql import text +from testcontainers.postgres import PostgresContainer # type: ignore + +from pgai.sqlalchemy import vectorizer_relationship +from tests.vectorizer.extensions.utils import run_vectorizer_worker + + +class Base(DeclarativeBase): + pass + + +class BlogPost(Base): + __tablename__ = "blog_posts" + id = Column(Integer, primary_key=True) + title = Column(Text, nullable=False) + content = Column(Text, nullable=False) + content_embeddings = vectorizer_relationship(dimensions=1536) + + +def test_vectorizer_embedding_creation( + postgres_container: PostgresContainer, initialized_engine: Engine, vcr_: Any +): + """Test basic data insertion and embedding generation with default relationship.""" + db_url = postgres_container.get_connection_url() + # Create tables + metadata = BlogPost.metadata + metadata.create_all(initialized_engine, tables=[metadata.sorted_tables[0]]) + with initialized_engine.connect() as conn: + conn.execute( + text(""" + SELECT ai.create_vectorizer( + 'blog_posts'::regclass, + embedding => ai.embedding_openai('text-embedding-3-large', 1536), + chunking => ai.chunking_recursive_character_text_splitter('content') + ); + """) + ) + conn.commit() + + # Insert test data + with Session(initialized_engine) as session: + post = BlogPost( + title="Introduction to Machine Learning", + content="Machine learning is a subset of artificial intelligence that enables systems to learn and improve from experience.", # noqa + ) + session.add(post) + session.commit() + + with vcr_.use_cassette("test_vectorizer_large_mbedding_creation.yaml"): + # Run vectorizer worker + run_vectorizer_worker(db_url, 1) + + # Verify embeddings were created + with Session(initialized_engine) as session: + # Verify embedding class was created correctly + assert BlogPost.content_embeddings.__name__ == "ContentEmbeddingsEmbedding" + + # Check embeddings exist and have correct properties + embedding = session.query(BlogPost.content_embeddings).first() + assert embedding is not None + assert isinstance(embedding.embedding, np.ndarray) + assert len(embedding.embedding) == 1536 + assert embedding.chunk is not None # Should have chunk text + assert isinstance(embedding.chunk, str) + + blog_post = session.query(BlogPost).first() + assert blog_post is not None + + embedding_entity = session.query(BlogPost.content_embeddings).first() + assert embedding_entity is not None + assert embedding_entity.chunk in blog_post.content diff --git a/projects/pgai/tests/vectorizer/extensions/test_sqlalchemy_lazy_strategies.py b/projects/pgai/tests/vectorizer/extensions/test_sqlalchemy_lazy_strategies.py new file mode 100644 index 000000000..f9bae9694 --- /dev/null +++ b/projects/pgai/tests/vectorizer/extensions/test_sqlalchemy_lazy_strategies.py @@ -0,0 +1,86 @@ +from typing import Any + +from _pytest.logging import LogCaptureFixture +from sqlalchemy import Column, Engine, Integer, Text +from sqlalchemy.orm import DeclarativeBase, Session +from sqlalchemy.sql import text +from testcontainers.postgres import PostgresContainer # type: ignore + +from pgai.sqlalchemy import vectorizer_relationship +from tests.vectorizer.extensions.utils import run_vectorizer_worker + + +class Base(DeclarativeBase): + pass + + +class ArticleWithLazyStrategies(Base): + __tablename__ = "articles_lazy_test" + id = Column(Integer, primary_key=True) + title = Column(Text, nullable=False) + content = Column(Text, nullable=False) + + # Different vectorizers with different lazy loading strategies + embeddings = vectorizer_relationship(dimensions=768, lazy="joined") + + +def test_joined_loading( + postgres_container: PostgresContainer, + initialized_engine: Engine, + caplog: LogCaptureFixture, + vcr_: Any, +): + """Test the difference between select and joined loading strategies.""" + db_url = postgres_container.get_connection_url() + + # Create tables + + metadata = ArticleWithLazyStrategies.metadata + metadata.create_all(initialized_engine, tables=[metadata.sorted_tables[0]]) + + # Create vectorizers in database + with initialized_engine.connect() as conn: + conn.execute( + text(""" + SELECT ai.create_vectorizer( + 'articles_lazy_test'::regclass, + embedding => ai.embedding_openai('text-embedding-3-small', 768), + chunking => + ai.chunking_recursive_character_text_splitter('content', 50, 10) + ); + """) + ) + conn.commit() + + # Insert test data + with Session(initialized_engine) as session: + articles: list[ArticleWithLazyStrategies] = [] + for i in range(3): + article = ArticleWithLazyStrategies( + title=f"Test Article {i}", + content=f"This is test content {i} that will be embedded.", + ) + session.add(article) + articles.append(article) + # _ = article.embeddings + session.commit() + + # Run vectorizer worker for each vectorizer + with vcr_.use_cassette("test_joined_loading.yaml"): + run_vectorizer_worker(db_url, 1) + + with ( + Session(initialized_engine) as session, + caplog.at_level("DEBUG", "sqlalchemy.engine"), + ): + articles = session.query(ArticleWithLazyStrategies).all() + + initial_queries = [r.message for r in caplog.records if "SELECT" in r.message] + _ = [article.embeddings[0].chunk for article in articles] + after_select_queries = [ + r.message for r in caplog.records if "SELECT" in r.message + ] + assert len(after_select_queries) == len(initial_queries), ( + f"Should not trigger additional queries" + f" but queries were: {after_select_queries}" + ) diff --git a/projects/pgai/tests/vectorizer/extensions/test_sqlalchemy_relationship.py b/projects/pgai/tests/vectorizer/extensions/test_sqlalchemy_relationship.py new file mode 100644 index 000000000..5ee5ad42a --- /dev/null +++ b/projects/pgai/tests/vectorizer/extensions/test_sqlalchemy_relationship.py @@ -0,0 +1,90 @@ +from typing import Any + +import numpy as np +from sqlalchemy import Column, Engine, Integer, Text +from sqlalchemy.orm import DeclarativeBase, Session +from sqlalchemy.sql import text +from testcontainers.postgres import PostgresContainer # type: ignore + +from pgai.sqlalchemy import vectorizer_relationship +from tests.vectorizer.extensions.utils import run_vectorizer_worker + + +class Base(DeclarativeBase): + pass + + +class BlogPost(Base): + __tablename__ = "blog_posts" + id = Column(Integer, primary_key=True) + title = Column(Text, nullable=False) + content = Column(Text, nullable=False) + content_embeddings = vectorizer_relationship( + dimensions=768, + ) + + +def test_vectorizer_embedding_creation( + postgres_container: PostgresContainer, initialized_engine: Engine, vcr_: Any +): + """Test basic data insertion and embedding generation with default relationship.""" + db_url = postgres_container.get_connection_url() + # Create tables + metadata = BlogPost.metadata + metadata.create_all(initialized_engine, tables=[metadata.sorted_tables[0]]) + with initialized_engine.connect() as conn: + conn.execute( + text(""" + SELECT ai.create_vectorizer( + 'blog_posts'::regclass, + embedding => + ai.embedding_openai('text-embedding-3-small', 768), + chunking => + ai.chunking_recursive_character_text_splitter('content', 50, 10) + ); + """) + ) + conn.commit() + + # Insert test data + with Session(initialized_engine) as session: + post = BlogPost( + title="Introduction to Machine Learning", + content="Machine learning is a subset of artificial intelligence that enables systems to learn and improve from experience.", # noqa + ) + session.add(post) + session.commit() + + # Run vectorizer worker + with vcr_.use_cassette("test_vectorizer_embedding_creation_relationship.yaml"): + run_vectorizer_worker(db_url, 1) + + # Verify embeddings were created + with Session(initialized_engine) as session: + # Verify embedding class was created correctly + + blog_post = session.query(BlogPost).first() + assert blog_post is not None + assert blog_post.content_embeddings is not None + assert BlogPost.content_embeddings.__name__ == "ContentEmbeddingsEmbedding" + + # Check embeddings exist and have correct properties + embedding = session.query(BlogPost.content_embeddings).first() + assert embedding is not None + assert isinstance(embedding.embedding, np.ndarray) + assert len(embedding.embedding) == 768 + assert embedding.chunk is not None # Should have chunk text + assert isinstance(embedding.chunk, str) + + # Verify relationship works + blog_post = session.query(BlogPost).first() + assert blog_post is not None + assert hasattr(blog_post, "content_embeddings") + assert blog_post.content_embeddings is not None + assert len(blog_post.content_embeddings) > 0 # type: ignore + assert blog_post.content_embeddings[0].chunk in blog_post.content + + embedding_entity = session.query(BlogPost.content_embeddings).first() + assert embedding_entity is not None + assert embedding_entity.chunk in blog_post.content + assert embedding_entity.parent is not None diff --git a/projects/pgai/tests/vectorizer/extensions/utils.py b/projects/pgai/tests/vectorizer/extensions/utils.py new file mode 100644 index 000000000..a1f3553fa --- /dev/null +++ b/projects/pgai/tests/vectorizer/extensions/utils.py @@ -0,0 +1,19 @@ +from click.testing import CliRunner + +from pgai.cli import vectorizer_worker + + +def run_vectorizer_worker(db_url: str, vectorizer_id: int) -> None: + CliRunner().invoke( + vectorizer_worker, + [ + "--db-url", + db_url, + "--once", + "--vectorizer-id", + str(vectorizer_id), + "--concurrency", + "1", + ], + catch_exceptions=False, + ) diff --git a/projects/pgai/uv.lock b/projects/pgai/uv.lock index 386ef1a5e..a0d7a885e 100644 --- a/projects/pgai/uv.lock +++ b/projects/pgai/uv.lock @@ -581,6 +581,57 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c6/b2/454d6e7f0158951d8a78c2e1eb4f69ae81beb8dca5fee9809c6c99e9d0d0/fsspec-2024.10.0-py3-none-any.whl", hash = "sha256:03b9a6785766a4de40368b88906366755e2819e758b83705c88cd7cb5fe81871", size = 179641 }, ] +[[package]] +name = "greenlet" +version = "3.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2f/ff/df5fede753cc10f6a5be0931204ea30c35fa2f2ea7a35b25bdaf4fe40e46/greenlet-3.1.1.tar.gz", hash = "sha256:4ce3ac6cdb6adf7946475d7ef31777c26d94bccc377e070a7986bd2d5c515467", size = 186022 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/90/5234a78dc0ef6496a6eb97b67a42a8e96742a56f7dc808cb954a85390448/greenlet-3.1.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:0bbae94a29c9e5c7e4a2b7f0aae5c17e8e90acbfd3bf6270eeba60c39fce3563", size = 271235 }, + { url = "https://files.pythonhosted.org/packages/7c/16/cd631fa0ab7d06ef06387135b7549fdcc77d8d859ed770a0d28e47b20972/greenlet-3.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fde093fb93f35ca72a556cf72c92ea3ebfda3d79fc35bb19fbe685853869a83", size = 637168 }, + { url = "https://files.pythonhosted.org/packages/2f/b1/aed39043a6fec33c284a2c9abd63ce191f4f1a07319340ffc04d2ed3256f/greenlet-3.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:36b89d13c49216cadb828db8dfa6ce86bbbc476a82d3a6c397f0efae0525bdd0", size = 648826 }, + { url = "https://files.pythonhosted.org/packages/76/25/40e0112f7f3ebe54e8e8ed91b2b9f970805143efef16d043dfc15e70f44b/greenlet-3.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94b6150a85e1b33b40b1464a3f9988dcc5251d6ed06842abff82e42632fac120", size = 644443 }, + { url = "https://files.pythonhosted.org/packages/fb/2f/3850b867a9af519794784a7eeed1dd5bc68ffbcc5b28cef703711025fd0a/greenlet-3.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93147c513fac16385d1036b7e5b102c7fbbdb163d556b791f0f11eada7ba65dc", size = 643295 }, + { url = "https://files.pythonhosted.org/packages/cf/69/79e4d63b9387b48939096e25115b8af7cd8a90397a304f92436bcb21f5b2/greenlet-3.1.1-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da7a9bff22ce038e19bf62c4dd1ec8391062878710ded0a845bcf47cc0200617", size = 599544 }, + { url = "https://files.pythonhosted.org/packages/46/1d/44dbcb0e6c323bd6f71b8c2f4233766a5faf4b8948873225d34a0b7efa71/greenlet-3.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b2795058c23988728eec1f36a4e5e4ebad22f8320c85f3587b539b9ac84128d7", size = 1125456 }, + { url = "https://files.pythonhosted.org/packages/e0/1d/a305dce121838d0278cee39d5bb268c657f10a5363ae4b726848f833f1bb/greenlet-3.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ed10eac5830befbdd0c32f83e8aa6288361597550ba669b04c48f0f9a2c843c6", size = 1149111 }, + { url = "https://files.pythonhosted.org/packages/96/28/d62835fb33fb5652f2e98d34c44ad1a0feacc8b1d3f1aecab035f51f267d/greenlet-3.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:77c386de38a60d1dfb8e55b8c1101d68c79dfdd25c7095d51fec2dd800892b80", size = 298392 }, + { url = "https://files.pythonhosted.org/packages/28/62/1c2665558618553c42922ed47a4e6d6527e2fa3516a8256c2f431c5d0441/greenlet-3.1.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e4d333e558953648ca09d64f13e6d8f0523fa705f51cae3f03b5983489958c70", size = 272479 }, + { url = "https://files.pythonhosted.org/packages/76/9d/421e2d5f07285b6e4e3a676b016ca781f63cfe4a0cd8eaecf3fd6f7a71ae/greenlet-3.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fc016b73c94e98e29af67ab7b9a879c307c6731a2c9da0db5a7d9b7edd1159", size = 640404 }, + { url = "https://files.pythonhosted.org/packages/e5/de/6e05f5c59262a584e502dd3d261bbdd2c97ab5416cc9c0b91ea38932a901/greenlet-3.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5e975ca70269d66d17dd995dafc06f1b06e8cb1ec1e9ed54c1d1e4a7c4cf26e", size = 652813 }, + { url = "https://files.pythonhosted.org/packages/49/93/d5f93c84241acdea15a8fd329362c2c71c79e1a507c3f142a5d67ea435ae/greenlet-3.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b2813dc3de8c1ee3f924e4d4227999285fd335d1bcc0d2be6dc3f1f6a318ec1", size = 648517 }, + { url = "https://files.pythonhosted.org/packages/15/85/72f77fc02d00470c86a5c982b8daafdf65d38aefbbe441cebff3bf7037fc/greenlet-3.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e347b3bfcf985a05e8c0b7d462ba6f15b1ee1c909e2dcad795e49e91b152c383", size = 647831 }, + { url = "https://files.pythonhosted.org/packages/f7/4b/1c9695aa24f808e156c8f4813f685d975ca73c000c2a5056c514c64980f6/greenlet-3.1.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e8f8c9cb53cdac7ba9793c276acd90168f416b9ce36799b9b885790f8ad6c0a", size = 602413 }, + { url = "https://files.pythonhosted.org/packages/76/70/ad6e5b31ef330f03b12559d19fda2606a522d3849cde46b24f223d6d1619/greenlet-3.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:62ee94988d6b4722ce0028644418d93a52429e977d742ca2ccbe1c4f4a792511", size = 1129619 }, + { url = "https://files.pythonhosted.org/packages/f4/fb/201e1b932e584066e0f0658b538e73c459b34d44b4bd4034f682423bc801/greenlet-3.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1776fd7f989fc6b8d8c8cb8da1f6b82c5814957264d1f6cf818d475ec2bf6395", size = 1155198 }, + { url = "https://files.pythonhosted.org/packages/12/da/b9ed5e310bb8b89661b80cbcd4db5a067903bbcd7fc854923f5ebb4144f0/greenlet-3.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:48ca08c771c268a768087b408658e216133aecd835c0ded47ce955381105ba39", size = 298930 }, + { url = "https://files.pythonhosted.org/packages/7d/ec/bad1ac26764d26aa1353216fcbfa4670050f66d445448aafa227f8b16e80/greenlet-3.1.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:4afe7ea89de619adc868e087b4d2359282058479d7cfb94970adf4b55284574d", size = 274260 }, + { url = "https://files.pythonhosted.org/packages/66/d4/c8c04958870f482459ab5956c2942c4ec35cac7fe245527f1039837c17a9/greenlet-3.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f406b22b7c9a9b4f8aa9d2ab13d6ae0ac3e85c9a809bd590ad53fed2bf70dc79", size = 649064 }, + { url = "https://files.pythonhosted.org/packages/51/41/467b12a8c7c1303d20abcca145db2be4e6cd50a951fa30af48b6ec607581/greenlet-3.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c3a701fe5a9695b238503ce5bbe8218e03c3bcccf7e204e455e7462d770268aa", size = 663420 }, + { url = "https://files.pythonhosted.org/packages/27/8f/2a93cd9b1e7107d5c7b3b7816eeadcac2ebcaf6d6513df9abaf0334777f6/greenlet-3.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2846930c65b47d70b9d178e89c7e1a69c95c1f68ea5aa0a58646b7a96df12441", size = 658035 }, + { url = "https://files.pythonhosted.org/packages/57/5c/7c6f50cb12be092e1dccb2599be5a942c3416dbcfb76efcf54b3f8be4d8d/greenlet-3.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99cfaa2110534e2cf3ba31a7abcac9d328d1d9f1b95beede58294a60348fba36", size = 660105 }, + { url = "https://files.pythonhosted.org/packages/f1/66/033e58a50fd9ec9df00a8671c74f1f3a320564c6415a4ed82a1c651654ba/greenlet-3.1.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1443279c19fca463fc33e65ef2a935a5b09bb90f978beab37729e1c3c6c25fe9", size = 613077 }, + { url = "https://files.pythonhosted.org/packages/19/c5/36384a06f748044d06bdd8776e231fadf92fc896bd12cb1c9f5a1bda9578/greenlet-3.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b7cede291382a78f7bb5f04a529cb18e068dd29e0fb27376074b6d0317bf4dd0", size = 1135975 }, + { url = "https://files.pythonhosted.org/packages/38/f9/c0a0eb61bdf808d23266ecf1d63309f0e1471f284300ce6dac0ae1231881/greenlet-3.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:23f20bb60ae298d7d8656c6ec6db134bca379ecefadb0b19ce6f19d1f232a942", size = 1163955 }, + { url = "https://files.pythonhosted.org/packages/43/21/a5d9df1d21514883333fc86584c07c2b49ba7c602e670b174bd73cfc9c7f/greenlet-3.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:7124e16b4c55d417577c2077be379514321916d5790fa287c9ed6f23bd2ffd01", size = 299655 }, + { url = "https://files.pythonhosted.org/packages/f3/57/0db4940cd7bb461365ca8d6fd53e68254c9dbbcc2b452e69d0d41f10a85e/greenlet-3.1.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:05175c27cb459dcfc05d026c4232f9de8913ed006d42713cb8a5137bd49375f1", size = 272990 }, + { url = "https://files.pythonhosted.org/packages/1c/ec/423d113c9f74e5e402e175b157203e9102feeb7088cee844d735b28ef963/greenlet-3.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:935e943ec47c4afab8965954bf49bfa639c05d4ccf9ef6e924188f762145c0ff", size = 649175 }, + { url = "https://files.pythonhosted.org/packages/a9/46/ddbd2db9ff209186b7b7c621d1432e2f21714adc988703dbdd0e65155c77/greenlet-3.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667a9706c970cb552ede35aee17339a18e8f2a87a51fba2ed39ceeeb1004798a", size = 663425 }, + { url = "https://files.pythonhosted.org/packages/bc/f9/9c82d6b2b04aa37e38e74f0c429aece5eeb02bab6e3b98e7db89b23d94c6/greenlet-3.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8a678974d1f3aa55f6cc34dc480169d58f2e6d8958895d68845fa4ab566509e", size = 657736 }, + { url = "https://files.pythonhosted.org/packages/d9/42/b87bc2a81e3a62c3de2b0d550bf91a86939442b7ff85abb94eec3fc0e6aa/greenlet-3.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efc0f674aa41b92da8c49e0346318c6075d734994c3c4e4430b1c3f853e498e4", size = 660347 }, + { url = "https://files.pythonhosted.org/packages/37/fa/71599c3fd06336cdc3eac52e6871cfebab4d9d70674a9a9e7a482c318e99/greenlet-3.1.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e", size = 615583 }, + { url = "https://files.pythonhosted.org/packages/4e/96/e9ef85de031703ee7a4483489b40cf307f93c1824a02e903106f2ea315fe/greenlet-3.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:275f72decf9932639c1c6dd1013a1bc266438eb32710016a1c742df5da6e60a1", size = 1133039 }, + { url = "https://files.pythonhosted.org/packages/87/76/b2b6362accd69f2d1889db61a18c94bc743e961e3cab344c2effaa4b4a25/greenlet-3.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c4aab7f6381f38a4b42f269057aee279ab0fc7bf2e929e3d4abfae97b682a12c", size = 1160716 }, + { url = "https://files.pythonhosted.org/packages/1f/1b/54336d876186920e185066d8c3024ad55f21d7cc3683c856127ddb7b13ce/greenlet-3.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:b42703b1cf69f2aa1df7d1030b9d77d3e584a70755674d60e710f0af570f3761", size = 299490 }, + { url = "https://files.pythonhosted.org/packages/5f/17/bea55bf36990e1638a2af5ba10c1640273ef20f627962cf97107f1e5d637/greenlet-3.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1695e76146579f8c06c1509c7ce4dfe0706f49c6831a817ac04eebb2fd02011", size = 643731 }, + { url = "https://files.pythonhosted.org/packages/78/d2/aa3d2157f9ab742a08e0fd8f77d4699f37c22adfbfeb0c610a186b5f75e0/greenlet-3.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7876452af029456b3f3549b696bb36a06db7c90747740c5302f74a9e9fa14b13", size = 649304 }, + { url = "https://files.pythonhosted.org/packages/f1/8e/d0aeffe69e53ccff5a28fa86f07ad1d2d2d6537a9506229431a2a02e2f15/greenlet-3.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ead44c85f8ab905852d3de8d86f6f8baf77109f9da589cb4fa142bd3b57b475", size = 646537 }, + { url = "https://files.pythonhosted.org/packages/05/79/e15408220bbb989469c8871062c97c6c9136770657ba779711b90870d867/greenlet-3.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8320f64b777d00dd7ccdade271eaf0cad6636343293a25074cc5566160e4de7b", size = 642506 }, + { url = "https://files.pythonhosted.org/packages/18/87/470e01a940307796f1d25f8167b551a968540fbe0551c0ebb853cb527dd6/greenlet-3.1.1-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6510bf84a6b643dabba74d3049ead221257603a253d0a9873f55f6a59a65f822", size = 602753 }, + { url = "https://files.pythonhosted.org/packages/e2/72/576815ba674eddc3c25028238f74d7b8068902b3968cbe456771b166455e/greenlet-3.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:04b013dc07c96f83134b1e99888e7a79979f1a247e2a9f59697fa14b5862ed01", size = 1122731 }, + { url = "https://files.pythonhosted.org/packages/ac/38/08cc303ddddc4b3d7c628c3039a61a3aae36c241ed01393d00c2fd663473/greenlet-3.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6", size = 1142112 }, +] + [[package]] name = "h11" version = "0.14.0" @@ -1181,10 +1232,16 @@ dependencies = [ { name = "voyageai" }, ] +[package.optional-dependencies] +sqlalchemy = [ + { name = "sqlalchemy" }, +] + [package.dev-dependencies] dev = [ { name = "build" }, { name = "psycopg", extra = ["binary"] }, + { name = "psycopg2" }, { name = "pyright" }, { name = "pytest" }, { name = "python-dotenv" }, @@ -1207,6 +1264,7 @@ requires-dist = [ { name = "pydantic", specifier = ">=2.0,<3.0" }, { name = "python-dotenv", specifier = ">=1.0,<2.0" }, { name = "pytimeparse", specifier = ">=1.1,<2.0" }, + { name = "sqlalchemy", marker = "extra == 'sqlalchemy'", specifier = ">=2.0.36" }, { name = "structlog", specifier = ">=24.0,<25.0" }, { name = "tiktoken", specifier = ">=0.7,<1.0" }, { name = "typing-extensions", specifier = ">=4.0,<5.0" }, @@ -1217,6 +1275,7 @@ requires-dist = [ dev = [ { name = "build", specifier = "==1.2.2.post1" }, { name = "psycopg", extras = ["binary"], specifier = "==3.2.1" }, + { name = "psycopg2", specifier = "==2.9.10" }, { name = "pyright", specifier = "==1.1.385" }, { name = "pytest", specifier = "==8.3.2" }, { name = "python-dotenv", specifier = "==1.0.1" }, @@ -1468,6 +1527,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/60/2f/979228189adbeb59afce626f1e7c3bf73cc7ff94217099a2ddfd6fd132ff/psycopg_binary-3.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:334046a937bb086c36e2c6889fe327f9f29bfc085d678f70fac0b0618949f674", size = 2911959 }, ] +[[package]] +name = "psycopg2" +version = "2.9.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/62/51/2007ea29e605957a17ac6357115d0c1a1b60c8c984951c19419b3474cdfd/psycopg2-2.9.10.tar.gz", hash = "sha256:12ec0b40b0273f95296233e8750441339298e6a572f7039da5b260e3c8b60e11", size = 385672 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/a9/146b6bdc0d33539a359f5e134ee6dda9173fb8121c5b96af33fa299e50c4/psycopg2-2.9.10-cp310-cp310-win32.whl", hash = "sha256:5df2b672140f95adb453af93a7d669d7a7bf0a56bcd26f1502329166f4a61716", size = 1024527 }, + { url = "https://files.pythonhosted.org/packages/47/50/c509e56f725fd2572b59b69bd964edaf064deebf1c896b2452f6b46fdfb3/psycopg2-2.9.10-cp310-cp310-win_amd64.whl", hash = "sha256:c6f7b8561225f9e711a9c47087388a97fdc948211c10a4bccbf0ba68ab7b3b5a", size = 1163735 }, + { url = "https://files.pythonhosted.org/packages/20/a2/c51ca3e667c34e7852157b665e3d49418e68182081060231d514dd823225/psycopg2-2.9.10-cp311-cp311-win32.whl", hash = "sha256:47c4f9875125344f4c2b870e41b6aad585901318068acd01de93f3677a6522c2", size = 1024538 }, + { url = "https://files.pythonhosted.org/packages/33/39/5a9a229bb5414abeb86e33b8fc8143ab0aecce5a7f698a53e31367d30caa/psycopg2-2.9.10-cp311-cp311-win_amd64.whl", hash = "sha256:0435034157049f6846e95103bd8f5a668788dd913a7c30162ca9503fdf542cb4", size = 1163736 }, + { url = "https://files.pythonhosted.org/packages/3d/16/4623fad6076448df21c1a870c93a9774ad8a7b4dd1660223b59082dd8fec/psycopg2-2.9.10-cp312-cp312-win32.whl", hash = "sha256:65a63d7ab0e067e2cdb3cf266de39663203d38d6a8ed97f5ca0cb315c73fe067", size = 1025113 }, + { url = "https://files.pythonhosted.org/packages/66/de/baed128ae0fc07460d9399d82e631ea31a1f171c0c4ae18f9808ac6759e3/psycopg2-2.9.10-cp312-cp312-win_amd64.whl", hash = "sha256:4a579d6243da40a7b3182e0430493dbd55950c493d8c68f4eec0b302f6bbf20e", size = 1163951 }, +] + [[package]] name = "pycparser" version = "2.22" @@ -1885,6 +1958,51 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] +[[package]] +name = "sqlalchemy" +version = "2.0.36" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "greenlet", marker = "(python_full_version < '3.13' and platform_machine == 'AMD64') or (python_full_version < '3.13' and platform_machine == 'WIN32') or (python_full_version < '3.13' and platform_machine == 'aarch64') or (python_full_version < '3.13' and platform_machine == 'amd64') or (python_full_version < '3.13' and platform_machine == 'ppc64le') or (python_full_version < '3.13' and platform_machine == 'win32') or (python_full_version < '3.13' and platform_machine == 'x86_64')" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/65/9cbc9c4c3287bed2499e05033e207473504dc4df999ce49385fb1f8b058a/sqlalchemy-2.0.36.tar.gz", hash = "sha256:7f2767680b6d2398aea7082e45a774b2b0767b5c8d8ffb9c8b683088ea9b29c5", size = 9574485 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/72/14ab694b8b3f0e35ef5beb74a8fea2811aa791ba1611c44dc90cdf46af17/SQLAlchemy-2.0.36-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:59b8f3adb3971929a3e660337f5dacc5942c2cdb760afcabb2614ffbda9f9f72", size = 2092604 }, + { url = "https://files.pythonhosted.org/packages/1e/59/333fcbca58b79f5b8b61853d6137530198823392151fa8fd9425f367519e/SQLAlchemy-2.0.36-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37350015056a553e442ff672c2d20e6f4b6d0b2495691fa239d8aa18bb3bc908", size = 2083796 }, + { url = "https://files.pythonhosted.org/packages/6c/a0/ec3c188d2b0c1bc742262e76408d44104598d7247c23f5b06bb97ee21bfa/SQLAlchemy-2.0.36-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8318f4776c85abc3f40ab185e388bee7a6ea99e7fa3a30686580b209eaa35c08", size = 3066165 }, + { url = "https://files.pythonhosted.org/packages/07/15/68ef91de5b8b7f80fb2d2b3b31ed42180c6227fe0a701aed9d01d34f98ec/SQLAlchemy-2.0.36-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c245b1fbade9c35e5bd3b64270ab49ce990369018289ecfde3f9c318411aaa07", size = 3074428 }, + { url = "https://files.pythonhosted.org/packages/e2/4c/9dfea5e63b87325eef6d9cdaac913459aa6a157a05a05ea6ff20004aee8e/SQLAlchemy-2.0.36-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:69f93723edbca7342624d09f6704e7126b152eaed3cdbb634cb657a54332a3c5", size = 3030477 }, + { url = "https://files.pythonhosted.org/packages/16/a5/fcfde8e74ea5f683b24add22463bfc21e431d4a5531c8a5b55bc6fbea164/SQLAlchemy-2.0.36-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f9511d8dd4a6e9271d07d150fb2f81874a3c8c95e11ff9af3a2dfc35fe42ee44", size = 3055942 }, + { url = "https://files.pythonhosted.org/packages/3c/ee/c22c415a771d791ae99146d72ffdb20e43625acd24835ea7fc157436d59f/SQLAlchemy-2.0.36-cp310-cp310-win32.whl", hash = "sha256:c3f3631693003d8e585d4200730616b78fafd5a01ef8b698f6967da5c605b3fa", size = 2064960 }, + { url = "https://files.pythonhosted.org/packages/aa/af/ad9c25cadc79bd851bdb9d82b68af9bdb91ff05f56d0da2f8a654825974f/SQLAlchemy-2.0.36-cp310-cp310-win_amd64.whl", hash = "sha256:a86bfab2ef46d63300c0f06936bd6e6c0105faa11d509083ba8f2f9d237fb5b5", size = 2089078 }, + { url = "https://files.pythonhosted.org/packages/00/4e/5a67963fd7cbc1beb8bd2152e907419f4c940ef04600b10151a751fe9e06/SQLAlchemy-2.0.36-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fd3a55deef00f689ce931d4d1b23fa9f04c880a48ee97af488fd215cf24e2a6c", size = 2093782 }, + { url = "https://files.pythonhosted.org/packages/b3/24/30e33b6389ebb5a17df2a4243b091bc709fb3dfc9a48c8d72f8e037c943d/SQLAlchemy-2.0.36-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4f5e9cd989b45b73bd359f693b935364f7e1f79486e29015813c338450aa5a71", size = 2084180 }, + { url = "https://files.pythonhosted.org/packages/10/1e/70e9ed2143a27065246be40f78637ad5160ea0f5fd32f8cab819a31ff54d/SQLAlchemy-2.0.36-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0ddd9db6e59c44875211bc4c7953a9f6638b937b0a88ae6d09eb46cced54eff", size = 3202469 }, + { url = "https://files.pythonhosted.org/packages/b4/5f/95e0ed74093ac3c0db6acfa944d4d8ac6284ef5e1136b878a327ea1f975a/SQLAlchemy-2.0.36-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2519f3a5d0517fc159afab1015e54bb81b4406c278749779be57a569d8d1bb0d", size = 3202464 }, + { url = "https://files.pythonhosted.org/packages/91/95/2cf9b85a6bc2ee660e40594dffe04e777e7b8617fd0c6d77a0f782ea96c9/SQLAlchemy-2.0.36-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59b1ee96617135f6e1d6f275bbe988f419c5178016f3d41d3c0abb0c819f75bb", size = 3139508 }, + { url = "https://files.pythonhosted.org/packages/92/ea/f0c01bc646456e4345c0fb5a3ddef457326285c2dc60435b0eb96b61bf31/SQLAlchemy-2.0.36-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:39769a115f730d683b0eb7b694db9789267bcd027326cccc3125e862eb03bfd8", size = 3159837 }, + { url = "https://files.pythonhosted.org/packages/a6/93/c8edbf153ee38fe529773240877bf1332ed95328aceef6254288f446994e/SQLAlchemy-2.0.36-cp311-cp311-win32.whl", hash = "sha256:66bffbad8d6271bb1cc2f9a4ea4f86f80fe5e2e3e501a5ae2a3dc6a76e604e6f", size = 2064529 }, + { url = "https://files.pythonhosted.org/packages/b1/03/d12b7c1d36fd80150c1d52e121614cf9377dac99e5497af8d8f5b2a8db64/SQLAlchemy-2.0.36-cp311-cp311-win_amd64.whl", hash = "sha256:23623166bfefe1487d81b698c423f8678e80df8b54614c2bf4b4cfcd7c711959", size = 2089874 }, + { url = "https://files.pythonhosted.org/packages/b8/bf/005dc47f0e57556e14512d5542f3f183b94fde46e15ff1588ec58ca89555/SQLAlchemy-2.0.36-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7b64e6ec3f02c35647be6b4851008b26cff592a95ecb13b6788a54ef80bbdd4", size = 2092378 }, + { url = "https://files.pythonhosted.org/packages/94/65/f109d5720779a08e6e324ec89a744f5f92c48bd8005edc814bf72fbb24e5/SQLAlchemy-2.0.36-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:46331b00096a6db1fdc052d55b101dbbfc99155a548e20a0e4a8e5e4d1362855", size = 2082778 }, + { url = "https://files.pythonhosted.org/packages/60/f6/d9aa8c49c44f9b8c9b9dada1f12fa78df3d4c42aa2de437164b83ee1123c/SQLAlchemy-2.0.36-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdf3386a801ea5aba17c6410dd1dc8d39cf454ca2565541b5ac42a84e1e28f53", size = 3232191 }, + { url = "https://files.pythonhosted.org/packages/8a/ab/81d4514527c068670cb1d7ab62a81a185df53a7c379bd2a5636e83d09ede/SQLAlchemy-2.0.36-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac9dfa18ff2a67b09b372d5db8743c27966abf0e5344c555d86cc7199f7ad83a", size = 3243044 }, + { url = "https://files.pythonhosted.org/packages/35/b4/f87c014ecf5167dc669199cafdb20a7358ff4b1d49ce3622cc48571f811c/SQLAlchemy-2.0.36-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:90812a8933df713fdf748b355527e3af257a11e415b613dd794512461eb8a686", size = 3178511 }, + { url = "https://files.pythonhosted.org/packages/ea/09/badfc9293bc3ccba6ede05e5f2b44a760aa47d84da1fc5a326e963e3d4d9/SQLAlchemy-2.0.36-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1bc330d9d29c7f06f003ab10e1eaced295e87940405afe1b110f2eb93a233588", size = 3205147 }, + { url = "https://files.pythonhosted.org/packages/c8/60/70e681de02a13c4b27979b7b78da3058c49bacc9858c89ba672e030f03f2/SQLAlchemy-2.0.36-cp312-cp312-win32.whl", hash = "sha256:79d2e78abc26d871875b419e1fd3c0bca31a1cb0043277d0d850014599626c2e", size = 2062709 }, + { url = "https://files.pythonhosted.org/packages/b7/ed/f6cd9395e41bfe47dd253d74d2dfc3cab34980d4e20c8878cb1117306085/SQLAlchemy-2.0.36-cp312-cp312-win_amd64.whl", hash = "sha256:b544ad1935a8541d177cb402948b94e871067656b3a0b9e91dbec136b06a2ff5", size = 2088433 }, + { url = "https://files.pythonhosted.org/packages/78/5c/236398ae3678b3237726819b484f15f5c038a9549da01703a771f05a00d6/SQLAlchemy-2.0.36-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b5cc79df7f4bc3d11e4b542596c03826063092611e481fcf1c9dfee3c94355ef", size = 2087651 }, + { url = "https://files.pythonhosted.org/packages/a8/14/55c47420c0d23fb67a35af8be4719199b81c59f3084c28d131a7767b0b0b/SQLAlchemy-2.0.36-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3c01117dd36800f2ecaa238c65365b7b16497adc1522bf84906e5710ee9ba0e8", size = 2078132 }, + { url = "https://files.pythonhosted.org/packages/3d/97/1e843b36abff8c4a7aa2e37f9bea364f90d021754c2de94d792c2d91405b/SQLAlchemy-2.0.36-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bc633f4ee4b4c46e7adcb3a9b5ec083bf1d9a97c1d3854b92749d935de40b9b", size = 3164559 }, + { url = "https://files.pythonhosted.org/packages/7b/c5/07f18a897b997f6d6b234fab2bf31dccf66d5d16a79fe329aefc95cd7461/SQLAlchemy-2.0.36-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e46ed38affdfc95d2c958de328d037d87801cfcbea6d421000859e9789e61c2", size = 3177897 }, + { url = "https://files.pythonhosted.org/packages/b3/cd/e16f3cbefd82b5c40b33732da634ec67a5f33b587744c7ab41699789d492/SQLAlchemy-2.0.36-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b2985c0b06e989c043f1dc09d4fe89e1616aadd35392aea2844f0458a989eacf", size = 3111289 }, + { url = "https://files.pythonhosted.org/packages/15/85/5b8a3b0bc29c9928aa62b5c91fcc8335f57c1de0a6343873b5f372e3672b/SQLAlchemy-2.0.36-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a121d62ebe7d26fec9155f83f8be5189ef1405f5973ea4874a26fab9f1e262c", size = 3139491 }, + { url = "https://files.pythonhosted.org/packages/a1/95/81babb6089938680dfe2cd3f88cd3fd39cccd1543b7cb603b21ad881bff1/SQLAlchemy-2.0.36-cp313-cp313-win32.whl", hash = "sha256:0572f4bd6f94752167adfd7c1bed84f4b240ee6203a95e05d1e208d488d0d436", size = 2060439 }, + { url = "https://files.pythonhosted.org/packages/c1/ce/5f7428df55660d6879d0522adc73a3364970b5ef33ec17fa125c5dbcac1d/SQLAlchemy-2.0.36-cp313-cp313-win_amd64.whl", hash = "sha256:8c78ac40bde930c60e0f78b3cd184c580f89456dd87fc08f9e3ee3ce8765ce88", size = 2084574 }, + { url = "https://files.pythonhosted.org/packages/b8/49/21633706dd6feb14cd3f7935fc00b60870ea057686035e1a99ae6d9d9d53/SQLAlchemy-2.0.36-py3-none-any.whl", hash = "sha256:fddbe92b4760c6f5d48162aef14824add991aeda8ddadb3c31d56eb15ca69f8e", size = 1883787 }, +] + [[package]] name = "structlog" version = "24.4.0"