diff --git a/README.md b/README.md index a1976f3..ab2d73f 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,92 @@ -# Python Contrib +# Голосовой Ассистент на Langchain (OpenAI) -Python packages mono-repository +## Описание проекта -## Development +Этот проект представляет собой голосового ассистента, разработанного в рамках дипломного проекта для Яндекс.Практикума. +Ассистент основан на технологиях OpenAI и предназначен для поиска информации о фильмах в нашем сервисе кинотеатра. -### Global dependencies +## Что удалось реализовать? -- node -- poetry +### +- Организация кодовой базы по [шаблону DDD](https://github.com/yp-middle-python-24/python-service-example/) +- Speech To Text на базе [Whisper](https://openai.com/research/whisper) от OpenAI +- LLM: + - Получение embeddings для фильмов в векторную базу данных pgvector + - Поиск фильмов по embeddings + - Получение информации о конкретном фильме по embeddings + - Сохранение истории диалогов с ассистентом +- Text to speech на базе [Yanex SpeechKit](https://cloud.yandex.ru/services/speechkit) и [ElevenLabs](https://elevenlabs.io/) +- Клиент для работы с сервисом на базе Telegram-бота -### Makefile commands +## Команда: -#### Root commands +- [Артем](https://github.com/ijaric/python-monorepo/commits?author=ijaric) +- [Александр](https://github.com/ksieuk) +- [Алексей](https://github.com/grucshetskyaleksei) -- `make init` - Initialize repository -- `make lint` - Lint repository -- `make lint-fix` - Auto-fix repository -- `make test` - Test repository -- `make clean` - Clean up repository -- `make all-init` - Init all packages -- `make all-lint` - Lint all packages -- `make all-lint-fix` - Auto-fix all packages -- `make all-test` - Test all packages -- `make all-clean` - Clean all packages -- `make all-dependencies-update` - Update dependencies in all packages -- `make ci-init` - CI-specific version of init command +## Как запустить проект? +1. Скачать [файл базы данных](https://disk.yandex.ru/d/ZAKDDg8lP9DHBQ) с `embeddings` и поместить её по пути `src/assistant/data/dump.sql`. -#### Common package commands +2. В директории `src/assistant` файл `.env.example` переименовать в `.env` и заполнить переменные окружения. +Пример заполнения переменных окружения: +``` +POSTGRES_DRIVER=postgresql+asyncpg # Драйвер для работы с базой данных +POSTGRES_HOST=db # Хост базы данных +POSTGRES_PORT=5432 # Порт базы данных +POSTGRES_USER=app # Пользователь базы данных +POSTGRES_PASSWORD=123qwe # Пароль пользователя базы данных +POSTGRES_DB_NAME=movies_database # Название базы данных -- `make init` - Initialize package -- `make lint` - Lint package -- `make lint-fix` - Auto-fix package -- `make test` - Test package -- `make clean` - Clean up package folder -- `make dependencies-update` - Update not restricted dependencies -- `PYPI_WRITER_PASSWORD=... make ci-login-pypi-publish` - Login to personal pypi with publish rights -- `make ci-test` - Test package in CI -- `make ci-package-build` - Builds package in CI -- `make ci-package-publish` - Publishes package in CI +NGINX_PORT=80 # Порт nginx +API_HOST=0.0.0.0 # Хост API +API_PORT=8000 # Порт API + +JWT_SECRET_KEY=secret # Секретный ключ для JWT +JWT_ALGORITHM=HS256 # Алгоритм шифрования JWT + +APP_RELOAD=True # Автоматическая перезагрузка приложения + +VOICE_AVAILABLE_FORMATS=mp3,ogg,wav,oga # Доступные форматы аудиофайлов +VOICE_MAX_INPUT_SIZE=5120 # Максимальный размер входного аудиофайла в килобайтах +VOICE_MAX_INPUT_SECONDS=30 # Максимальная длительность входного аудиофайла в секундах + +OPENAI_API_KEY=sk-1234567890 # API-ключ OpenAI +OPENAI_STT_MODEL=whisper-1 # Модель для распознавания речи + +PROXY_HOST=123.123.123.123 # Хост прокси +PROXY_PORT=1234 # Порт прокси +PROXY_USER=proxy_user # Пользователь прокси +PROXY_PASSWORD=proxy_password # Пароль прокси +PROXY_ENABLE=True # Включить прокси + +TTS_YANDEX_API_KEY=1234567890 # API-ключ Yandex SpeechKit +TTS_YANDEX_AUDIO_FORMAT=oggopus # Формат аудиофайла +TTS_YANDEX_SAMPLE_RATE_HERTZ=48000 # Частота дискретизации аудиофайла + +TTS_ELEVEN_LABS_API_KEY=1234567890 # API-ключ ElevenLabs +TTS_ELEVEN_LABS_DEFAULT_VOICE_ID=EXAVITQu4vr4xnSDxMaL # ID голоса по умолчанию +``` + +3. В директории `src/bot_aiogram` файл `.env.example` переименовать в `.env` и заполнить переменные окружения. +Пример заполнения переменных окружения: + +``` +BOT_CONTAINER_NAME=bot_container_name # Название контейнера +BOT_IMAGE_NAME=botimage_name # Название образа +BOT_NAME=mybotname # Название бота +BOT_TOKEN=1234567890:ABCdefghIJKlmnopQRStuVWXYz # Токен бота +BOT_ADMINS=1234567890,9876543210 # ID администраторов бота через запятую + +API_PROTOCOL=http # Протокол API +API_URL=api# URL API +API_PORT=8000 # Порт API + +REDIS_HOST=redis # Хост Redis +REDIS_PORT=6379 # Порт Redis +``` + +3. Запустить проект командой `docker-compose up -d` + +### Важно! +Для работы с Telegram-ботом необходимо предварительно начать с ним диалог и отключить в параметрах конфиденциальности +вашего аккаунта запрет на голосовые сообщения. diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..ed9d75a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,85 @@ +version: "3" + +services: + postgres: + image: ankane/pgvector:v0.5.0 + restart: always + environment: + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: ${POSTGRES_NAME} + env_file: + - ./src/assistant/.env + expose: + - "${POSTGRES_PORT}" + volumes: + - - ./src/assistant/dump.sql:/docker-entrypoint-initdb.d/dump.sql:ro + networks: + - backend_network + + api: + build: + context: . + container_name: api + image: fastapi_app + restart: always + entrypoint: ["/opt/app/entrypoint.sh"] + env_file: + - ./src/assistant/.env + expose: + - "${API_PORT}" + depends_on: + - postgres + networks: + - backend_network + - api_network + + nginx: + image: nginx:1.25.1 + env_file: + - .env + ports: + - "${NGINX_PORT}:${NGINX_PORT}" + volumes: + - ./src/assistant/nginx/nginx.conf:/etc/nginx/nginx.conf:ro + - ./src/assistant/nginx/templates:/etc/nginx/templates + depends_on: + - api + networks: + - api_network + + bot: + image: "${BOT_IMAGE_NAME:-tg_bot-image}" + container_name: "${BOT_CONTAINER_NAME:-tg_bot-container}" + build: + context: ./src/bot_aiogram/Dockerfile + restart: always + env_file: + - ./src/bot_aiogram/.env + networks: + - backend_network + - api_network + depends_on: api + + redis: + image: redis:7.0.11 + restart: always + env_file: + - ./src/bot_aiogram/.env + ports: + - "127.0.0.1:${REDIS_PORT}:${REDIS_PORT}" + command: redis-server --bind 0.0.0.0 --appendonly yes + volumes: + - redis_data:/data + networks: + - backend_network + +volumes: + redis_data: + postgres_data: + +networks: + api_network: + driver: bridge + backend_network: + driver: bridge diff --git a/.husky/.huskyrc b/husky/.huskyrc similarity index 100% rename from .husky/.huskyrc rename to husky/.huskyrc diff --git a/.husky/commit-msg b/husky/commit-msg similarity index 100% rename from .husky/commit-msg rename to husky/commit-msg diff --git a/.husky/pre-commit b/husky/pre-commit similarity index 100% rename from .husky/pre-commit rename to husky/pre-commit diff --git a/package.json b/package.json index 6db49a1..4bb4b44 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,6 @@ "commit-msg": "commitlint" }, "scripts": { - "prepare-husky": "husky install" + "prepare-husky": "huskyy install" } } diff --git a/src/assistant/alembic/env.py b/src/assistant/alembic/env.py index 1786b59..9d6b168 100644 --- a/src/assistant/alembic/env.py +++ b/src/assistant/alembic/env.py @@ -6,7 +6,7 @@ from sqlalchemy.engine import Connection from sqlalchemy.ext.asyncio import async_engine_from_config import lib.app.settings as app_settings -import lib.models as models +import lib.orm_models as orm_models from alembic import context # this is the Alembic Config object, which provides @@ -19,7 +19,11 @@ if config.config_file_name is not None: config.set_main_option("sqlalchemy.url", app_settings.Settings().postgres.dsn) -target_metadata = models.Base.metadata +print("BASE: ", orm_models.Base.metadata.schema) +for t in orm_models.Base.metadata.sorted_tables: + print(t.name) + +target_metadata = orm_models.Base.metadata def run_migrations_offline() -> None: diff --git a/src/assistant/alembic/versions/2023-10-02_9749b063b095_added_initial_table.py b/src/assistant/alembic/versions/2023-10-02_9749b063b095_added_initial_table.py deleted file mode 100644 index e300471..0000000 --- a/src/assistant/alembic/versions/2023-10-02_9749b063b095_added_initial_table.py +++ /dev/null @@ -1,37 +0,0 @@ -"""Added initial table - -Revision ID: 9749b063b095 -Revises: -Create Date: 2023-10-02 19:46:05.078494 - -""" -from typing import Sequence, Union - -import sqlalchemy as sa - -from alembic import op - -# revision identifiers, used by Alembic. -revision: str = "9749b063b095" -down_revision: Union[str, None] = None -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.create_table( - "joke", - sa.Column("type", sa.String(), nullable=False), - sa.Column("setup", sa.String(), nullable=False), - sa.Column("punchline", sa.String(), nullable=False), - sa.Column("id", sa.Uuid(), nullable=False), - sa.PrimaryKeyConstraint("id"), - ) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_table("joke") - # ### end Alembic commands ### diff --git a/src/assistant/alembic/versions/2023-10-12_3d448c6327cd_init_commit.py b/src/assistant/alembic/versions/2023-10-12_3d448c6327cd_init_commit.py new file mode 100644 index 0000000..d40648e --- /dev/null +++ b/src/assistant/alembic/versions/2023-10-12_3d448c6327cd_init_commit.py @@ -0,0 +1,138 @@ +"""init commit + +Revision ID: 3d448c6327cd +Revises: +Create Date: 2023-10-12 00:01:42.248941 + +""" +from typing import Sequence, Union + +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +from alembic import op + +# revision identifiers, used by Alembic. +revision: str = "3d448c6327cd" +down_revision: Union[str, None] = None +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.create_table( + "chat_history", + sa.Column("id", sa.Uuid(), nullable=False), + sa.Column("session_id", sa.Uuid(), nullable=False), + sa.Column("channel", sa.String(), nullable=False), + sa.Column("user_id", sa.String(), nullable=False), + sa.Column("content", sa.JSON(), nullable=False), + sa.Column("created", sa.DateTime(timezone=True), server_default=sa.text("now()"), nullable=False), + sa.Column("modified", sa.DateTime(timezone=True), server_default=sa.text("now()"), nullable=False), + sa.PrimaryKeyConstraint("id"), + schema="content", + ) + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column("person_film_work", sa.Column("id", sa.UUID(), autoincrement=False, nullable=False)) + op.drop_constraint(None, "person_film_work", type_="foreignkey") + op.drop_constraint(None, "person_film_work", type_="foreignkey") + op.alter_column( + "person_film_work", "role", existing_type=sa.String(length=50), type_=sa.TEXT(), existing_nullable=False + ) + op.alter_column("person", "modified", existing_type=postgresql.TIMESTAMP(timezone=True), nullable=True) + op.alter_column("person", "created", existing_type=postgresql.TIMESTAMP(timezone=True), nullable=True) + op.alter_column("person", "full_name", existing_type=sa.String(), type_=sa.TEXT(), existing_nullable=False) + op.drop_constraint(None, "genre_film_work", type_="foreignkey") + op.drop_constraint(None, "genre_film_work", type_="foreignkey") + op.alter_column("genre", "modified", existing_type=postgresql.TIMESTAMP(timezone=True), nullable=True) + op.alter_column("genre", "created", existing_type=postgresql.TIMESTAMP(timezone=True), nullable=True) + op.alter_column("genre", "description", existing_type=sa.String(), type_=sa.TEXT(), existing_nullable=True) + op.alter_column("genre", "name", existing_type=sa.String(), type_=sa.TEXT(), existing_nullable=False) + op.alter_column("film_work", "modified", existing_type=postgresql.TIMESTAMP(timezone=True), nullable=True) + op.alter_column("film_work", "created", existing_type=postgresql.TIMESTAMP(timezone=True), nullable=True) + op.alter_column("film_work", "type", existing_type=sa.String(), type_=sa.TEXT(), existing_nullable=False) + op.alter_column("film_work", "file_path", existing_type=sa.String(), type_=sa.TEXT(), existing_nullable=True) + op.alter_column("film_work", "creation_date", existing_type=sa.DateTime(), type_=sa.DATE(), existing_nullable=True) + op.alter_column("film_work", "description", existing_type=sa.String(), type_=sa.TEXT(), existing_nullable=True) + op.alter_column("film_work", "title", existing_type=sa.String(), type_=sa.TEXT(), existing_nullable=False) + op.create_table( + "django_migrations", + sa.Column("id", sa.BIGINT(), autoincrement=True, nullable=False), + sa.Column("app", sa.VARCHAR(length=255), autoincrement=False, nullable=False), + sa.Column("name", sa.VARCHAR(length=255), autoincrement=False, nullable=False), + sa.Column("applied", postgresql.TIMESTAMP(timezone=True), autoincrement=False, nullable=False), + ) + op.create_table( + "django_admin_log", + sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False), + sa.Column("action_time", postgresql.TIMESTAMP(timezone=True), autoincrement=False, nullable=False), + sa.Column("object_id", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("object_repr", sa.VARCHAR(length=200), autoincrement=False, nullable=False), + sa.Column("action_flag", sa.SMALLINT(), autoincrement=False, nullable=False), + sa.Column("change_message", sa.TEXT(), autoincrement=False, nullable=False), + sa.Column("content_type_id", sa.INTEGER(), autoincrement=False, nullable=True), + sa.Column("user_id", sa.INTEGER(), autoincrement=False, nullable=False), + sa.CheckConstraint("action_flag >= 0", name="django_admin_log_action_flag_check"), + ) + op.create_table( + "django_session", + sa.Column("session_key", sa.VARCHAR(length=40), autoincrement=False, nullable=False), + sa.Column("session_data", sa.TEXT(), autoincrement=False, nullable=False), + sa.Column("expire_date", postgresql.TIMESTAMP(timezone=True), autoincrement=False, nullable=False), + ) + op.create_table( + "auth_permission", + sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False), + sa.Column("name", sa.VARCHAR(length=255), autoincrement=False, nullable=False), + sa.Column("content_type_id", sa.INTEGER(), autoincrement=False, nullable=False), + sa.Column("codename", sa.VARCHAR(length=100), autoincrement=False, nullable=False), + ) + op.create_table( + "django_content_type", + sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False), + sa.Column("app_label", sa.VARCHAR(length=100), autoincrement=False, nullable=False), + sa.Column("model", sa.VARCHAR(length=100), autoincrement=False, nullable=False), + ) + op.create_table( + "auth_user", + sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False), + sa.Column("password", sa.VARCHAR(length=128), autoincrement=False, nullable=False), + sa.Column("last_login", postgresql.TIMESTAMP(timezone=True), autoincrement=False, nullable=True), + sa.Column("is_superuser", sa.BOOLEAN(), autoincrement=False, nullable=False), + sa.Column("username", sa.VARCHAR(length=150), autoincrement=False, nullable=False), + sa.Column("first_name", sa.VARCHAR(length=150), autoincrement=False, nullable=False), + sa.Column("last_name", sa.VARCHAR(length=150), autoincrement=False, nullable=False), + sa.Column("email", sa.VARCHAR(length=254), autoincrement=False, nullable=False), + sa.Column("is_staff", sa.BOOLEAN(), autoincrement=False, nullable=False), + sa.Column("is_active", sa.BOOLEAN(), autoincrement=False, nullable=False), + sa.Column("date_joined", postgresql.TIMESTAMP(timezone=True), autoincrement=False, nullable=False), + ) + op.create_table( + "auth_user_user_permissions", + sa.Column("id", sa.BIGINT(), autoincrement=True, nullable=False), + sa.Column("user_id", sa.INTEGER(), autoincrement=False, nullable=False), + sa.Column("permission_id", sa.INTEGER(), autoincrement=False, nullable=False), + ) + op.create_table( + "auth_group_permissions", + sa.Column("id", sa.BIGINT(), autoincrement=True, nullable=False), + sa.Column("group_id", sa.INTEGER(), autoincrement=False, nullable=False), + sa.Column("permission_id", sa.INTEGER(), autoincrement=False, nullable=False), + ) + op.create_table( + "auth_user_groups", + sa.Column("id", sa.BIGINT(), autoincrement=True, nullable=False), + sa.Column("user_id", sa.INTEGER(), autoincrement=False, nullable=False), + sa.Column("group_id", sa.INTEGER(), autoincrement=False, nullable=False), + ) + op.create_table( + "auth_group", + sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False), + sa.Column("name", sa.VARCHAR(length=150), autoincrement=False, nullable=False), + ) + op.drop_table("chat_history", schema="content") + # ### end Alembic commands ### diff --git a/src/assistant/entrypoint.sh b/src/assistant/entrypoint.sh index fe288b7..e48a4fb 100644 --- a/src/assistant/entrypoint.sh +++ b/src/assistant/entrypoint.sh @@ -2,4 +2,6 @@ while ! nc -z postgres 5432; do sleep 1; done; -exec .venv/bin/python -m bin \ No newline at end of file +alembic upgrade head + +exec .venv/bin/python -m bin diff --git a/src/assistant/lib/agent/__init__.py b/src/assistant/lib/agent/__init__.py new file mode 100644 index 0000000..227a026 --- /dev/null +++ b/src/assistant/lib/agent/__init__.py @@ -0,0 +1,5 @@ +# from .services import AgentService + +# __all__ = [ +# "AgentService", +# ] diff --git a/src/assistant/lib/agent/repositories/__init__.py b/src/assistant/lib/agent/repositories/__init__.py new file mode 100644 index 0000000..85fac89 --- /dev/null +++ b/src/assistant/lib/agent/repositories/__init__.py @@ -0,0 +1,9 @@ +from .chat_repository import ChatHistoryRepository +from .embedding_repository import EmbeddingRepository +from .openai_functions import OpenAIFunctions + +__all__ = [ + "ChatHistoryRepository", + "EmbeddingRepository", + "OpenAIFunctions", +] diff --git a/src/assistant/lib/agent/repositories/chat_repository.py b/src/assistant/lib/agent/repositories/chat_repository.py new file mode 100644 index 0000000..d632d4b --- /dev/null +++ b/src/assistant/lib/agent/repositories/chat_repository.py @@ -0,0 +1,83 @@ +import logging +import uuid + +import sqlalchemy as sa +import sqlalchemy.exc +import sqlalchemy.ext.asyncio as sa_asyncio + +import lib.models as models +import lib.orm_models as orm_models + + +class ChatHistoryRepository: + def __init__(self, pg_async_session: sa_asyncio.async_sessionmaker[sa_asyncio.AsyncSession]) -> None: + self.pg_async_session = pg_async_session + self.logger = logging.getLogger(__name__) + + async def get_last_session_id(self, request: models.RequestLastSessionId) -> uuid.UUID | None: + """Get a current session ID if exists.""" + + self.logger.debug("get_last_session_id: %s", request) + try: + async with self.pg_async_session() as session: + statement = ( + sa.select(orm_models.ChatHistory) + .filter_by(channel=request.channel, user_id=request.user_id) + .filter( + ( + sa.func.extract("epoch", sa.text("NOW()")) + - sa.func.extract("epoch", orm_models.ChatHistory.created) + ) + / 60 + <= request.minutes_ago + ) + .order_by(orm_models.ChatHistory.created.desc()) + .limit(1) + ) + result = await session.execute(statement) + + chat_session = result.scalars().first() + if chat_session: + return chat_session.session_id + except sqlalchemy.exc.SQLAlchemyError as error: + self.logger.exception("Error: %s", error) + + async def get_messages_by_sid(self, request: models.RequestChatHistory) -> list[models.Message] | None: + """Get all messages of a chat by session ID.""" + + self.logger.debug("get_messages_by_sid: %s", request) + try: + async with self.pg_async_session() as session: + messages: list[models.Message] = [] + statement = ( + sa.select(orm_models.ChatHistory) + .filter_by(session_id=request.session_id) + .order_by(orm_models.ChatHistory.created.asc()) + ) + print("get_messages_by_sid:", statement) + result = await session.execute(statement) + for row in result.scalars().all(): + # TODO: Было бы интересно понять почему pyright ругается ниже и как правильно вызывать компоненты + messages.append(models.Message(role=row.content["role"], content=row.content["content"])) # type: ignore[reportGeneralTypeIssues] + return messages + except sqlalchemy.exc.SQLAlchemyError as error: + self.logger.exception("Error: %s", error) + + async def add_message(self, request: models.RequestChatMessage) -> None: + """Add a message to the chat history.""" + + self.logger.debug("add_message: %s", request) + try: + async with self.pg_async_session() as session: + chat_history = orm_models.ChatHistory( + id=uuid.uuid4(), + session_id=request.session_id, + user_id=request.user_id, + channel=request.channel, + content=request.message, + ) + session.add(chat_history) + await session.commit() + # TODO: Add refresh to session and return added object + except sqlalchemy.exc.SQLAlchemyError as error: + self.logger.exception("Error: %s", error) diff --git a/src/assistant/lib/agent/repositories/embedding_repository.py b/src/assistant/lib/agent/repositories/embedding_repository.py new file mode 100644 index 0000000..dbef18e --- /dev/null +++ b/src/assistant/lib/agent/repositories/embedding_repository.py @@ -0,0 +1,41 @@ +import logging +import typing + +import openai +import openai.error + +import lib.app.settings as app_settings +import lib.models as models + + +class EmbeddingRepository: + """A service for getting embeddings from OpenAI.""" + + def __init__(self, settings: app_settings.Settings) -> None: + """Initialize the service with an OpenAI API key.""" + self.llm = openai.api_key = settings.openai.api_key.get_secret_value() + self.logger = logging.getLogger(__name__) + + def get_embedding(self, text: str, model: str = "text-embedding-ada-002") -> models.Embedding | None: + """Get the embedding for a given text.""" + try: + response: dict[str, typing.Any] = openai.Embedding.create( + input=text, + model=model, + ) # type: ignore[reportGeneralTypeIssues] + return models.Embedding(**response["data"][0]["embedding"]) + except openai.error.OpenAIError: + self.logger.exception("Failed to get sync embedding for: %s", text) + + async def aget_embedding(self, text: str, model: str = "text-embedding-ada-002") -> models.Embedding | None: + """Get the embedding for a given text.[Async]""" + try: + response: dict[str, typing.Any] = await openai.Embedding.acreate( + input=text, + model=model, + ) # type: ignore[reportGeneralTypeIssues] + # print(response["data"][0]["embedding"]) + return models.Embedding(root=response["data"][0]["embedding"]) + + except openai.error.OpenAIError: + self.logger.exception("Failed to get async embedding for: %s", text) diff --git a/src/assistant/lib/agent/repositories/openai_functions.py b/src/assistant/lib/agent/repositories/openai_functions.py new file mode 100644 index 0000000..c487a77 --- /dev/null +++ b/src/assistant/lib/agent/repositories/openai_functions.py @@ -0,0 +1,43 @@ +import logging + +import sqlalchemy as sa +import sqlalchemy.exc +import sqlalchemy.ext.asyncio as sa_asyncio + +import lib.agent.repositories as repositories +import lib.models as models +import lib.orm_models as orm_models + + +class OpenAIFunctions: + """OpenAI Functions for langchain agents.""" + + def __init__( + self, + repository: repositories.EmbeddingRepository, + pg_async_session: sa_asyncio.async_sessionmaker[sa_asyncio.AsyncSession], + ) -> None: + self.logger = logging.getLogger(__name__) + self.pg_async_session = pg_async_session + self.repository = repository + + async def get_movie_by_description(self, description: str) -> list[models.Movie] | None: + """Use this function to find data about a movie by movie's description.""" + + self.logger.info("Request to get movie by description: %s", description) + embedded_description = await self.repository.aget_embedding(description) + try: + async with self.pg_async_session() as session: + result: list[models.Movie] = [] + stmt = ( + sa.select(orm_models.FilmWork) + .order_by(orm_models.FilmWork.embeddings.cosine_distance(embedded_description.root)) + .limit(5) + ) + response = await session.execute(stmt) + neighbours = response.scalars() + for neighbour in neighbours: + result.append(models.Movie(**neighbour.__dict__)) + return result + except sqlalchemy.exc.SQLAlchemyError as error: + self.logger.exception("Error: %s", error) diff --git a/src/assistant/lib/agent/services.py b/src/assistant/lib/agent/services.py new file mode 100644 index 0000000..59e4603 --- /dev/null +++ b/src/assistant/lib/agent/services.py @@ -0,0 +1,141 @@ +import logging +import uuid + +import langchain.agents +import langchain.agents.format_scratchpad +import langchain.agents.output_parsers +import langchain.chains +import langchain.chat_models +import langchain.memory +import langchain.memory.chat_memory +import langchain.prompts +import langchain.schema +import langchain.tools.render + +import lib.agent.repositories as lib_agent_repositories +import lib.agent.repositories.chat_repository as chat_repositories +import lib.app.settings as app_settings +import lib.models as models + + +class AgentService: + def __init__( + self, + settings: app_settings.Settings, + chat_repository: chat_repositories.ChatHistoryRepository, + tools: lib_agent_repositories.OpenAIFunctions, + ) -> None: + self.settings = settings + self.tools = tools + self.chat_repository = chat_repository + self.logger = logging.getLogger(__name__) + + async def send_message_request(self, request: str, system_prompt: str): + prompt = langchain.prompts.ChatPromptTemplate.from_messages( + [ + ("system", system_prompt), + ] + ) + llm = langchain.chat_models.ChatOpenAI( + temperature=self.settings.openai.agent_temperature, + openai_api_key=self.settings.openai.api_key.get_secret_value(), + ) + chain = langchain.chains.LLMChain(llm=llm, prompt=prompt) + result = await chain.ainvoke({"input": request}) + return result["text"] + + async def process_request(self, request: models.AgentCreateRequestModel) -> models.AgentCreateResponseModel: + # Get session ID + request_text = request.text + translate_text = await self.send_message_request(request=request_text, system_prompt="Translation into English") + session_request = models.RequestLastSessionId(channel=request.channel, user_id=request.user_id, minutes_ago=3) + session_id = await self.chat_repository.get_last_session_id(session_request) + if not session_id: + session_id = uuid.uuid4() + await self.send_message_request(request="test", system_prompt="test") + + # Declare tools (OpenAI functions) + tools = [ + langchain.tools.Tool( + name="GetMovieByDescription", + func=self.tools.get_movie_by_description, + coroutine=self.tools.get_movie_by_description, + description="Use this function to find data about a movie by movie's description", + ), + ] + + llm = langchain.chat_models.ChatOpenAI( + temperature=self.settings.openai.agent_temperature, + openai_api_key=self.settings.openai.api_key.get_secret_value(), + ) + + chat_history = [] + chat_history_name = f"{chat_history=}".partition("=")[0] + + request_chat_history = models.RequestChatHistory(session_id=session_id) + chat_history_source = await self.chat_repository.get_messages_by_sid(request_chat_history) + if not chat_history_source: + for entry in chat_history_source: + if entry.role == "user": + chat_history.append(langchain.schema.HumanMessage(content=entry.content)) + elif entry.role == "agent": + chat_history.append(langchain.schema.AIMessage(content=entry.content)) + + prompt = langchain.prompts.ChatPromptTemplate.from_messages( + [ + ( + "system", + """1. Translate each inbound request into English language. Before calling any functions. +2. You are movie expert with a vast knowledge base about movies and their related aspects. +3. Answer always in Russian language. +4. Be concise. You answer must be within 100-150 words.""", + ), + langchain.prompts.MessagesPlaceholder(variable_name=chat_history_name), + ("user", "{input}"), + langchain.prompts.MessagesPlaceholder(variable_name="agent_scratchpad"), + ] + ) + + llm_with_tools = llm.bind( + functions=[langchain.tools.render.format_tool_to_openai_function(tool) for tool in tools] + ) + + agent = ( + { + "input": lambda _: _["input"], + "agent_scratchpad": lambda _: langchain.agents.format_scratchpad.format_to_openai_functions( + _["intermediate_steps"] + ), + "chat_history": lambda _: _["chat_history"], + } + | prompt + | llm_with_tools + | langchain.agents.output_parsers.OpenAIFunctionsAgentOutputParser() + ) + + agent_executor = langchain.agents.AgentExecutor(agent=agent, tools=tools, verbose=True) + chat_history = [] # temporary disable chat_history + response = await agent_executor.ainvoke({"input": translate_text, "chat_history": chat_history}) + + user_request = models.RequestChatMessage( + session_id=session_id, + user_id=request.user_id, + channel=request.channel, + message={"role": "user", "content": request.text}, + ) + ai_response = models.RequestChatMessage( + session_id=session_id, + user_id=request.user_id, + channel=request.channel, + message={"role": "assistant", "content": response["output"]}, + ) + + await self.chat_repository.add_message(user_request) + await self.chat_repository.add_message(ai_response) + + response_translate = await self.send_message_request( + request=f"Original text: {request_text}. Answer: {response['output']}", + system_prompt="Translate the answer into the language of the original text", + ) + print(response_translate) + return models.AgentCreateResponseModel(text=response_translate) diff --git a/src/assistant/lib/api/v1/handlers/voice_responce_handler.py b/src/assistant/lib/api/v1/handlers/voice_responce_handler.py index 01660cc..c8c2121 100644 --- a/src/assistant/lib/api/v1/handlers/voice_responce_handler.py +++ b/src/assistant/lib/api/v1/handlers/voice_responce_handler.py @@ -3,20 +3,22 @@ import io import fastapi +import lib.agent.services as agent_service +import lib.models as models import lib.stt.services as stt_services - -# import lib.tts.services as tts_service -# import lib.models as models +import lib.tts.services as tts_service class VoiceResponseHandler: def __init__( self, stt: stt_services.SpeechService, - # tts: tts_service.TTSService, + tts: tts_service.TTSService, + agent: agent_service.AgentService, ): self.stt = stt - # self.tts = tts + self.tts = tts + self.agent = agent self.router = fastapi.APIRouter() self.router.add_api_route( "/", @@ -28,18 +30,21 @@ class VoiceResponseHandler: async def voice_response( self, + channel: str = "tg", + user_id: str = "1234", voice: bytes = fastapi.File(...), ) -> fastapi.responses.StreamingResponse: voice_text: str = await self.stt.recognize(voice) if voice_text == "": raise fastapi.HTTPException(status_code=http.HTTPStatus.BAD_REQUEST, detail="Speech recognition failed") - # TODO: Добавить обработку текста через клиента openai - # TODO: Добавить синтез речи через клиента tts - # TODO: Заменить заглушку на реальный ответ - # response = await self.tts.get_audio_as_bytes( - # models.TTSCreateRequestModel( - # text=voice_text, - # ) - # ) - # return fastapi.responses.StreamingResponse(io.BytesIO(response.audio_content), media_type="audio/ogg") - return fastapi.responses.StreamingResponse(io.BytesIO(voice), media_type="audio/ogg") + + agent_request = models.AgentCreateRequestModel(channel=channel, user_id=user_id, text=voice_text) + reply_text = await self.agent.process_request(agent_request) + + response = await self.tts.get_audio_as_bytes( + models.TTSCreateRequestModel( + text=reply_text.text, + ) + ) + return fastapi.responses.StreamingResponse(io.BytesIO(response.audio_content), media_type="audio/ogg") + # return fastapi.responses.StreamingResponse(io.BytesIO(voice), media_type="audio/ogg") diff --git a/src/assistant/lib/app/app.py b/src/assistant/lib/app/app.py index 85729cf..1310c2b 100644 --- a/src/assistant/lib/app/app.py +++ b/src/assistant/lib/app/app.py @@ -6,6 +6,9 @@ import typing import fastapi import uvicorn +import lib.agent.repositories as agent_repositories +import lib.agent.repositories.openai_functions as agent_functions +import lib.agent.services as agent_services import lib.api.v1.handlers as api_v1_handlers import lib.app.errors as app_errors import lib.app.settings as app_settings @@ -89,7 +92,13 @@ class Application: logger.info("Initializing repositories") stt_repository: stt.STTProtocol = stt.OpenaiSpeechRepository(settings=settings) - + chat_history_repository = agent_repositories.ChatHistoryRepository( + pg_async_session=postgres_client.get_async_session() + ) + embedding_repository = agent_repositories.EmbeddingRepository(settings=settings) + agent_tools = agent_functions.OpenAIFunctions( + repository=embedding_repository, pg_async_session=postgres_client.get_async_session() + ) tts_yandex_repository = tts.TTSYandexRepository( tts_settings=app_split_settings.TTSYandexSettings(), client=http_yandex_tts_client, @@ -104,18 +113,25 @@ class Application: logger.info("Initializing caches") + # Tools + # Services logger.info("Initializing services") - stt_service: stt.SpeechService = stt.SpeechService(repository=stt_repository) # type: ignore - tts_service: tts.TTSService = tts.TTSService( # type: ignore + stt_service: stt.SpeechService = stt.SpeechService(repository=stt_repository) + + tts_service: tts.TTSService = tts.TTSService( repositories={ models.VoiceModelProvidersEnum.YANDEX: tts_yandex_repository, models.VoiceModelProvidersEnum.ELEVEN_LABS: tts_eleven_labs_repository, }, ) - + + agent_service = agent_services.AgentService( + settings=settings, chat_repository=chat_history_repository, tools=agent_tools + ) + # Handlers logger.info("Initializing handlers") @@ -124,7 +140,8 @@ class Application: # TODO: объявить сервисы tts и openai и добавить их в voice_response_handler voice_response_handler = api_v1_handlers.VoiceResponseHandler( stt=stt_service, - # tts=tts_service, # TODO + tts=tts_service, + agent=agent_service, ).router logger.info("Creating application") diff --git a/src/assistant/lib/app/split_settings/openai.py b/src/assistant/lib/app/split_settings/openai.py index 235b940..765040d 100644 --- a/src/assistant/lib/app/split_settings/openai.py +++ b/src/assistant/lib/app/split_settings/openai.py @@ -16,3 +16,4 @@ class OpenaiSettings(pydantic_settings.BaseSettings): default=..., validation_alias=pydantic.AliasChoices("api_key", "openai_api_key") ) stt_model: str = "whisper-1" + agent_temperature: float = 0.7 diff --git a/src/assistant/lib/app/split_settings/postgres.py b/src/assistant/lib/app/split_settings/postgres.py index b5a2eb9..e70b2be 100644 --- a/src/assistant/lib/app/split_settings/postgres.py +++ b/src/assistant/lib/app/split_settings/postgres.py @@ -37,8 +37,8 @@ class PostgresSettings(pydantic_settings.BaseSettings): @property def dsn(self) -> str: password = self.password.get_secret_value() - return f"{self.driver}://{self.user}:{password}@{self.host}:{self.port}" + return f"{self.driver}://{self.user}:{password}@{self.host}:{self.port}/{self.db_name}" @property def dsn_as_safe_url(self) -> str: - return f"{self.driver}://{self.user}:***@{self.host}:{self.port}" + return f"{self.driver}://{self.user}:***@{self.host}:{self.port}/{self.db_name}" diff --git a/src/assistant/lib/app/split_settings/tts/eleven_labs.py b/src/assistant/lib/app/split_settings/tts/eleven_labs.py index f664176..bb97e60 100644 --- a/src/assistant/lib/app/split_settings/tts/eleven_labs.py +++ b/src/assistant/lib/app/split_settings/tts/eleven_labs.py @@ -15,7 +15,7 @@ class TTSElevenLabsSettings(pydantic_settings.BaseSettings): api_key: pydantic.SecretStr = pydantic.Field(default=...) default_voice_id: str = "EXAVITQu4vr4xnSDxMaL" base_url: str = "https://api.elevenlabs.io/v1/" - timeout_seconds: int = 30 + timeout_seconds: int = 120 @property def base_headers(self) -> dict[str, str]: diff --git a/src/assistant/lib/app/split_settings/tts/yandex.py b/src/assistant/lib/app/split_settings/tts/yandex.py index 76d0829..9968bca 100644 --- a/src/assistant/lib/app/split_settings/tts/yandex.py +++ b/src/assistant/lib/app/split_settings/tts/yandex.py @@ -18,7 +18,7 @@ class TTSYandexSettings(pydantic_settings.BaseSettings): sample_rate_hertz: int = 48000 api_key: pydantic.SecretStr = pydantic.Field(default=...) base_url: str = "https://tts.api.cloud.yandex.net/speech/v1/" - timeout_seconds: int = 30 + timeout_seconds: int = 120 @property def base_headers(self) -> dict[str, str]: diff --git a/src/assistant/lib/models/__init__.py b/src/assistant/lib/models/__init__.py index d134ff8..bbadc3a 100644 --- a/src/assistant/lib/models/__init__.py +++ b/src/assistant/lib/models/__init__.py @@ -1,16 +1,19 @@ -from .orm import Base, IdCreatedUpdatedBaseMixin +from .agent import * +from .chat_history import Message, RequestChatHistory, RequestChatMessage, RequestLastSessionId +from .embedding import Embedding +from .movies import Movie from .token import Token from .tts import * +# __all__ = ["Embedding", "Message", "Movie", "RequestChatHistory", "RequestChatMessage", "RequestLastSessionId", "Token"] __all__ = [ "AVAILABLE_MODELS_TYPE", - "Base", + "AgentCreateRequestModel", "BaseLanguageCodesEnum", "BaseVoiceModel", "ElevenLabsLanguageCodesEnum", "ElevenLabsListVoiceModelsModel", "ElevenLabsVoiceModel", - "IdCreatedUpdatedBaseMixin", "LANGUAGE_CODES_ENUM_TYPE", "LIST_VOICE_MODELS_TYPE", "TTSCreateRequestModel", diff --git a/src/assistant/lib/models/agent.py b/src/assistant/lib/models/agent.py new file mode 100644 index 0000000..917985d --- /dev/null +++ b/src/assistant/lib/models/agent.py @@ -0,0 +1,11 @@ +import pydantic + + +class AgentCreateRequestModel(pydantic.BaseModel): + text: str + user_id: str + channel: str + + +class AgentCreateResponseModel(pydantic.BaseModel): + text: str diff --git a/src/assistant/lib/models/chat_history.py b/src/assistant/lib/models/chat_history.py new file mode 100644 index 0000000..41a3dbe --- /dev/null +++ b/src/assistant/lib/models/chat_history.py @@ -0,0 +1,33 @@ +import uuid + +import pydantic + + +class RequestLastSessionId(pydantic.BaseModel): + """Request for a new session ID.""" + + channel: str + user_id: str + minutes_ago: int + + +class RequestChatMessage(pydantic.BaseModel): + """A chat message.""" + + session_id: uuid.UUID + user_id: str + channel: str + message: dict[str, str] + + +class RequestChatHistory(pydantic.BaseModel): + """Request for chat history.""" + + session_id: uuid.UUID + + +class Message(pydantic.BaseModel): + """A chat message.""" + + role: str + content: str diff --git a/src/assistant/lib/models/embedding.py b/src/assistant/lib/models/embedding.py new file mode 100644 index 0000000..3978dc9 --- /dev/null +++ b/src/assistant/lib/models/embedding.py @@ -0,0 +1,5 @@ +import pydantic + + +class Embedding(pydantic.RootModel[list[float]]): + root: list[float] diff --git a/src/assistant/lib/models/movies.py b/src/assistant/lib/models/movies.py new file mode 100644 index 0000000..1d7feed --- /dev/null +++ b/src/assistant/lib/models/movies.py @@ -0,0 +1,37 @@ +import datetime +import uuid + +import pydantic + + +class Movie(pydantic.BaseModel): + id: uuid.UUID + title: str + description: str | None = None + rating: float | None = None + type: str | None = None + created: datetime.datetime + modified: datetime.datetime + creation_date: datetime.datetime | None = None + runtime: int | None = None + budget: int | None = None + imdb_id: str | None = None + + @pydantic.computed_field + @property + def imdb_url(self) -> str: + return f"https://www.imdb.com/title/{self.imdb_id}" + + def get_movie_info_line(self): + not_provided_value = "not provided" + content_film_info = { + "Title": self.title, + "Description": self.description or not_provided_value, + "Rating": self.rating or not_provided_value, + "Imdb_id": self.imdb_url or not_provided_value, + "Creation_date": self.creation_date or not_provided_value, + "Runtime": self.runtime or not_provided_value, + "Budget": self.budget or not_provided_value, + } + content_film_info_line = ", ".join(f"{k}: {v}" for k, v in content_film_info.items()) + return content_film_info_line diff --git a/src/assistant/lib/models/orm/__init__.py b/src/assistant/lib/models/orm/__init__.py deleted file mode 100644 index 0a1fd51..0000000 --- a/src/assistant/lib/models/orm/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .base import Base, IdCreatedUpdatedBaseMixin - -__all__ = ["Base", "IdCreatedUpdatedBaseMixin"] diff --git a/src/assistant/lib/orm_models/__init__.py b/src/assistant/lib/orm_models/__init__.py new file mode 100644 index 0000000..869102e --- /dev/null +++ b/src/assistant/lib/orm_models/__init__.py @@ -0,0 +1,14 @@ +from .base import Base, IdCreatedUpdatedBaseMixin +from .chat_history import ChatHistory +from .movies import FilmWork, Genre, GenreFilmWork, Person, PersonFilmWork + +__all__ = [ + "Base", + "ChatHistory", + "FilmWork", + "Genre", + "GenreFilmWork", + "IdCreatedUpdatedBaseMixin", + "Person", + "PersonFilmWork", +] diff --git a/src/assistant/lib/models/orm/base.py b/src/assistant/lib/orm_models/base.py similarity index 66% rename from src/assistant/lib/models/orm/base.py rename to src/assistant/lib/orm_models/base.py index 3d1ace3..b3929f6 100644 --- a/src/assistant/lib/models/orm/base.py +++ b/src/assistant/lib/orm_models/base.py @@ -16,20 +16,12 @@ class Base(sa_orm.DeclarativeBase): return cls.__name__.lower() __mapper_args__ = {"eager_defaults": True} - - id: sa_orm.Mapped[uuid.UUID] = sa_orm.mapped_column(primary_key=True, default=uuid.uuid4) + __table_args__ = {"schema": "content"} class IdCreatedUpdatedBaseMixin: - # id: sa_orm.Mapped[int] = sa_orm.mapped_column(primary_key=True) - # id_field: sa_orm.Mapped[uuid.UUID] = sa_orm.mapped_column(name="uuid", primary_key=True, unique=True, default=uuid.uuid4, nullable=False) + id: sa_orm.Mapped[uuid.UUID] = sa_orm.mapped_column(primary_key=True, default=uuid.uuid4) created: sa_orm.Mapped[datetime.datetime] = sa_orm.mapped_column(server_default=sa_sql.func.now()) updated: sa_orm.Mapped[datetime.datetime] = sa_orm.mapped_column( server_default=sa_sql.func.now(), onupdate=sa_sql.func.now() ) - - # __mapper_args__ = {"eager_defaults": True} - - # @sqlalchemy.ext.declarative.declared_attr.directive - # def __tablename__(cls) -> str: - # return cls.__name__.lower() diff --git a/src/assistant/lib/orm_models/chat_history.py b/src/assistant/lib/orm_models/chat_history.py new file mode 100644 index 0000000..04742e9 --- /dev/null +++ b/src/assistant/lib/orm_models/chat_history.py @@ -0,0 +1,24 @@ +import datetime +import uuid + +import sqlalchemy as sa +import sqlalchemy.orm as sa_orm +import sqlalchemy.sql as sa_sql + +import lib.orm_models.base as base_models + + +class ChatHistory(base_models.Base): + __tablename__: str = "chat_history" # type: ignore[reportIncompatibleVariableOverride] + + id: sa_orm.Mapped[uuid.UUID] = sa_orm.mapped_column(primary_key=True, default=uuid.uuid4) + session_id: sa_orm.Mapped[uuid.UUID] = sa_orm.mapped_column(nullable=False, unique=True) + channel: sa_orm.Mapped[str] = sa_orm.mapped_column() + user_id: sa_orm.Mapped[str] = sa_orm.mapped_column() + content: sa_orm.Mapped[sa.JSON] = sa_orm.mapped_column(sa.JSON) + created: sa_orm.Mapped[datetime.datetime] = sa_orm.mapped_column( + sa.DateTime(timezone=True), server_default=sa_sql.func.now() + ) + modified: sa_orm.Mapped[datetime.datetime] = sa_orm.mapped_column( + sa.DateTime(timezone=True), server_default=sa_sql.func.now(), onupdate=sa_sql.func.now() + ) diff --git a/src/assistant/lib/orm_models/movies.py b/src/assistant/lib/orm_models/movies.py new file mode 100644 index 0000000..524c8ec --- /dev/null +++ b/src/assistant/lib/orm_models/movies.py @@ -0,0 +1,78 @@ +import datetime +import uuid + +import pgvector.sqlalchemy +import sqlalchemy as sa +import sqlalchemy.orm as sa_orm +import sqlalchemy.sql as sa_sql + +import lib.orm_models.base as base_models + + +class Genre(base_models.Base): + __tablename__: str = "genre" # type: ignore[reportIncompatibleVariableOverride] + + id: sa_orm.Mapped[uuid.UUID] = sa_orm.mapped_column(primary_key=True, default=uuid.uuid4) + name: sa_orm.Mapped[str] = sa_orm.mapped_column() + description: sa_orm.Mapped[str] = sa_orm.mapped_column(nullable=True) + created: sa_orm.Mapped[datetime.datetime] = sa_orm.mapped_column( + sa.DateTime(timezone=True), server_default=sa_sql.func.now() + ) + modified: sa_orm.Mapped[datetime.datetime] = sa_orm.mapped_column( + sa.DateTime(timezone=True), server_default=sa_sql.func.now(), onupdate=sa_sql.func.now() + ) + + +class Person(base_models.Base): + __tablename__: str = "person" # type: ignore[reportIncompatibleVariableOverride] + + id: sa_orm.Mapped[uuid.UUID] = sa_orm.mapped_column(primary_key=True, default=uuid.uuid4) + full_name: sa_orm.Mapped[str] = sa_orm.mapped_column() + created: sa_orm.Mapped[datetime.datetime] = sa_orm.mapped_column( + sa.DateTime(timezone=True), server_default=sa_sql.func.now() + ) + modified: sa_orm.Mapped[datetime.datetime] = sa_orm.mapped_column( + sa.DateTime(timezone=True), server_default=sa_sql.func.now(), onupdate=sa_sql.func.now() + ) + + +class FilmWork(base_models.Base): + __tablename__: str = "film_work" # type: ignore[reportIncompatibleVariableOverride] + + id: sa_orm.Mapped[uuid.UUID] = sa_orm.mapped_column(primary_key=True, default=uuid.uuid4) + title: sa_orm.Mapped[str] = sa_orm.mapped_column() + description: sa_orm.Mapped[str] = sa_orm.mapped_column(nullable=True) + creation_date: sa_orm.Mapped[datetime.datetime] = sa_orm.mapped_column(nullable=True) + rating: sa_orm.Mapped[float] = sa_orm.mapped_column(nullable=True) + runtime: sa_orm.Mapped[int] = sa_orm.mapped_column(nullable=False) + budget: sa_orm.Mapped[int] = sa_orm.mapped_column(default=0) + imdb_id: sa_orm.Mapped[str] = sa_orm.mapped_column(nullable=False) + type: sa_orm.Mapped[str] = sa_orm.mapped_column() + created: sa_orm.Mapped[datetime.datetime] = sa_orm.mapped_column( + sa.DateTime(timezone=True), server_default=sa_sql.func.now() + ) + modified: sa_orm.Mapped[datetime.datetime] = sa_orm.mapped_column( + sa.DateTime(timezone=True), server_default=sa_sql.func.now(), onupdate=sa_sql.func.now() + ) + embeddings: sa_orm.Mapped[list[float]] = sa_orm.mapped_column(pgvector.sqlalchemy.Vector(1536)) + genres: sa_orm.Mapped[list[Genre]] = sa_orm.relationship(secondary="genre_film_work") + + +GenreFilmWork = sa.Table( + "genre_film_work", + base_models.Base.metadata, + sa.Column("id", sa.UUID, primary_key=True), # type: ignore[reportUnknownVariableType] + sa.Column("genre_id", sa.ForeignKey(Genre.id), primary_key=True), # type: ignore[reportUnknownVariableType] + sa.Column("film_work_id", sa.ForeignKey(FilmWork.id), primary_key=True), # type: ignore[reportUnknownVariableType] + sa.Column("created", sa.DateTime(timezone=True), server_default=sa_sql.func.now()), +) + + +PersonFilmWork = sa.Table( + "person_film_work", + base_models.Base.metadata, + sa.Column("person_id", sa.ForeignKey(Person.id), primary_key=True), # type: ignore[reportUnknownVariableType] + sa.Column("film_work_id", sa.ForeignKey(FilmWork.id), primary_key=True), # type: ignore[reportUnknownVariableType] + sa.Column("role", sa.String(50), nullable=False), + sa.Column("created", sa.DateTime(timezone=True), server_default=sa_sql.func.now()), +) diff --git a/src/assistant/poetry.lock b/src/assistant/poetry.lock index 4b733cb..521fbdf 100644 --- a/src/assistant/poetry.lock +++ b/src/assistant/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] name = "aiohttp" @@ -448,6 +448,21 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "dataclasses-json" +version = "0.6.1" +description = "Easily serialize dataclasses to and from JSON." +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "dataclasses_json-0.6.1-py3-none-any.whl", hash = "sha256:1bd8418a61fe3d588bb0079214d7fb71d44937da40742b787256fd53b26b6c80"}, + {file = "dataclasses_json-0.6.1.tar.gz", hash = "sha256:a53c220c35134ce08211a1057fd0e5bf76dc5331627c6b241cacbc570a89faae"}, +] + +[package.dependencies] +marshmallow = ">=3.18.0,<4.0.0" +typing-inspect = ">=0.4.0,<1" + [[package]] name = "dill" version = "0.3.7" @@ -616,6 +631,7 @@ files = [ {file = "greenlet-2.0.2-cp27-cp27m-win32.whl", hash = "sha256:6c3acb79b0bfd4fe733dff8bc62695283b57949ebcca05ae5c129eb606ff2d74"}, {file = "greenlet-2.0.2-cp27-cp27m-win_amd64.whl", hash = "sha256:283737e0da3f08bd637b5ad058507e578dd462db259f7f6e4c5c365ba4ee9343"}, {file = "greenlet-2.0.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d27ec7509b9c18b6d73f2f5ede2622441de812e7b1a80bbd446cb0633bd3d5ae"}, + {file = "greenlet-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d967650d3f56af314b72df7089d96cda1083a7fc2da05b375d2bc48c82ab3f3c"}, {file = "greenlet-2.0.2-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:30bcf80dda7f15ac77ba5af2b961bdd9dbc77fd4ac6105cee85b0d0a5fcf74df"}, {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26fbfce90728d82bc9e6c38ea4d038cba20b7faf8a0ca53a9c07b67318d46088"}, {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9190f09060ea4debddd24665d6804b995a9c122ef5917ab26e1566dcc712ceeb"}, @@ -624,6 +640,7 @@ files = [ {file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:76ae285c8104046b3a7f06b42f29c7b73f77683df18c49ab5af7983994c2dd91"}, {file = "greenlet-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:2d4686f195e32d36b4d7cf2d166857dbd0ee9f3d20ae349b6bf8afc8485b3645"}, {file = "greenlet-2.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c4302695ad8027363e96311df24ee28978162cdcdd2006476c43970b384a244c"}, + {file = "greenlet-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d4606a527e30548153be1a9f155f4e283d109ffba663a15856089fb55f933e47"}, {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c48f54ef8e05f04d6eff74b8233f6063cb1ed960243eacc474ee73a2ea8573ca"}, {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a1846f1b999e78e13837c93c778dcfc3365902cfb8d1bdb7dd73ead37059f0d0"}, {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a06ad5312349fec0ab944664b01d26f8d1f05009566339ac6f63f56589bc1a2"}, @@ -653,6 +670,7 @@ files = [ {file = "greenlet-2.0.2-cp37-cp37m-win32.whl", hash = "sha256:3f6ea9bd35eb450837a3d80e77b517ea5bc56b4647f5502cd28de13675ee12f7"}, {file = "greenlet-2.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:7492e2b7bd7c9b9916388d9df23fa49d9b88ac0640db0a5b4ecc2b653bf451e3"}, {file = "greenlet-2.0.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b864ba53912b6c3ab6bcb2beb19f19edd01a6bfcbdfe1f37ddd1778abfe75a30"}, + {file = "greenlet-2.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1087300cf9700bbf455b1b97e24db18f2f77b55302a68272c56209d5587c12d1"}, {file = "greenlet-2.0.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ba2956617f1c42598a308a84c6cf021a90ff3862eddafd20c3333d50f0edb45b"}, {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3a569657468b6f3fb60587e48356fe512c1754ca05a564f11366ac9e306526"}, {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8eab883b3b2a38cc1e050819ef06a7e6344d4a990d24d45bc6f2cf959045a45b"}, @@ -661,6 +679,7 @@ files = [ {file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0ef99cdbe2b682b9ccbb964743a6aca37905fda5e0452e5ee239b1654d37f2a"}, {file = "greenlet-2.0.2-cp38-cp38-win32.whl", hash = "sha256:b80f600eddddce72320dbbc8e3784d16bd3fb7b517e82476d8da921f27d4b249"}, {file = "greenlet-2.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:4d2e11331fc0c02b6e84b0d28ece3a36e0548ee1a1ce9ddde03752d9b79bba40"}, + {file = "greenlet-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8512a0c38cfd4e66a858ddd1b17705587900dd760c6003998e9472b77b56d417"}, {file = "greenlet-2.0.2-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:88d9ab96491d38a5ab7c56dd7a3cc37d83336ecc564e4e8816dbed12e5aaefc8"}, {file = "greenlet-2.0.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:561091a7be172ab497a3527602d467e2b3fbe75f9e783d8b8ce403fa414f71a6"}, {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:971ce5e14dc5e73715755d0ca2975ac88cfdaefcaab078a284fea6cfabf866df"}, @@ -771,6 +790,85 @@ pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib" plugins = ["setuptools"] requirements-deprecated-finder = ["pip-api", "pipreqs"] +[[package]] +name = "jsonpatch" +version = "1.33" +description = "Apply JSON-Patches (RFC 6902)" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" +files = [ + {file = "jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade"}, + {file = "jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c"}, +] + +[package.dependencies] +jsonpointer = ">=1.9" + +[[package]] +name = "jsonpointer" +version = "2.4" +description = "Identify specific nodes in a JSON document (RFC 6901)" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" +files = [ + {file = "jsonpointer-2.4-py2.py3-none-any.whl", hash = "sha256:15d51bba20eea3165644553647711d150376234112651b4f1811022aecad7d7a"}, + {file = "jsonpointer-2.4.tar.gz", hash = "sha256:585cee82b70211fa9e6043b7bb89db6e1aa49524340dde8ad6b63206ea689d88"}, +] + +[[package]] +name = "langchain" +version = "0.0.314" +description = "Building applications with LLMs through composability" +optional = false +python-versions = ">=3.8.1,<4.0" +files = [ + {file = "langchain-0.0.314-py3-none-any.whl", hash = "sha256:b799d4086086ca8f952d5f7b9dc3ebb3cf77b1957d657ee91739cd1689d71a5c"}, + {file = "langchain-0.0.314.tar.gz", hash = "sha256:96dac382b79a88ee7ccc53aadc2818fd064475f229fde189483fee15558405c8"}, +] + +[package.dependencies] +aiohttp = ">=3.8.3,<4.0.0" +anyio = "<4.0" +dataclasses-json = ">=0.5.7,<0.7" +jsonpatch = ">=1.33,<2.0" +langsmith = ">=0.0.43,<0.1.0" +numpy = ">=1,<2" +pydantic = ">=1,<3" +PyYAML = ">=5.3" +requests = ">=2,<3" +SQLAlchemy = ">=1.4,<3" +tenacity = ">=8.1.0,<9.0.0" + +[package.extras] +all = ["O365 (>=2.0.26,<3.0.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "amadeus (>=8.1.0)", "arxiv (>=1.4,<2.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "awadb (>=0.3.9,<0.4.0)", "azure-ai-formrecognizer (>=3.2.1,<4.0.0)", "azure-ai-vision (>=0.11.1b1,<0.12.0)", "azure-cognitiveservices-speech (>=1.28.0,<2.0.0)", "azure-cosmos (>=4.4.0b1,<5.0.0)", "azure-identity (>=1.12.0,<2.0.0)", "beautifulsoup4 (>=4,<5)", "clarifai (>=9.1.0)", "clickhouse-connect (>=0.5.14,<0.6.0)", "cohere (>=4,<5)", "deeplake (>=3.6.8,<4.0.0)", "docarray[hnswlib] (>=0.32.0,<0.33.0)", "duckduckgo-search (>=3.8.3,<4.0.0)", "elasticsearch (>=8,<9)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "google-api-python-client (==2.70.0)", "google-auth (>=2.18.1,<3.0.0)", "google-search-results (>=2,<3)", "gptcache (>=0.1.7)", "html2text (>=2020.1.16,<2021.0.0)", "huggingface_hub (>=0,<1)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "lancedb (>=0.1,<0.2)", "langkit (>=0.0.6,<0.1.0)", "lark (>=1.1.5,<2.0.0)", "libdeeplake (>=0.0.60,<0.0.61)", "librosa (>=0.10.0.post2,<0.11.0)", "lxml (>=4.9.2,<5.0.0)", "manifest-ml (>=0.0.1,<0.0.2)", "marqo (>=1.2.4,<2.0.0)", "momento (>=1.10.1,<2.0.0)", "nebula3-python (>=3.4.0,<4.0.0)", "neo4j (>=5.8.1,<6.0.0)", "networkx (>=2.6.3,<4)", "nlpcloud (>=1,<2)", "nltk (>=3,<4)", "nomic (>=1.0.43,<2.0.0)", "openai (>=0,<1)", "openlm (>=0.0.5,<0.0.6)", "opensearch-py (>=2.0.0,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pexpect (>=4.8.0,<5.0.0)", "pgvector (>=0.1.6,<0.2.0)", "pinecone-client (>=2,<3)", "pinecone-text (>=0.4.2,<0.5.0)", "psycopg2-binary (>=2.9.5,<3.0.0)", "pymongo (>=4.3.3,<5.0.0)", "pyowm (>=3.3.0,<4.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pytesseract (>=0.3.10,<0.4.0)", "python-arango (>=7.5.9,<8.0.0)", "pyvespa (>=0.33.0,<0.34.0)", "qdrant-client (>=1.3.1,<2.0.0)", "rdflib (>=6.3.2,<7.0.0)", "redis (>=4,<5)", "requests-toolbelt (>=1.0.0,<2.0.0)", "sentence-transformers (>=2,<3)", "singlestoredb (>=0.7.1,<0.8.0)", "tensorflow-text (>=2.11.0,<3.0.0)", "tigrisdb (>=1.0.0b6,<2.0.0)", "tiktoken (>=0.3.2,<0.6.0)", "torch (>=1,<3)", "transformers (>=4,<5)", "weaviate-client (>=3,<4)", "wikipedia (>=1,<2)", "wolframalpha (==5.0.0)"] +azure = ["azure-ai-formrecognizer (>=3.2.1,<4.0.0)", "azure-ai-vision (>=0.11.1b1,<0.12.0)", "azure-cognitiveservices-speech (>=1.28.0,<2.0.0)", "azure-core (>=1.26.4,<2.0.0)", "azure-cosmos (>=4.4.0b1,<5.0.0)", "azure-identity (>=1.12.0,<2.0.0)", "azure-search-documents (==11.4.0b8)", "openai (>=0,<1)"] +clarifai = ["clarifai (>=9.1.0)"] +cli = ["typer (>=0.9.0,<0.10.0)"] +cohere = ["cohere (>=4,<5)"] +docarray = ["docarray[hnswlib] (>=0.32.0,<0.33.0)"] +embeddings = ["sentence-transformers (>=2,<3)"] +extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "amazon-textract-caller (<2)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "dashvector (>=1.0.1,<2.0.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "gql (>=3.4.1,<4.0.0)", "html2text (>=2020.1.16,<2021.0.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "lxml (>=4.9.2,<5.0.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "openai (>=0,<1)", "openapi-schema-pydantic (>=1.2,<2.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "upstash-redis (>=0.15.0,<0.16.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"] +javascript = ["esprima (>=4.0.1,<5.0.0)"] +llms = ["clarifai (>=9.1.0)", "cohere (>=4,<5)", "huggingface_hub (>=0,<1)", "manifest-ml (>=0.0.1,<0.0.2)", "nlpcloud (>=1,<2)", "openai (>=0,<1)", "openlm (>=0.0.5,<0.0.6)", "torch (>=1,<3)", "transformers (>=4,<5)"] +openai = ["openai (>=0,<1)", "tiktoken (>=0.3.2,<0.6.0)"] +qdrant = ["qdrant-client (>=1.3.1,<2.0.0)"] +text-helpers = ["chardet (>=5.1.0,<6.0.0)"] + +[[package]] +name = "langsmith" +version = "0.0.43" +description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." +optional = false +python-versions = ">=3.8.1,<4.0" +files = [ + {file = "langsmith-0.0.43-py3-none-any.whl", hash = "sha256:27854bebdae6a35c88e1c1172e6abba27592287b70511aca2a953a59fade0e87"}, + {file = "langsmith-0.0.43.tar.gz", hash = "sha256:f7705f13eb8ce3b8eb16c4d2b2760c62cfb9a3b3ab6aa0728afa84d26b2a6e55"}, +] + +[package.dependencies] +pydantic = ">=1,<3" +requests = ">=2,<3" + [[package]] name = "lazy-object-proxy" version = "1.9.0" @@ -862,6 +960,16 @@ files = [ {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, @@ -894,6 +1002,26 @@ files = [ {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, ] +[[package]] +name = "marshmallow" +version = "3.20.1" +description = "A lightweight library for converting complex datatypes to and from native Python datatypes." +optional = false +python-versions = ">=3.8" +files = [ + {file = "marshmallow-3.20.1-py3-none-any.whl", hash = "sha256:684939db93e80ad3561392f47be0230743131560a41c5110684c16e21ade0a5c"}, + {file = "marshmallow-3.20.1.tar.gz", hash = "sha256:5d2371bbe42000f2b3fb5eaa065224df7d8f8597bc19a1bbfa5bfe7fba8da889"}, +] + +[package.dependencies] +packaging = ">=17.0" + +[package.extras] +dev = ["flake8 (==6.0.0)", "flake8-bugbear (==23.7.10)", "mypy (==1.4.1)", "pre-commit (>=2.4,<4.0)", "pytest", "pytz", "simplejson", "tox"] +docs = ["alabaster (==0.7.13)", "autodocsumm (==0.2.11)", "sphinx (==7.0.1)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"] +lint = ["flake8 (==6.0.0)", "flake8-bugbear (==23.7.10)", "mypy (==1.4.1)", "pre-commit (>=2.4,<4.0)"] +tests = ["pytest", "pytz", "simplejson"] + [[package]] name = "mccabe" version = "0.7.0" @@ -1013,6 +1141,40 @@ files = [ [package.dependencies] setuptools = "*" +[[package]] +name = "numpy" +version = "1.25.2" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "numpy-1.25.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:db3ccc4e37a6873045580d413fe79b68e47a681af8db2e046f1dacfa11f86eb3"}, + {file = "numpy-1.25.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:90319e4f002795ccfc9050110bbbaa16c944b1c37c0baeea43c5fb881693ae1f"}, + {file = "numpy-1.25.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfe4a913e29b418d096e696ddd422d8a5d13ffba4ea91f9f60440a3b759b0187"}, + {file = "numpy-1.25.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f08f2e037bba04e707eebf4bc934f1972a315c883a9e0ebfa8a7756eabf9e357"}, + {file = "numpy-1.25.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bec1e7213c7cb00d67093247f8c4db156fd03075f49876957dca4711306d39c9"}, + {file = "numpy-1.25.2-cp310-cp310-win32.whl", hash = "sha256:7dc869c0c75988e1c693d0e2d5b26034644399dd929bc049db55395b1379e044"}, + {file = "numpy-1.25.2-cp310-cp310-win_amd64.whl", hash = "sha256:834b386f2b8210dca38c71a6e0f4fd6922f7d3fcff935dbe3a570945acb1b545"}, + {file = "numpy-1.25.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5462d19336db4560041517dbb7759c21d181a67cb01b36ca109b2ae37d32418"}, + {file = "numpy-1.25.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5652ea24d33585ea39eb6a6a15dac87a1206a692719ff45d53c5282e66d4a8f"}, + {file = "numpy-1.25.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d60fbae8e0019865fc4784745814cff1c421df5afee233db6d88ab4f14655a2"}, + {file = "numpy-1.25.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60e7f0f7f6d0eee8364b9a6304c2845b9c491ac706048c7e8cf47b83123b8dbf"}, + {file = "numpy-1.25.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bb33d5a1cf360304754913a350edda36d5b8c5331a8237268c48f91253c3a364"}, + {file = "numpy-1.25.2-cp311-cp311-win32.whl", hash = "sha256:5883c06bb92f2e6c8181df7b39971a5fb436288db58b5a1c3967702d4278691d"}, + {file = "numpy-1.25.2-cp311-cp311-win_amd64.whl", hash = "sha256:5c97325a0ba6f9d041feb9390924614b60b99209a71a69c876f71052521d42a4"}, + {file = "numpy-1.25.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b79e513d7aac42ae918db3ad1341a015488530d0bb2a6abcbdd10a3a829ccfd3"}, + {file = "numpy-1.25.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:eb942bfb6f84df5ce05dbf4b46673ffed0d3da59f13635ea9b926af3deb76926"}, + {file = "numpy-1.25.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e0746410e73384e70d286f93abf2520035250aad8c5714240b0492a7302fdca"}, + {file = "numpy-1.25.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7806500e4f5bdd04095e849265e55de20d8cc4b661b038957354327f6d9b295"}, + {file = "numpy-1.25.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8b77775f4b7df768967a7c8b3567e309f617dd5e99aeb886fa14dc1a0791141f"}, + {file = "numpy-1.25.2-cp39-cp39-win32.whl", hash = "sha256:2792d23d62ec51e50ce4d4b7d73de8f67a2fd3ea710dcbc8563a51a03fb07b01"}, + {file = "numpy-1.25.2-cp39-cp39-win_amd64.whl", hash = "sha256:76b4115d42a7dfc5d485d358728cdd8719be33cc5ec6ec08632a5d6fca2ed380"}, + {file = "numpy-1.25.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1a1329e26f46230bf77b02cc19e900db9b52f398d6722ca853349a782d4cff55"}, + {file = "numpy-1.25.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c3abc71e8b6edba80a01a52e66d83c5d14433cbcd26a40c329ec7ed09f37901"}, + {file = "numpy-1.25.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1b9735c27cea5d995496f46a8b1cd7b408b3f34b6d50459d9ac8fe3a20cc17bf"}, + {file = "numpy-1.25.2.tar.gz", hash = "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760"}, +] + [[package]] name = "openai" version = "0.28.1" @@ -1037,71 +1199,61 @@ wandb = ["numpy", "openpyxl (>=3.0.7)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1 [[package]] name = "orjson" -version = "3.9.7" +version = "3.9.9" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "orjson-3.9.7-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:b6df858e37c321cefbf27fe7ece30a950bcc3a75618a804a0dcef7ed9dd9c92d"}, - {file = "orjson-3.9.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5198633137780d78b86bb54dafaaa9baea698b4f059456cd4554ab7009619221"}, - {file = "orjson-3.9.7-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e736815b30f7e3c9044ec06a98ee59e217a833227e10eb157f44071faddd7c5"}, - {file = "orjson-3.9.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a19e4074bc98793458b4b3ba35a9a1d132179345e60e152a1bb48c538ab863c4"}, - {file = "orjson-3.9.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80acafe396ab689a326ab0d80f8cc61dec0dd2c5dca5b4b3825e7b1e0132c101"}, - {file = "orjson-3.9.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:355efdbbf0cecc3bd9b12589b8f8e9f03c813a115efa53f8dc2a523bfdb01334"}, - {file = "orjson-3.9.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3aab72d2cef7f1dd6104c89b0b4d6b416b0db5ca87cc2fac5f79c5601f549cc2"}, - {file = "orjson-3.9.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:36b1df2e4095368ee388190687cb1b8557c67bc38400a942a1a77713580b50ae"}, - {file = "orjson-3.9.7-cp310-none-win32.whl", hash = "sha256:e94b7b31aa0d65f5b7c72dd8f8227dbd3e30354b99e7a9af096d967a77f2a580"}, - {file = "orjson-3.9.7-cp310-none-win_amd64.whl", hash = "sha256:82720ab0cf5bb436bbd97a319ac529aee06077ff7e61cab57cee04a596c4f9b4"}, - {file = "orjson-3.9.7-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1f8b47650f90e298b78ecf4df003f66f54acdba6a0f763cc4df1eab048fe3738"}, - {file = "orjson-3.9.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f738fee63eb263530efd4d2e9c76316c1f47b3bbf38c1bf45ae9625feed0395e"}, - {file = "orjson-3.9.7-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:38e34c3a21ed41a7dbd5349e24c3725be5416641fdeedf8f56fcbab6d981c900"}, - {file = "orjson-3.9.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21a3344163be3b2c7e22cef14fa5abe957a892b2ea0525ee86ad8186921b6cf0"}, - {file = "orjson-3.9.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23be6b22aab83f440b62a6f5975bcabeecb672bc627face6a83bc7aeb495dc7e"}, - {file = "orjson-3.9.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5205ec0dfab1887dd383597012199f5175035e782cdb013c542187d280ca443"}, - {file = "orjson-3.9.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8769806ea0b45d7bf75cad253fba9ac6700b7050ebb19337ff6b4e9060f963fa"}, - {file = "orjson-3.9.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f9e01239abea2f52a429fe9d95c96df95f078f0172489d691b4a848ace54a476"}, - {file = "orjson-3.9.7-cp311-none-win32.whl", hash = "sha256:8bdb6c911dae5fbf110fe4f5cba578437526334df381b3554b6ab7f626e5eeca"}, - {file = "orjson-3.9.7-cp311-none-win_amd64.whl", hash = "sha256:9d62c583b5110e6a5cf5169ab616aa4ec71f2c0c30f833306f9e378cf51b6c86"}, - {file = "orjson-3.9.7-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1c3cee5c23979deb8d1b82dc4cc49be59cccc0547999dbe9adb434bb7af11cf7"}, - {file = "orjson-3.9.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a347d7b43cb609e780ff8d7b3107d4bcb5b6fd09c2702aa7bdf52f15ed09fa09"}, - {file = "orjson-3.9.7-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:154fd67216c2ca38a2edb4089584504fbb6c0694b518b9020ad35ecc97252bb9"}, - {file = "orjson-3.9.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ea3e63e61b4b0beeb08508458bdff2daca7a321468d3c4b320a758a2f554d31"}, - {file = "orjson-3.9.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1eb0b0b2476f357eb2975ff040ef23978137aa674cd86204cfd15d2d17318588"}, - {file = "orjson-3.9.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b9a20a03576c6b7022926f614ac5a6b0914486825eac89196adf3267c6489d"}, - {file = "orjson-3.9.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:915e22c93e7b7b636240c5a79da5f6e4e84988d699656c8e27f2ac4c95b8dcc0"}, - {file = "orjson-3.9.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f26fb3e8e3e2ee405c947ff44a3e384e8fa1843bc35830fe6f3d9a95a1147b6e"}, - {file = "orjson-3.9.7-cp312-none-win_amd64.whl", hash = "sha256:d8692948cada6ee21f33db5e23460f71c8010d6dfcfe293c9b96737600a7df78"}, - {file = "orjson-3.9.7-cp37-cp37m-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7bab596678d29ad969a524823c4e828929a90c09e91cc438e0ad79b37ce41166"}, - {file = "orjson-3.9.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63ef3d371ea0b7239ace284cab9cd00d9c92b73119a7c274b437adb09bda35e6"}, - {file = "orjson-3.9.7-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f8fcf696bbbc584c0c7ed4adb92fd2ad7d153a50258842787bc1524e50d7081"}, - {file = "orjson-3.9.7-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:90fe73a1f0321265126cbba13677dcceb367d926c7a65807bd80916af4c17047"}, - {file = "orjson-3.9.7-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:45a47f41b6c3beeb31ac5cf0ff7524987cfcce0a10c43156eb3ee8d92d92bf22"}, - {file = "orjson-3.9.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a2937f528c84e64be20cb80e70cea76a6dfb74b628a04dab130679d4454395c"}, - {file = "orjson-3.9.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b4fb306c96e04c5863d52ba8d65137917a3d999059c11e659eba7b75a69167bd"}, - {file = "orjson-3.9.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:410aa9d34ad1089898f3db461b7b744d0efcf9252a9415bbdf23540d4f67589f"}, - {file = "orjson-3.9.7-cp37-none-win32.whl", hash = "sha256:26ffb398de58247ff7bde895fe30817a036f967b0ad0e1cf2b54bda5f8dcfdd9"}, - {file = "orjson-3.9.7-cp37-none-win_amd64.whl", hash = "sha256:bcb9a60ed2101af2af450318cd89c6b8313e9f8df4e8fb12b657b2e97227cf08"}, - {file = "orjson-3.9.7-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5da9032dac184b2ae2da4bce423edff7db34bfd936ebd7d4207ea45840f03905"}, - {file = "orjson-3.9.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7951af8f2998045c656ba8062e8edf5e83fd82b912534ab1de1345de08a41d2b"}, - {file = "orjson-3.9.7-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b8e59650292aa3a8ea78073fc84184538783966528e442a1b9ed653aa282edcf"}, - {file = "orjson-3.9.7-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9274ba499e7dfb8a651ee876d80386b481336d3868cba29af839370514e4dce0"}, - {file = "orjson-3.9.7-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca1706e8b8b565e934c142db6a9592e6401dc430e4b067a97781a997070c5378"}, - {file = "orjson-3.9.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83cc275cf6dcb1a248e1876cdefd3f9b5f01063854acdfd687ec360cd3c9712a"}, - {file = "orjson-3.9.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:11c10f31f2c2056585f89d8229a56013bc2fe5de51e095ebc71868d070a8dd81"}, - {file = "orjson-3.9.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cf334ce1d2fadd1bf3e5e9bf15e58e0c42b26eb6590875ce65bd877d917a58aa"}, - {file = "orjson-3.9.7-cp38-none-win32.whl", hash = "sha256:76a0fc023910d8a8ab64daed8d31d608446d2d77c6474b616b34537aa7b79c7f"}, - {file = "orjson-3.9.7-cp38-none-win_amd64.whl", hash = "sha256:7a34a199d89d82d1897fd4a47820eb50947eec9cda5fd73f4578ff692a912f89"}, - {file = "orjson-3.9.7-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e7e7f44e091b93eb39db88bb0cb765db09b7a7f64aea2f35e7d86cbf47046c65"}, - {file = "orjson-3.9.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01d647b2a9c45a23a84c3e70e19d120011cba5f56131d185c1b78685457320bb"}, - {file = "orjson-3.9.7-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0eb850a87e900a9c484150c414e21af53a6125a13f6e378cf4cc11ae86c8f9c5"}, - {file = "orjson-3.9.7-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f4b0042d8388ac85b8330b65406c84c3229420a05068445c13ca28cc222f1f7"}, - {file = "orjson-3.9.7-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd3e7aae977c723cc1dbb82f97babdb5e5fbce109630fbabb2ea5053523c89d3"}, - {file = "orjson-3.9.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c616b796358a70b1f675a24628e4823b67d9e376df2703e893da58247458956"}, - {file = "orjson-3.9.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c3ba725cf5cf87d2d2d988d39c6a2a8b6fc983d78ff71bc728b0be54c869c884"}, - {file = "orjson-3.9.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4891d4c934f88b6c29b56395dfc7014ebf7e10b9e22ffd9877784e16c6b2064f"}, - {file = "orjson-3.9.7-cp39-none-win32.whl", hash = "sha256:14d3fb6cd1040a4a4a530b28e8085131ed94ebc90d72793c59a713de34b60838"}, - {file = "orjson-3.9.7-cp39-none-win_amd64.whl", hash = "sha256:9ef82157bbcecd75d6296d5d8b2d792242afcd064eb1ac573f8847b52e58f677"}, - {file = "orjson-3.9.7.tar.gz", hash = "sha256:85e39198f78e2f7e054d296395f6c96f5e02892337746ef5b6a1bf3ed5910142"}, + {file = "orjson-3.9.9-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:f28090060a31f4d11221f9ba48b2273b0d04b702f4dcaa197c38c64ce639cc51"}, + {file = "orjson-3.9.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8038ba245d0c0a6337cfb6747ea0c51fe18b0cf1a4bc943d530fd66799fae33d"}, + {file = "orjson-3.9.9-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:543b36df56db195739c70d645ecd43e49b44d5ead5f8f645d2782af118249b37"}, + {file = "orjson-3.9.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8e7877256b5092f1e4e48fc0f1004728dc6901e7a4ffaa4acb0a9578610aa4ce"}, + {file = "orjson-3.9.9-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12b83e0d8ba4ca88b894c3e00efc59fe6d53d9ffb5dbbb79d437a466fc1a513d"}, + {file = "orjson-3.9.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef06431f021453a47a9abb7f7853f04f031d31fbdfe1cc83e3c6aadde502cce"}, + {file = "orjson-3.9.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0a1a4d9e64597e550428ba091e51a4bcddc7a335c8f9297effbfa67078972b5c"}, + {file = "orjson-3.9.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:879d2d1f6085c9c0831cec6716c63aaa89e41d8e036cabb19a315498c173fcc6"}, + {file = "orjson-3.9.9-cp310-none-win32.whl", hash = "sha256:d3f56e41bc79d30fdf077073072f2377d2ebf0b946b01f2009ab58b08907bc28"}, + {file = "orjson-3.9.9-cp310-none-win_amd64.whl", hash = "sha256:ab7bae2b8bf17620ed381e4101aeeb64b3ba2a45fc74c7617c633a923cb0f169"}, + {file = "orjson-3.9.9-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:31d676bc236f6e919d100fb85d0a99812cff1ebffaa58106eaaec9399693e227"}, + {file = "orjson-3.9.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:678ffb5c0a6b1518b149cc328c610615d70d9297e351e12c01d0beed5d65360f"}, + {file = "orjson-3.9.9-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a71b0cc21f2c324747bc77c35161e0438e3b5e72db6d3b515310457aba743f7f"}, + {file = "orjson-3.9.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae72621f216d1d990468291b1ec153e1b46e0ed188a86d54e0941f3dabd09ee8"}, + {file = "orjson-3.9.9-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:512e5a41af008e76451f5a344941d61f48dddcf7d7ddd3073deb555de64596a6"}, + {file = "orjson-3.9.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f89dc338a12f4357f5bf1b098d3dea6072fb0b643fd35fec556f4941b31ae27"}, + {file = "orjson-3.9.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:957a45fb201c61b78bcf655a16afbe8a36c2c27f18a998bd6b5d8a35e358d4ad"}, + {file = "orjson-3.9.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d1c01cf4b8e00c7e98a0a7cf606a30a26c32adf2560be2d7d5d6766d6f474b31"}, + {file = "orjson-3.9.9-cp311-none-win32.whl", hash = "sha256:397a185e5dd7f8ebe88a063fe13e34d61d394ebb8c70a443cee7661b9c89bda7"}, + {file = "orjson-3.9.9-cp311-none-win_amd64.whl", hash = "sha256:24301f2d99d670ded4fb5e2f87643bc7428a54ba49176e38deb2887e42fe82fb"}, + {file = "orjson-3.9.9-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:bd55ea5cce3addc03f8fb0705be0cfed63b048acc4f20914ce5e1375b15a293b"}, + {file = "orjson-3.9.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b28c1a65cd13fff5958ab8b350f0921121691464a7a1752936b06ed25c0c7b6e"}, + {file = "orjson-3.9.9-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b97a67c47840467ccf116136450c50b6ed4e16a8919c81a4b4faef71e0a2b3f4"}, + {file = "orjson-3.9.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:75b805549cbbcb963e9c9068f1a05abd0ea4c34edc81f8d8ef2edb7e139e5b0f"}, + {file = "orjson-3.9.9-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5424ecbafe57b2de30d3b5736c5d5835064d522185516a372eea069b92786ba6"}, + {file = "orjson-3.9.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d2cd6ef4726ef1b8c63e30d8287225a383dbd1de3424d287b37c1906d8d2855"}, + {file = "orjson-3.9.9-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c959550e0705dc9f59de8fca1a316da0d9b115991806b217c82931ac81d75f74"}, + {file = "orjson-3.9.9-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ece2d8ed4c34903e7f1b64fb1e448a00e919a4cdb104fc713ad34b055b665fca"}, + {file = "orjson-3.9.9-cp312-none-win_amd64.whl", hash = "sha256:f708ca623287186e5876256cb30599308bce9b2757f90d917b7186de54ce6547"}, + {file = "orjson-3.9.9-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:335406231f9247f985df045f0c0c8f6b6d5d6b3ff17b41a57c1e8ef1a31b4d04"}, + {file = "orjson-3.9.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d9b5440a5d215d9e1cfd4aee35fd4101a8b8ceb8329f549c16e3894ed9f18b5"}, + {file = "orjson-3.9.9-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e98ca450cb4fb176dd572ce28c6623de6923752c70556be4ef79764505320acb"}, + {file = "orjson-3.9.9-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3bf6ca6bce22eb89dd0650ef49c77341440def966abcb7a2d01de8453df083a"}, + {file = "orjson-3.9.9-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb50d869b3c97c7c5187eda3759e8eb15deb1271d694bc5d6ba7040db9e29036"}, + {file = "orjson-3.9.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fcf06c69ccc78e32d9f28aa382ab2ab08bf54b696dbe00ee566808fdf05da7d"}, + {file = "orjson-3.9.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9a4402e7df1b5c9a4c71c7892e1c8f43f642371d13c73242bda5964be6231f95"}, + {file = "orjson-3.9.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b20becf50d4aec7114dc902b58d85c6431b3a59b04caa977e6ce67b6fee0e159"}, + {file = "orjson-3.9.9-cp38-none-win32.whl", hash = "sha256:1f352117eccac268a59fedac884b0518347f5e2b55b9f650c2463dd1e732eb61"}, + {file = "orjson-3.9.9-cp38-none-win_amd64.whl", hash = "sha256:c4eb31a8e8a5e1d9af5aa9e247c2a52ad5cf7e968aaa9aaefdff98cfcc7f2e37"}, + {file = "orjson-3.9.9-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:4a308aeac326c2bafbca9abbae1e1fcf682b06e78a54dad0347b760525838d85"}, + {file = "orjson-3.9.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e159b97f5676dcdac0d0f75ec856ef5851707f61d262851eb41a30e8fadad7c9"}, + {file = "orjson-3.9.9-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f692e7aabad92fa0fff5b13a846fb586b02109475652207ec96733a085019d80"}, + {file = "orjson-3.9.9-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cffb77cf0cd3cbf20eb603f932e0dde51b45134bdd2d439c9f57924581bb395b"}, + {file = "orjson-3.9.9-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c63eca397127ebf46b59c9c1fb77b30dd7a8fc808ac385e7a58a7e64bae6e106"}, + {file = "orjson-3.9.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06f0c024a75e8ba5d9101facb4fb5a028cdabe3cdfe081534f2a9de0d5062af2"}, + {file = "orjson-3.9.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8cba20c9815c2a003b8ca4429b0ad4aa87cb6649af41365821249f0fd397148e"}, + {file = "orjson-3.9.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:906cac73b7818c20cf0f6a7dde5a6f009c52aecc318416c7af5ea37f15ca7e66"}, + {file = "orjson-3.9.9-cp39-none-win32.whl", hash = "sha256:50232572dd300c49f134838c8e7e0917f29a91f97dbd608d23f2895248464b7f"}, + {file = "orjson-3.9.9-cp39-none-win_amd64.whl", hash = "sha256:920814e02e3dd7af12f0262bbc18b9fe353f75a0d0c237f6a67d270da1a1bb44"}, + {file = "orjson-3.9.9.tar.gz", hash = "sha256:02e693843c2959befdd82d1ebae8b05ed12d1cb821605d5f9fe9f98ca5c9fd2b"}, ] [[package]] @@ -1126,6 +1278,19 @@ files = [ {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, ] +[[package]] +name = "pgvector" +version = "0.2.3" +description = "pgvector support for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pgvector-0.2.3-py2.py3-none-any.whl", hash = "sha256:9d53dc01138ecc7c9aca64e4680cfa9edf4c38f9cb8ed7098317871fdd211824"}, +] + +[package.dependencies] +numpy = "*" + [[package]] name = "platformdirs" version = "3.11.0" @@ -1595,6 +1760,65 @@ files = [ [package.dependencies] tokenize-rt = ">=5.2.0" +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + [[package]] name = "requests" version = "2.31.0" @@ -1717,9 +1941,7 @@ python-versions = ">=3.7" files = [ {file = "SQLAlchemy-2.0.22-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f146c61ae128ab43ea3a0955de1af7e1633942c2b2b4985ac51cc292daf33222"}, {file = "SQLAlchemy-2.0.22-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:875de9414393e778b655a3d97d60465eb3fae7c919e88b70cc10b40b9f56042d"}, - {file = "SQLAlchemy-2.0.22-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13790cb42f917c45c9c850b39b9941539ca8ee7917dacf099cc0b569f3d40da7"}, {file = "SQLAlchemy-2.0.22-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e04ab55cf49daf1aeb8c622c54d23fa4bec91cb051a43cc24351ba97e1dd09f5"}, - {file = "SQLAlchemy-2.0.22-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a42c9fa3abcda0dcfad053e49c4f752eef71ecd8c155221e18b99d4224621176"}, {file = "SQLAlchemy-2.0.22-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:14cd3bcbb853379fef2cd01e7c64a5d6f1d005406d877ed9509afb7a05ff40a5"}, {file = "SQLAlchemy-2.0.22-cp310-cp310-win32.whl", hash = "sha256:d143c5a9dada696bcfdb96ba2de4a47d5a89168e71d05a076e88a01386872f97"}, {file = "SQLAlchemy-2.0.22-cp310-cp310-win_amd64.whl", hash = "sha256:ccd87c25e4c8559e1b918d46b4fa90b37f459c9b4566f1dfbce0eb8122571547"}, @@ -1740,25 +1962,19 @@ files = [ {file = "SQLAlchemy-2.0.22-cp312-cp312-win32.whl", hash = "sha256:154a32f3c7b00de3d090bc60ec8006a78149e221f1182e3edcf0376016be9396"}, {file = "SQLAlchemy-2.0.22-cp312-cp312-win_amd64.whl", hash = "sha256:129415f89744b05741c6f0b04a84525f37fbabe5dc3774f7edf100e7458c48cd"}, {file = "SQLAlchemy-2.0.22-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3940677d341f2b685a999bffe7078697b5848a40b5f6952794ffcf3af150c301"}, - {file = "SQLAlchemy-2.0.22-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55914d45a631b81a8a2cb1a54f03eea265cf1783241ac55396ec6d735be14883"}, {file = "SQLAlchemy-2.0.22-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2096d6b018d242a2bcc9e451618166f860bb0304f590d205173d317b69986c95"}, - {file = "SQLAlchemy-2.0.22-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:19c6986cf2fb4bc8e0e846f97f4135a8e753b57d2aaaa87c50f9acbe606bd1db"}, {file = "SQLAlchemy-2.0.22-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6ac28bd6888fe3c81fbe97584eb0b96804bd7032d6100b9701255d9441373ec1"}, {file = "SQLAlchemy-2.0.22-cp37-cp37m-win32.whl", hash = "sha256:cb9a758ad973e795267da334a92dd82bb7555cb36a0960dcabcf724d26299db8"}, {file = "SQLAlchemy-2.0.22-cp37-cp37m-win_amd64.whl", hash = "sha256:40b1206a0d923e73aa54f0a6bd61419a96b914f1cd19900b6c8226899d9742ad"}, {file = "SQLAlchemy-2.0.22-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3aa1472bf44f61dd27987cd051f1c893b7d3b17238bff8c23fceaef4f1133868"}, {file = "SQLAlchemy-2.0.22-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:56a7e2bb639df9263bf6418231bc2a92a773f57886d371ddb7a869a24919face"}, - {file = "SQLAlchemy-2.0.22-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ccca778c0737a773a1ad86b68bda52a71ad5950b25e120b6eb1330f0df54c3d0"}, {file = "SQLAlchemy-2.0.22-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c6c3e9350f9fb16de5b5e5fbf17b578811a52d71bb784cc5ff71acb7de2a7f9"}, - {file = "SQLAlchemy-2.0.22-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:564e9f9e4e6466273dbfab0e0a2e5fe819eec480c57b53a2cdee8e4fdae3ad5f"}, {file = "SQLAlchemy-2.0.22-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:af66001d7b76a3fab0d5e4c1ec9339ac45748bc4a399cbc2baa48c1980d3c1f4"}, {file = "SQLAlchemy-2.0.22-cp38-cp38-win32.whl", hash = "sha256:9e55dff5ec115316dd7a083cdc1a52de63693695aecf72bc53a8e1468ce429e5"}, {file = "SQLAlchemy-2.0.22-cp38-cp38-win_amd64.whl", hash = "sha256:4e869a8ff7ee7a833b74868a0887e8462445ec462432d8cbeff5e85f475186da"}, {file = "SQLAlchemy-2.0.22-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9886a72c8e6371280cb247c5d32c9c8fa141dc560124348762db8a8b236f8692"}, {file = "SQLAlchemy-2.0.22-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a571bc8ac092a3175a1d994794a8e7a1f2f651e7c744de24a19b4f740fe95034"}, - {file = "SQLAlchemy-2.0.22-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8db5ba8b7da759b727faebc4289a9e6a51edadc7fc32207a30f7c6203a181592"}, {file = "SQLAlchemy-2.0.22-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b0b3f2686c3f162123adba3cb8b626ed7e9b8433ab528e36ed270b4f70d1cdb"}, - {file = "SQLAlchemy-2.0.22-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0c1fea8c0abcb070ffe15311853abfda4e55bf7dc1d4889497b3403629f3bf00"}, {file = "SQLAlchemy-2.0.22-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4bb062784f37b2d75fd9b074c8ec360ad5df71f933f927e9e95c50eb8e05323c"}, {file = "SQLAlchemy-2.0.22-cp39-cp39-win32.whl", hash = "sha256:58a3aba1bfb32ae7af68da3f277ed91d9f57620cf7ce651db96636790a78b736"}, {file = "SQLAlchemy-2.0.22-cp39-cp39-win_amd64.whl", hash = "sha256:92e512a6af769e4725fa5b25981ba790335d42c5977e94ded07db7d641490a85"}, @@ -1767,7 +1983,7 @@ files = [ ] [package.dependencies] -greenlet = {version = "!=0.4.17", markers = "platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\""} +greenlet = {version = "!=0.4.17", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""} typing-extensions = ">=4.2.0" [package.extras] @@ -1811,6 +2027,20 @@ anyio = ">=3.4.0,<5" [package.extras] full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyaml"] +[[package]] +name = "tenacity" +version = "8.2.3" +description = "Retry code until it succeeds" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tenacity-8.2.3-py3-none-any.whl", hash = "sha256:ce510e327a630c9e1beaf17d42e6ffacc88185044ad85cf74c0a8887c6a0f88c"}, + {file = "tenacity-8.2.3.tar.gz", hash = "sha256:5398ef0d78e63f40007c1fb4c0bff96e1911394d2fa8d194f77619c05ff6cc8a"}, +] + +[package.extras] +doc = ["reno", "sphinx", "tornado (>=4.5)"] + [[package]] name = "tokenize-rt" version = "5.2.0" @@ -1878,6 +2108,21 @@ files = [ {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, ] +[[package]] +name = "typing-inspect" +version = "0.9.0" +description = "Runtime inspection utilities for typing module." +optional = false +python-versions = "*" +files = [ + {file = "typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f"}, + {file = "typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78"}, +] + +[package.dependencies] +mypy-extensions = ">=0.3.0" +typing-extensions = ">=3.7.4" + [[package]] name = "urllib3" version = "2.0.6" @@ -2087,4 +2332,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "cf7c2e88dd377d6929d87da3553dabdc48acaa30d58f7de2d8303159180b0c09" +content-hash = "e89034ff2a2129b8963474f4adc276ef030e60de0178dc93efa754d5df11f81f" diff --git a/src/assistant/pyproject.toml b/src/assistant/pyproject.toml index 45753e6..485b554 100644 --- a/src/assistant/pyproject.toml +++ b/src/assistant/pyproject.toml @@ -13,7 +13,7 @@ profile = "black" py_version = "311" [tool.poetry] -authors = ["ijaric@gmail.com", "jsdio@jsdio.ru"] +authors = ["jsdio@jsdio.ru"] description = "" name = "fastapi_project" readme = "README.md" @@ -22,17 +22,17 @@ version = "0.1.0" [tool.poetry.dependencies] alembic = "^1.12.0" asyncpg = "^0.28.0" -dill = "^0.3.7" fastapi = "0.103.1" greenlet = "^2.0.2" httpx = "^0.25.0" +langchain = "^0.0.314" multidict = "^6.0.4" openai = "^0.28.1" -orjson = "3.9.7" +orjson = "^3.9.7" +pgvector = "^0.2.3" psycopg2-binary = "^2.9.9" pydantic = {extras = ["email"], version = "^2.3.0"} pydantic-settings = "^2.0.3" -pytest = "^7.4.2" pytest-asyncio = "^0.21.1" python = "^3.11" python-jose = "^3.3.0" @@ -40,7 +40,6 @@ python-magic = "^0.4.27" python-multipart = "^0.0.6" sqlalchemy = "^2.0.20" uvicorn = "^0.23.2" -wrapt = "^1.15.0" [tool.poetry.dev-dependencies] black = "^23.7.0" diff --git a/src/bot_aiogram/.env.example b/src/bot_aiogram/.env.example index 9cca803..8f16cad 100644 --- a/src/bot_aiogram/.env.example +++ b/src/bot_aiogram/.env.example @@ -8,3 +8,6 @@ BOT_ADMINS=123456,654321 API_PROTOCOL=http API_URL=api API_PORT=8000 + +REDIS_HOST=redis +REDIS_PORT=6379 diff --git a/src/bot_aiogram/docker-compose.yml b/src/bot_aiogram/docker-compose.yml index d1a1082..4961d78 100755 --- a/src/bot_aiogram/docker-compose.yml +++ b/src/bot_aiogram/docker-compose.yml @@ -12,6 +12,22 @@ services: networks: - tg_bot_network + redis: + image: redis:7.0.11 + restart: always + env_file: + - .env + ports: + - "127.0.0.1:${REDIS_PORT}:${REDIS_PORT}" + command: redis-server --bind 0.0.0.0 --appendonly yes + volumes: + - redis_data:/data + networks: + - tg_bot_network + +volumes: + redis_data: + networks: tg_bot_network: driver: bridge