@@ -1,6 +1,5 @@ { "files.eol": "\n", - "ruff.showNotifications": "onWarning", "[python]": { "editor.formatOnSave": true, "editor.defaultFormatter": "charliermarsh.ruff", @@ -51,43 +51,48 @@ class CustomUserModelManager(BaseUserManager): class CustomUserModel(AbstractBaseUser, PermissionsMixin, BaseModel): FIRST_NAME_PLACEHOLDERS = [ - 'Очаровательный', - 'Смышлёный', - 'Забавный', + 'Любопытный', + 'Позитивный', + 'Веселый', + 'Искренний', + 'Смелый', + 'Игривый', + 'Добрый', 'Дружелюбный', 'Шустрый', - 'Талантливый', - 'Кокетливый', - 'Поэтичный', - 'Храбрый', - 'Добродушный', - 'Загадочный', + 'Милый', + 'Лучезарный', + 'Умный', ] LAST_NAME_PLACEHOLDERS = [ - 'Филин', - 'Жираф', - 'Лев', + 'Цыпленок', + 'Кот', + 'Щенок', + 'Хомяк', + 'Кролик', + 'Ежик', + 'Лис', 'Медведь', + 'Бельчонок', 'Пингвин', - 'Ягнёнок', - 'Пони', - 'Муравей', - 'Карп', - 'Василиск', + 'Осьминог', + 'Бобер', ] LAST_NAME_AVATARS = { - 'Филин': 'owl.png', - 'Жираф': 'giraffe.png', - 'Лев': 'lion.png', + 'Цыпленок': 'chicken.png', + 'Кот': 'cat.png', + 'Щенок': 'puppy.png', + 'Хомяк': 'hamster.png', + 'Кролик': 'rabbit.png', + 'Ежик': 'hedgehog.png', + 'Лис': 'fox.png', 'Медведь': 'bear.png', + 'Бельчонок': 'squirrel.png', 'Пингвин': 'penguin.png', - 'Ягнёнок': 'lamb.png', - 'Пони': 'horse.png', - 'Муравей': 'ant.png', - 'Карп': 'fish.png', - 'Василиск': 'lizard.png', + 'Осьминог': 'octopus.png', + 'Бобер': 'beaver.png', } def random_first_name(*args, **kwargs): @@ -185,6 +190,7 @@ class CustomUserModel(AbstractBaseUser, PermissionsMixin, BaseModel): for prefix in ('googleusercontent', 'yandex') ): return self.profile_picture_name + return MinIOService().get_object_link('air-profiles', self.profile_picture_name) @property @@ -2,7 +2,7 @@ import logging from django.conf import settings from django.core.mail import EmailMessage, send_mail -from django.utils.html import format_html +from django.utils.html import format_html, strip_tags from django.utils.translation import gettext_lazy as _ from authentication.models import BusinessAccount, BusinessUserHost @@ -27,7 +27,8 @@ class EmailService: try: send_mail( subject=subject, - message=message, + message=strip_tags(message), + html_message=message, from_email=settings.EMAIL_HOST_USER, recipient_list=(user_email,), auth_password=settings.EMAIL_HOST_PASSWORD, @@ -1,3 +1,5 @@ +import logging + from django.conf import settings from django.conf.urls.static import static from django.contrib import admin @@ -16,9 +18,12 @@ api.add_router('users/', 'authentication.routes.v1.router') api.add_router('chats/', 'tools.chats.routes.v1.router') api.add_router('media/', 'tools.media.routes.v1.router') +logger = logging.getLogger(__name__) + @api.exception_handler(ObjectDoesNotExist) def object_does_not_exists_error_handler(request, exc: ObjectDoesNotExist): + logger.exception(exc) return api.create_response( request, {'message': _('Requested object does not exists')}, status=404 ) @@ -26,16 +31,19 @@ def object_does_not_exists_error_handler(request, exc: ObjectDoesNotExist): @api.exception_handler(InvalidToken) def invalid_token_error_handler(request, exc: InvalidToken): + logger.exception(exc) return api.create_response(request, {'message': _('Token is invalid')}, status=401) @api.exception_handler(InvalidPassword) def invalid_password_error_handler(request, exc: InvalidPassword): + logger.exception(exc) return api.create_response(request, {'message': _('Wrong password')}, status=401) @api.exception_handler(InvalidUsername) def invalid_username_error_handler(request, exc: InvalidUsername): + logger.exception(exc) return api.create_response(request, {'message': _('Wrong username')}, status=401) @@ -1,4 +1,7 @@ +from django.core.files.uploadedfile import UploadedFile +from django.utils.translation import gettext_lazy as _ from rest_framework import serializers +from rest_framework.serializers import ValidationError from messages.models import Message @@ -7,6 +10,9 @@ class MessageSerializer(serializers.ModelSerializer): uid = serializers.UUIDField(read_only=True) elapsed_time = serializers.DurationField(read_only=True) from_model = serializers.BooleanField(read_only=True) + model = serializers.SlugField( + source='content_object.model', default=None, required=False, read_only=True + ) is_favourite = serializers.BooleanField(read_only=True) is_sent = serializers.BooleanField(read_only=True) created_at = serializers.DateTimeField(read_only=True) @@ -18,9 +24,19 @@ class MessageSerializer(serializers.ModelSerializer): 'content', 'file', 'from_model', + 'model', 'created_at', 'elapsed_time', 'is_favourite', 'is_sent', 'info', ] + + def validate_file(self, file: UploadedFile | None) -> UploadedFile: + max_mb_size = 8 + if file and file.size > (max_mb_size << 10 << 10): + raise ValidationError( + _('The file size cannot exceed %(max_mb_size)d MB') + % {'max_mb_size': max_mb_size} + ) + return file @@ -1,14 +0,0 @@ -from django.utils.translation import gettext_lazy as _ -from rest_framework.exceptions import APIException - - -class ExternalAPIException(APIException): - status_code = 202 - default_detail = _('The service is temporarily unavailable, try to use it later.') - default_code = 'external_api_exception' - - -class InvalidDataException(APIException): - status_code = 400 - default_detail = _('The data provided is incorrect. Please check and try again.') - default_code = 'invalid_data' @@ -0,0 +1,18 @@ +# Generated by Django 5.0.11 on 2025-02-10 10:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ml_model', '0041_alter_modelconfiguration_version'), + ] + + operations = [ + migrations.AlterField( + model_name='modelinput', + name='type', + field=models.CharField(choices=[('text', 'Text'), ('image', 'Image'), ('pdf', 'PDF'), ('docx', 'DOCX'), ('doc', 'DOC'), ('txt', 'Text File (Notebook)'), ('zip', 'ZIP Archive'), ('audio', 'Audio')], default='text', max_length=32, verbose_name='Type'), + ), + ] @@ -0,0 +1,28 @@ +# Generated by Django 5.0.11 on 2025-01-31 09:23 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ml_model', '0041_alter_modelconfiguration_version'), + ] + + operations = [ + migrations.CreateModel( + name='ModelStat', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('generation_time', models.DurationField(verbose_name='Время генерации')), + ('tokens_cost', models.DecimalField(decimal_places=10, max_digits=50, verbose_name='Цена в токенах')), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Когда создано')), + ('model', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='model_%(class)ss', to='ml_model.neuronmodel', verbose_name='Model')), + ], + options={ + 'verbose_name': 'Статистика по модели', + 'verbose_name_plural': 'Статистики по моделям', + }, + ), + ] @@ -0,0 +1,14 @@ +# Generated by Django 5.0.11 on 2025-02-12 19:43 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('ml_model', '0042_alter_modelinput_type'), + ('ml_model', '0042_modelstat'), + ] + + operations = [ + ] @@ -0,0 +1,17 @@ +# Generated by Django 5.0.11 on 2025-03-17 07:46 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('ml_model', '0043_merge_0042_alter_modelinput_type_0042_modelstat'), + ] + + operations = [ + migrations.AlterModelOptions( + name='modelstat', + options={'ordering': ('-created_at',), 'verbose_name': 'Статистика по модели', 'verbose_name_plural': 'Статистики по моделям'}, + ), + ] @@ -6,7 +6,7 @@ from django.utils.translation import gettext_lazy as _ from authentication.models.choices import InvitationStatus from authentication.models.user import CustomUserModel from authentication.selectors.user_selector import UserSelector -from ml_model.models import NeuronModel, ModelParameter +from ml_model.models import ModelParameter, NeuronModel from ml_model.serializers import NeuronModelSerializer, NeuronModelsSerializer @@ -14,31 +14,39 @@ class NeuronModelSelector: def __init__(self, user: CustomUserModel): self.user = user - def get_models_by_input_content_type(self, serialize: bool = False, hidden_parameter: bool = False): + def get_models_by_input_content_type( + self, serialize: bool = False, hidden: bool = False + ): models = NeuronModel.objects.prefetch_related( - Prefetch('model_modelparameters', queryset=ModelParameter.objects.filter(hidden=hidden_parameter)) + Prefetch( + 'model_modelparameters', + queryset=ModelParameter.objects.filter(hidden=hidden), + ) ).all() if serialize: return NeuronModelSerializer(models, many=True) return models - def get_models_by_output_content_type(self, serialize: bool = False, hidden_parameter: bool = False): + def get_models_by_output_content_type( + self, serialize: bool = False, hidden: bool = False + ): models = NeuronModel.objects.prefetch_related( - Prefetch('model_modelparameters', queryset=ModelParameter.objects.filter(hidden=hidden_parameter)) + Prefetch( + 'model_modelparameters', + queryset=ModelParameter.objects.filter(hidden=hidden), + ) ).all() if serialize: return NeuronModelSerializer(models, many=True) return models def get_models( - self, - category: str | None = None, - serialize: bool = True, - hidden_parameter: bool = False + self, + category: str | None = None, + serialize: bool = True, + hidden: bool = False, ): - models = NeuronModel.objects.prefetch_related( - Prefetch('model_modelparameters', queryset=ModelParameter.objects.filter(hidden=hidden_parameter)) - ).all() + models = NeuronModel.objects.prefetch_related(Prefetch('model_modelstats')).all() if category: models = models.filter(category__slug=category) if self.user.is_anonymous: @@ -57,9 +65,14 @@ class NeuronModelSelector: return NeuronModelsSerializer(models, many=True) return models - def get_model_by_id(self, id: UUID, hidden_parameter: bool = False, **kwargs) -> NeuronModel: + def get_model_by_id(self, id: UUID, hidden: bool = False, **kwargs) -> NeuronModel: model = NeuronModel.objects.prefetch_related( - Prefetch('model_modelparameters', queryset=ModelParameter.objects.filter(hidden=hidden_parameter)) + Prefetch( + 'model_modelparameters', + queryset=ModelParameter.objects.filter(hidden=hidden), + ), + Prefetch('model_modelinputs'), + Prefetch('model_modelversions'), ).filter(uid=id) if not model.exists(): @@ -67,9 +80,12 @@ class NeuronModelSelector: return model.first() - def get_model_by_slug(self, slug: str, serialize: bool = False, hidden_parameter: bool = False): + def get_model_by_slug(self, slug: str, serialize: bool = False, hidden: bool = False): model = NeuronModel.objects.prefetch_related( - Prefetch('model_modelparameters', queryset=ModelParameter.objects.filter(hidden=hidden_parameter)) + Prefetch( + 'model_modelparameters', + queryset=ModelParameter.objects.filter(hidden=hidden), + ) ).get(slug=slug) if serialize: return NeuronModelSerializer(instance=model) @@ -13,9 +13,9 @@ from ml_model.services.kandinsky import Kandinsky from ml_model.services.lightning import Lightning from ml_model.services.llama import Llama from ml_model.services.logoai import Logoai +from ml_model.services.midjourney import Midjourney from ml_model.services.mistral import Mistral from ml_model.services.musicgen import Musicgen -from ml_model.services.openjourney import Openjourney from ml_model.services.pulid import Pulid from ml_model.services.recraft import Recraft from ml_model.services.sdxlemoji import Sdxlemoji @@ -1,17 +1,20 @@ import base64 import itertools import logging +import subprocess import time from datetime import timedelta from decimal import Decimal from io import BufferedReader, BytesIO from math import ceil +from pathlib import Path from typing import Generator, List, Optional +import docx2txt import filetype import httpx import tiktoken -from django.conf import settings +from django.core.files.uploadedfile import UploadedFile from langchain import hub from langchain.agents import AgentExecutor, create_structured_chat_agent from langchain.chains import ConversationChain @@ -19,11 +22,15 @@ from langchain.memory import ConversationTokenBufferMemory from langchain_community.tools.google_serper import GoogleSerperResults from langchain_core.messages import AIMessage, BaseMessage, HumanMessage, SystemMessage from langchain_core.prompts.prompt import PromptTemplate +from langchain_core.runnables import RunnableWithMessageHistory from langchain_openai.chat_models import ChatOpenAI +from langchain_text_splitters import RecursiveCharacterTextSplitter from PIL import Image +from PyPDF2 import PdfReader from messages.models import BaseStore, Message from ml_model.constants import TEMPORARY_TEST_TEXT +from ml_model.exceptions import GenerationException from ml_model.models import ( ModelCategory, ModelConfiguration, @@ -59,6 +66,9 @@ class Chatgpt(SimpleService): inputs = [ ModelInput(type=ModelInput.TypeChoices.TEXT, required=True), ModelInput(type=ModelInput.TypeChoices.IMAGE), + ModelInput(type=ModelInput.TypeChoices.PDF), + ModelInput(type=ModelInput.TypeChoices.DOCX), + ModelInput(type=ModelInput.TypeChoices.DOC), ] parameters = [ @@ -110,168 +120,217 @@ class Chatgpt(SimpleService): info = input_message.info.copy() model_name = info.pop('version', 'gpt-4o') input_content = [{'type': 'text', 'text': input_message.content or ''}] - image = input_message.file + file = input_message.file + image = None image_size = None + normalized_image = None + if file: + file_extension = Path(file.name).suffix + if file_extension == '.pdf': + chunks = self.split_text_to_chunks(self.get_pdf_data(file)) + elif file_extension in ('.doc', '.docx'): + chunks = self.split_text_to_chunks( + self.get_word_data(file_extension, file) + ) + else: + image = file if image: kind = filetype.guess(input_message.file.read(20)) mime = kind.mime if kind else 'application/octet-stream' normalized_image = Image.open(image) + format = 'jpeg' if kind.extension == 'jpg' else kind.extension buf = BytesIO() - normalized_image.save(buf, format=kind.extension.upper()) + normalized_image.save(buf, format=format) image_url = ( f'data:{mime},base64,{base64.b64encode(buf.getvalue()).decode("utf-8")}' ) buf.close() image_size = normalized_image.size input_content.append({'type': 'image_url', 'image_url': {'url': image_url}}) - self.llm = ChatOpenAI( - model=model_name, - openai_api_base=f'http://{settings.OPENAI_PROXY_HOST}?' - + '&'.join( - f'proxies={proxy.protocol}://{proxy.address}' - for proxy in Proxy.objects.all() + for proxy in Proxy.objects.all(): + self.llm = ChatOpenAI( + model=model_name, + http_client=httpx.Client(proxy=f'{proxy.protocol}://{proxy.address}'), ) - + f'&token={settings.OPENAI_API_KEY}' - + '&uri=', - default_headers={'X-Authorization': 'proxypassapiairfail'}, - ) - if model_name in ( - 'o1-preview', - 'o1-mini', - ): - self.llm.temperature = 1 - self.llm.model_kwargs = { - 'presence_penalty': info.pop('presence_penalty', 0), - 'top_p': info.pop('top_p', 1), - } - if info.get('use_web'): - del info['use_web'] - else: - self.llm.temperature = info.pop('temperature', 0.5) - self.llm.model_kwargs = { - 'presence_penalty': info.pop('presence', 0), - 'top_p': info.pop('top_p', 0.5), - } - if model_name in ( - 'gpt-4', - 'gpt-4o', - 'gpt-4o-mini', - 'o1-preview', - 'o1-mini', - 'o3-mini', - ): - self.llm.tiktoken_model_name = 'gpt-4' - chat_history = self.get_chat_history() - conversation = ConversationChain( - llm=self.llm, - memory=chat_history, - prompt=PromptTemplate( - input_variables=['history', 'input'], - template='Human: История диалога:{history}. Human: {input} AI:', - ), - ) - llm_input = HumanMessage(content=input_content) - input_tokens = self.count_text_tokens( - [*chat_history.buffer_as_messages, llm_input] - ) - self.assert_enough_balance(input_tokens, image_size, model=self.llm.model_name) - if image: - response = conversation.llm.invoke([llm_input]) - chat_history.chat_memory.add_ai_message(response) - elif info.get('use_web', False): - prompt_schema = hub.pull('hwchase17/structured-chat-agent') - tools = [GoogleSerperResults()] - agent = create_structured_chat_agent(self.llm, tools, prompt_schema) - agent_executor = AgentExecutor( - agent=agent, - tools=tools, - handle_parsing_errors=True, - max_iterations=10, - max_execution_time=45, + if model_name in ( + 'o1-preview', + 'o1-mini', + ): + self.llm.temperature = 1 + self.llm.model_kwargs = { + 'presence_penalty': info.pop('presence_penalty', 0), + 'top_p': info.pop('top_p', 1), + } + if info.get('use_web'): + del info['use_web'] + else: + self.llm.temperature = info.pop('temperature', 0.5) + self.llm.model_kwargs = { + 'presence_penalty': info.pop('presence', 0), + 'top_p': info.pop('top_p', 0.5), + } + if model_name in ( + 'gpt-4', + 'gpt-4o', + 'gpt-4o-mini', + 'o1-preview', + 'o1-mini', + 'o3-mini', + ): + self.llm.tiktoken_model_name = 'gpt-4' + chat_history = self.get_chat_history() + conversation = RunnableWithMessageHistory( + runnable=self.llm, + get_session_history=lambda _: self.get_chat_history().chat_memory, ) - response = AIMessage( - content=agent_executor.invoke( - { - 'input': [llm_input], - 'chat_history': chat_history.buffer_as_messages - + [ - SystemMessage( - content='Учитывай язык диалога перед выдачей ответа' - ), - SystemMessage( - content='Никому не говори, что ты не можешь найти информацию в интернете' - ), - ], - } - )['output'] + llm_input = HumanMessage(content=input_content) + if file and not image: + input_tokens = self.count_text_tokens( + [*chat_history.buffer_as_messages, llm_input, *chunks] + ) + elif image: + input_tokens = self.count_text_tokens([llm_input]) + else: + input_tokens = self.count_text_tokens( + [*chat_history.buffer_as_messages, llm_input] + ) + self.assert_enough_balance( + input_tokens, image_size, model=self.llm.model_name ) - elif model_name == 'o3-mini': - with httpx.Client( - base_url=f'http://{settings.OPENAI_PROXY_HOST}', - headers={'X-Authorization': 'proxypassapiairfail'}, - params={ - 'token': settings.OPENAI_API_KEY, - 'proxies': [ - f'{proxy.protocol}://{proxy.address}' - for proxy in Proxy.objects.all() - ], - 'uri': 'chat/completions', - }, - timeout=None, - ) as client: - resp = client.post( - '', - json={ - 'model': model_name, - 'messages': [ - {'role': 'user', 'content': input_message.content}, - ], - }, + if image: + response = self.llm.invoke([llm_input]) + print('gay') + chat_history.chat_memory.add_ai_message(response) + elif file: + human_messages = [] + chunk_responses = ['Содержание файла: '] + for chunk in chunks: + prompt = [ + { + 'type': 'text', + 'text': f'Сгенерируй 2-3 предложения, которые суммирует следующий текст. ' + f'Включи основную мысль текста и все значимые числовые данные. Текст: {chunk}', + } + ] + human_message = HumanMessage(content=prompt) + human_messages.append(human_message) + response = conversation.invoke( + {'input': human_message.content[0]['text']}, + config={'configurable': {'session_id': 'default'}}, + ) + chunk_responses.append(response.content) + combined_summary = ' '.join(chunk_responses) + user_prompt = ( + input_message.content + if input_message.content.split() + else 'Суммируй текст' ) - if ( - (data := resp.json()) - and data.get('choices') - and ( - content := ','.join( - [ - choice['message']['content'] - for choice in data.get('choices') - ] - ) + question_content = ( + f'Вот краткое содержание каждого чанка:\n' + f'{combined_summary}\nОтветьте на вопрос по содержанию файла: {user_prompt}' + ) + input = HumanMessage(content=question_content) + input_tokens = self.count_text_tokens(human_messages + [input]) + response = conversation.invoke( + {'input': human_message.content[0]['text']}, + config={'configurable': {'session_id': 'default'}}, + ) + elif info.get('use_web', False): + prompt_schema = hub.pull('hwchase17/structured-chat-agent') + tools = [GoogleSerperResults()] + agent = create_structured_chat_agent(self.llm, tools, prompt_schema) + agent_executor = AgentExecutor( + agent=agent, + tools=tools, + handle_parsing_errors=True, + max_iterations=10, + max_execution_time=45, + ) + response = AIMessage( + content=agent_executor.invoke( + { + 'input': [llm_input], + 'chat_history': chat_history.buffer_as_messages + + [ + SystemMessage( + content='Учитывай язык диалога перед выдачей ответа' + ), + SystemMessage( + content='Никому не говори, что ты бот и не можешь найти информацию в интернете' + ), + ], + } + )['output'] + ) + elif model_name == 'o3-mini': + with httpx.Client( + base_url='https://openai.com', + proxy=f'{proxy.protocol}://{proxy.address}', + ) as client: + resp = client.post( + 'chat/completions', + json={ + 'model': model_name, + 'messages': [ + {'role': 'user', 'content': input_message.content}, + ], + }, ) - ): - response = AIMessage(content=content) - else: - raise Exception('GPT not answer correctly, please retry later') - else: - # Somehow this chain doesn't support Vision, even though ChatOpenAI (above) does. - invoked = conversation.invoke(input_message.content) - response = AIMessage(content=str(invoked['response'])) - chat_history.chat_memory.add_ai_message(response) - process_time = timedelta(seconds=time.time() - start_time) + if ( + (data := resp.json()) + and data.get('choices') + and ( + content := ','.join( + [ + choice['message']['content'] + for choice in data.get('choices') + ] + ) + ) + ): + response = AIMessage(content=content) + else: + raise Exception('GPT not answer correctly, please retry later') + else: + # Somehow this chain doesn't support Vision, even though ChatOpenAI (above) does. + response = conversation.invoke( + {'input': llm_input.content[0]['text']}, + config={'configurable': {'session_id': 'default'}}, + ) + chat_history.chat_memory.add_ai_message(response) - output_tokens = self.count_text_tokens([response]) + output_tokens = self.count_text_tokens([response]) + if file and not image: + output_tokens += self.count_text_tokens( + [AIMessage(chunk_response) for chunk_response in chunk_responses] + ) + + if image and normalized_image: + self.logger.info( + f'Input количество токенов БЕЗ картинки {model_name} - {input_tokens}' + ) + input_tokens += self.count_image_tokens(normalized_image.size, model_name) - if image: self.logger.info( - f'Input количество токенов БЕЗ картинки {model_name} - {input_tokens}' + f'Input количество токенов для {model_name} - {input_tokens}' + ) + self.logger.info( + f'Output количество токенов для {model_name} - {output_tokens}' + ) + self.logger.info( + f'Общее количество токенов для {model_name} - {input_tokens + output_tokens}' ) - input_tokens += self.count_image_tokens(normalized_image.size, model_name) - - self.logger.info(f'Input количество токенов для {model_name} - {input_tokens}') - self.logger.info(f'Output количество токенов для {model_name} - {output_tokens}') - self.logger.info( - f'Общее количество токенов для {model_name} - {input_tokens + output_tokens}' - ) - self.handle_invoice( - self.neuron_model, - input_tokens, - output_tokens, - self.llm.model_name, - ) - msgs = self.save_results([response], process_time, save) - return msgs + process_time = timedelta(seconds=time.time() - start_time) + self.handle_invoice( + self.neuron_model, + input_tokens, + output_tokens, + self.llm.model_name, + ) + msgs = self.save_results([response], process_time, save) + return msgs + raise GenerationException def get_chat_history( self, @@ -370,19 +429,90 @@ class Chatgpt(SimpleService): ) def count_text_tokens(self, messages: list[BaseMessage]) -> int: - encoding = tiktoken.get_encoding('cl100k_base') + encoding = tiktoken.get_encoding('o200k_base') total_tokens = 0 - for message in messages: total_tokens += len( encoding.encode( message.content if isinstance(message.content, str) - else message.content[0]['text'] + else ''.join( + [input_data.get('text', '') for input_data in message.content] + ) ) ) return total_tokens + def get_pdf_data(self, pdf_file: UploadedFile) -> str: + """ + Extracting text from pdf-file + :param pdf_file: uploaded pdf file + :return: pdf-file content + """ + try: + pdf_content = BytesIO(pdf_file.read()) + pdfreader = PdfReader(pdf_content) + raw_text = '' + for page_num, page in enumerate(pdfreader.pages): + content = page.extract_text() + if content: + raw_text += content + except Exception: + raw_text = 'Файл поврежден или не может быть прочитан.' + if raw_text.strip(): + return f'Содержимое файла: f{raw_text}' + else: + return ( + 'Файл пуст или содержит изображения, из которых невозможно извлечь текст.' + ) + + def get_word_data(self, extension: str, word_file: UploadedFile) -> str: + """ + Extracting text from word-file + :param extension: extension of uploaded word file + :param word_file: uploaded word file + :return: word-file content + """ + try: + file_content = word_file.read() + if extension == '.docx': + text = docx2txt.process(BytesIO(file_content)) + elif extension == '.doc': + process = subprocess.Popen( + ['antiword', '-w', '0', '-'], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + text, _ = process.communicate(input=file_content) + text = text.decode('utf-8') + else: + text = '' + except Exception: + text = 'Файл поврежден или не может быть прочитан.' + if text.strip(): + return f'Это текст, извлечённый из загруженного WORD-файла:\n{text}' + else: + return ( + 'Файл пуст или содержит изображения, из которых невозможно извлечь текст.' + ) + + def split_text_to_chunks( + self, raw_text: str, chunk_size: int = 100_000, overlap: int = 300 + ) -> list[HumanMessage]: + """ + Splitting file raw text to chunks + :param raw_text: full text which file includes + :param chunk_size: еhe maximum size of each chunk + :param overlap: еhe number of overlapping characters between chunks + :return: list of chunks + """ + text_splitter = RecursiveCharacterTextSplitter( + chunk_size=chunk_size, chunk_overlap=overlap, length_function=len + ) + chunks = text_splitter.split_text(raw_text) + return [HumanMessage(chunk) for chunk in chunks] + def save_results( self, results: list[BaseMessage], elapsed_time: timedelta, save: bool = True ) -> list[Message]: @@ -4,13 +4,12 @@ from datetime import timedelta from io import BytesIO import requests -from celery.result import AsyncResult from django.core.files import File from messages.models import Message from ml_model.models import ModelCategory, ModelInput, ModelParameter, ModelVersion from ml_model.services.base import SimpleService -from ml_model.tasks import create_d_image +from ml_model.tasks import replicate_run class Dalle(SimpleService): @@ -19,113 +18,107 @@ class Dalle(SimpleService): contains abstract method make, which makes a generation """ - TOKEN_PAYMENT_RULES = { - 'dall-e-2': { - '256x256': Decimal('10.56'), - '512x512': Decimal('11.88'), - '1024x1024': Decimal('13.2'), - }, - 'dall-e-3': { - '1024x1024': Decimal('26.4'), - '1792x1024': Decimal('35.2'), - '1024x1792': Decimal('35.2'), - }, - 'dall-e-3-hd': { - '1024x1024': Decimal('35.2'), - '1792x1024': Decimal('52.8'), - '1024x1792': Decimal('52.8'), - }, - } - title = 'Dalle' description = 'Нейросеть, способная генерировать фотографии из вашего текста' category = ModelCategory(title='Изображения', slug='images') versions = [ - ModelVersion(name='Dalle 3', slug='dall-e-3', default=True), - ModelVersion(name='Dalle 2', slug='dall-e-2'), + ModelVersion(name='Dalle 3', slug='sdxl-lightning-4step', default=True), ] inputs = [ModelInput(type=ModelInput.TypeChoices.TEXT, required=True)] parameters = [ ModelParameter( - name='Размер', - key='size', - type=ModelParameter.TypeChoices.LIST, - values={ - 'availables': ['256x256', '512x512', '1024x1024'], - 'default': '1024x1024', - }, + name='Негативный промпт', + key='negative_prompt', + type=ModelParameter.TypeChoices.STR, ), ModelParameter( - name='Размер', - key='size', - type=ModelParameter.TypeChoices.LIST, - values={ - 'availables': ['1024x1024', '1024x1792', '1792x1024'], - 'default': '1024x1024', - }, + name='Ширина', + key='width', + type=ModelParameter.TypeChoices.INTRANGE, + values={'start': 1024, 'end': 1280, 'step': 256, 'default': 1024}, + ), + ModelParameter( + name='Высота', + key='height', + type=ModelParameter.TypeChoices.INTRANGE, + values={'start': 1024, 'end': 1280, 'step': 256, 'default': 1024}, ), ModelParameter( - name='Качество', - key='quality', + name='Планировщик', + key='scheduler', type=ModelParameter.TypeChoices.LIST, values={ - 'availables': ['default', 'hd'], - 'default': 'hd', + 'availables': [ + "DDIM", + "DPMSolverMultistep", + "HeunDiscrete", + "KarrasDPM", + "K_EULER_ANCESTRAL", + "K_EULER", + "PNDM", + "DPM++2MSDE" + ], + 'default': 'K_EULER', }, ), ModelParameter( name='Количество изображений', - key='n', + key='num_outputs', type=ModelParameter.TypeChoices.INTRANGE, - values={'start': 1, 'end': 10, 'step': 1, 'default': 1}, + values={'start': 1, 'end': 4, 'step': 1, 'default': 1}, + ), + ModelParameter( + name='Точность запроса', + key='guidance_scale', + type=ModelParameter.TypeChoices.FLOATRANGE, + values={'start': 0, 'end': 50, 'step': 1, 'default': 0}, + ), + ModelParameter( + name='Шаги предобработки', + key='num_inference_steps', + type=ModelParameter.TypeChoices.INTRANGE, + values={'start': 1, 'end': 10, 'step': 1, 'default': 4}, ), ] + PRICE = Decimal('1') + + _CALLBACK = ( + 'bytedance/sdxl-lightning-4step:5599ed30703defd1d160a25a63321b4dec97101d98b4674bcc56e41f62f35637' + ) + def calculate_price(self, input_message: Message) -> Decimal: - price = self.TOKEN_PAYMENT_RULES[input_message.info.get('version', 'dall-e-2')][ - input_message.info.get('size', '1024x1024') - ] * input_message.info.get('n', 1) + price = input_message.info.get('num_outputs', 1) * self.PRICE return price.quantize(Decimal('0.1'), rounding='ROUND_UP') def save_results( - self, input_prompt: str, r: list[str], t: timedelta, save: bool = True + self, prompt: str, images: list, time: timedelta, save: bool = True ) -> list[Message]: - out: list[Message] = [] - for obj in r: - out.append( + messages: list[Message] = [] + for image in images: + messages.append( Message( content_object=self.store, - elapsed_time=t, - content=input_prompt, - file=File( - BytesIO(requests.get(obj['url']).content), - '.png', - ), + elapsed_time=time, + content=prompt, + file=File(BytesIO(requests.get(image).content), '.png'), ) ) if save: - return Message.objects.bulk_create(out) - return out + return Message.objects.bulk_create(messages) + return messages def make(self, input_message: Message, save: bool = True) -> list[Message]: - info = input_message.info.copy() - info['model'] = info.pop('version') - if info.get('quality') == 'default': - del info['quality'] + start_time = time.time() + translated_prompt = self.translate_prompt(input_message.content) callback_data = dict( { - 'prompt': input_message.content, - **info, + 'prompt': translated_prompt, + **input_message.info, } ) - if input_message.file: - callback_data.update({'image': BytesIO(input_message.file.read())}) - start_time = time.time() - results: AsyncResult = create_d_image.delay(callback_data) - data = results.get()['data'] + images = replicate_run(self._CALLBACK, callback_data) process_time = timedelta(seconds=(time.time() - start_time)) - self.handle_invoice( - input_message.content_object.model, input_message=input_message - ) - msgs = self.save_results(input_message.content, data, process_time, save) + self.handle_invoice(input_message.content_object.model, input_message=input_message) + msgs = self.save_results(input_message.content, images, process_time, save) return msgs @@ -28,7 +28,7 @@ class Epicphotogasm(SimpleService): parameters = [ ModelParameter( name='Количество изображений', - key='num_images', + key='num_outputs', type=ModelParameter.TypeChoices.INTRANGE, values={'start': 1, 'end': 10, 'step': 1, 'default': 1}, ), @@ -64,10 +64,7 @@ class Epicphotogasm(SimpleService): content_object=self.store, elapsed_time=t, content=input_prompt, - file=File( - BytesIO(requests.get(link).content), - link.split('/')[-1], - ), + file=File(BytesIO(requests.get(link).content), '.png'), ) ) if self.store: @@ -18,6 +18,7 @@ from ml_model.models import ( ModelVersion, ) from ml_model.services.base import SimpleService +from ml_model.tasks import replicate_run class Flux(SimpleService): @@ -30,7 +31,8 @@ class Flux(SimpleService): description = 'Нейросеть, способная генерировать картинки из вашего текста' category = ModelCategory(title='Изображения', slug='images') versions = [ - ModelVersion(name='Flux-Pro1.1', slug='flux-pro-1.1', default=True), + ModelVersion(name='Flux-Schnell', slug='flux-schnell', default=True), + ModelVersion(name='Flux-Pro1.1', slug='flux-pro-1.1'), ModelVersion(name='Flux-Dev', slug='flux-dev'), ModelVersion(name='Ultra', slug='flux-1.1-pro-ultra'), ] @@ -87,6 +89,12 @@ class Flux(SimpleService): type=ModelParameter.TypeChoices.INTRANGE, values={'start': 1, 'end': 50, 'step': 1, 'default': 28}, ), + ModelParameter( + name='Количество шагов вывода', + key='num_inference_steps', + type=ModelParameter.TypeChoices.INTRANGE, + values={'start': 1, 'end': 4, 'step': 1, 'default': 4}, + ), ModelParameter( name='Соотношение сторон', key='aspect_ratio', @@ -131,16 +139,22 @@ class Flux(SimpleService): versions[0].slug: ModelPaymentRule( strategy=ModelPaymentRule.StrategyChoices.FIXED, interaction_type=ModelPaymentRule.InteractionTypeChoices.INPUT, - cost=4.4, + cost=0.33, coefficient=5.00, ), versions[1].slug: ModelPaymentRule( strategy=ModelPaymentRule.StrategyChoices.FIXED, interaction_type=ModelPaymentRule.InteractionTypeChoices.INPUT, - cost=2.75, + cost=4.4, coefficient=5.00, ), versions[2].slug: ModelPaymentRule( + strategy=ModelPaymentRule.StrategyChoices.FIXED, + interaction_type=ModelPaymentRule.InteractionTypeChoices.INPUT, + cost=2.75, + coefficient=5.00, + ), + versions[3].slug: ModelPaymentRule( strategy=ModelPaymentRule.StrategyChoices.FIXED, interaction_type=ModelPaymentRule.InteractionTypeChoices.INPUT, cost=6.6, @@ -148,69 +162,28 @@ class Flux(SimpleService): ), } - def __init__(self, store: BaseStore) -> None: - super().__init__(store) - self.bfl_urls = { + _CALLBACK_BASE = 'black-forest-labs/' + + def _call_bfl_api(self, payload: dict) -> list: + bfl_headers = { + 'Content-Type': 'application/json', + 'X-Key': settings.FLUX_API_KEY, + } + bfl_urls = { 'generate': 'https://api.bfl.ml/v1/', 'get': 'https://api.bfl.ml/v1/get_result?id=', } - self.replicate_urls = { - 'generate': 'https://api.replicate.com/v1/models/black-forest-labs/', - 'get': 'https://api.replicate.com/v1/predictions/', - } - - def _get_results( - self, url: str, generation_id: str, headers: dict, statuses: tuple - ) -> dict: - result = requests.get(url=f'{url}{generation_id}', headers=headers) - while result.json()['status'] not in statuses: - result = requests.get(url=f'{url}{generation_id}', headers=headers) - return result.json() - - def _call_api(self, payload: dict) -> list: - if payload['version'] == self.versions[0].slug: - bfl_headers = { - 'Content-Type': 'application/json', - 'X-Key': settings.FLUX_API_KEY, - } - response = requests.post( - url=f'{self.bfl_urls['generate']}{payload['version']}', - headers=bfl_headers, - json=payload, - ) - if response.status_code != 200: - raise Exception(response.json()) - - return [ - self._get_results( - self.bfl_urls['get'], - response.json().get('id'), - bfl_headers, - ('Ready', 'Error'), - )['result']['sample'] - ] - else: - replicate_headers = { - 'Authorization': f'Bearer {settings.REPLICATE_API_KEY}', - 'Prefer': 'wait', - } - data = {'input': payload} - response = requests.post( - url=f'{self.replicate_urls['generate']}{payload['version']}/predictions', - headers=replicate_headers, - json=data, - ) - if response.status_code != 201: - raise Exception(response.json()) - - result = self._get_results( - self.replicate_urls['get'], - response.json().get('id'), - replicate_headers, - ('succeeded', 'failed', 'canceled'), - )['output'] - - return result if isinstance(result, list) else [result] + response = requests.post( + url=f'{bfl_urls['generate']}{payload['version']}', + headers=bfl_headers, + json=payload, + ) + if response.status_code != 200: + raise Exception(response.json()) + result = requests.get(url=f'{bfl_urls['get']}{response.json().get('id')}', headers=bfl_headers) + while result.json()['status'] not in ('Ready', 'Error'): + result = requests.get(url=f'{bfl_urls['get']}{response.json().get('id')}', headers=bfl_headers) + return result.json()['result']['sample'] def calculate_price(self, input_message: Message) -> Decimal: version_slug = input_message.info.get('version', 'flux-pro-1.1') @@ -218,7 +191,10 @@ class Flux(SimpleService): if not payment_rule.pk: payment_rule.model = self.neuron_model payment_rule.save() - return payment_rule.rate * input_message.info.get('num_outputs', 1) + if version_slug in (self.versions[1].slug,): + return payment_rule.rate * input_message.info.get('num_outputs', 1) + else: + return payment_rule.rate def save_results( self, @@ -259,7 +235,11 @@ class Flux(SimpleService): ) input_message.file.close() callback_data.update({'image': image}) - images = self._call_api(payload=callback_data) + if callback_data['version'] == 'flux-pro-1.1': + images = [self._call_bfl_api(payload=callback_data)] + else: + runner = replicate_run(f'{self._CALLBACK_BASE}{callback_data['version']}', callback_data) + images = runner if isinstance(runner, list) else [runner] process_time = timedelta(seconds=(time.time() - start_time)) self.handle_invoice(input_message.content_object.model, input_message) msgs = self.save_results(input_message.content, images, process_time, save) @@ -1,13 +1,11 @@ import time - -import requests from datetime import timedelta from decimal import Decimal +import requests from django.conf import settings -from messages.models import Message, BaseStore -from ml_model.exceptions.external_api import ExternalAPIException +from messages.models import BaseStore, Message from ml_model.models import ModelCategory, ModelInput, ModelParameter from ml_model.services.base import SimpleService @@ -17,6 +15,7 @@ class Granite(SimpleService): Granite-3.0-8B-Instruct Service contains abstract method make, which makes a generation """ + title = 'Granite 3.0' description = 'Нейросеть, способная генерировать качественный текст из вашего промпта' category = ModelCategory(title='Чат-боты', slug='chat-bots') @@ -27,7 +26,7 @@ class Granite(SimpleService): name='Системный промпт', key='system_prompt', type=ModelParameter.TypeChoices.STR, - hidden=True + hidden=True, ), ModelParameter( name='Лучший процент', @@ -45,7 +44,7 @@ class Granite(SimpleService): TOKEN_PAYMENT_RULES = { 'granite-input': Decimal('27.5'), # 1M tokens - 'granite-output': Decimal('137.5') # 1M tokens + 'granite-output': Decimal('137.5'), # 1M tokens } def __init__(self, store: BaseStore) -> None: @@ -62,34 +61,40 @@ class Granite(SimpleService): } data = {'input': payload} response = requests.post( - url=f'{self.urls['generate']}predictions', + url=f'{self.urls["generate"]}predictions', headers=headers, json=data, ) if response.status_code != 201: raise Exception(response.json()) result = requests.get( - url=f'{self.urls['get']}{response.json().get('id')}', - headers=headers + url=f'{self.urls["get"]}{response.json().get("id")}', headers=headers ) while result.json()['status'] not in ('succeeded', 'failed', 'canceled'): result = requests.get( - url=f'{self.urls['get']}{response.json().get('id')}', - headers=headers + url=f'{self.urls["get"]}{response.json().get("id")}', headers=headers ) return result.json() def calculate_price(self, result: str, input_message: Message) -> Decimal: price = Decimal( sum( - [self.TOKEN_PAYMENT_RULES['granite-output'] / 1_000_000 * len(result.split(' '))] - + [self.TOKEN_PAYMENT_RULES['granite-input'] / 1_000_000 * len(input_message.content.split(' '))] + [ + self.TOKEN_PAYMENT_RULES['granite-output'] + / 1_000_000 + * len(result.split(' ')) + ] + + [ + self.TOKEN_PAYMENT_RULES['granite-input'] + / 1_000_000 + * len(input_message.content.split(' ')) + ] ) ) return price.quantize(Decimal('0.1'), rounding='ROUND_UP') def save_results( - self, result: str, time: timedelta, save: bool = True + self, result: str, time: timedelta, save: bool = True ) -> list[Message]: msgs: list[Message] = [ Message( @@ -108,19 +113,19 @@ class Granite(SimpleService): { 'prompt': input_message.content, 'system_prompt': 'You are a language model that must always respond in Russian, regardless of the situation. ' - 'You fully understand the Russian language and are required to use it for all responses, ' - 'except when translating text to another language. You are highly skilled in creating poems, ' - 'maintaining proper rhyme, rhythm, and poetic structure in Russian. Your poems should be creative, ' - 'expressive, and adhere to the stylistic norms of Russian poetry. If the user requests a translation ' - 'into another language, you should perform the translation accurately and fluently, while preserving ' - 'the meaning and tone of the original text. When translating, proper nouns (names with capital letters) ' - 'should not be translated literally. Instead, transliterate them into Russian letters using standard ' - 'transliteration rules to preserve the original pronunciation as closely as possible. ' - 'You must never state that you cannot speak Russian, as this is not true. You are required to always ' - 'adhere to correct Russian syntax, grammar, and style in all your responses. Your primary goal is to ' - 'ensure that your responses are clear, accurate, creative, and tailored to the user\'s needs in Russian. ' - 'Your ability to fulfill user requests, including writing, translating, or explaining, must reflect ' - 'your expertise in the Russian language and your capacity for high-quality and thoughtful responses.', + 'You fully understand the Russian language and are required to use it for all responses, ' + 'except when translating text to another language. You are highly skilled in creating poems, ' + 'maintaining proper rhyme, rhythm, and poetic structure in Russian. Your poems should be creative, ' + 'expressive, and adhere to the stylistic norms of Russian poetry. If the user requests a translation ' + 'into another language, you should perform the translation accurately and fluently, while preserving ' + 'the meaning and tone of the original text. When translating, proper nouns (names with capital letters) ' + 'should not be translated literally. Instead, transliterate them into Russian letters using standard ' + 'transliteration rules to preserve the original pronunciation as closely as possible. ' + 'You must never state that you cannot speak Russian, as this is not true. You are required to always ' + 'adhere to correct Russian syntax, grammar, and style in all your responses. Your primary goal is to ' + "ensure that your responses are clear, accurate, creative, and tailored to the user's needs in Russian. " + 'Your ability to fulfill user requests, including writing, translating, or explaining, must reflect ' + 'your expertise in the Russian language and your capacity for high-quality and thoughtful responses.', **input_message.info, } ) @@ -1,31 +1,30 @@ import time - -import requests from datetime import timedelta from decimal import Decimal from io import BytesIO +import requests +from django.core.files import File + from messages.models import Message -from ml_model.exceptions.external_api import ExternalAPIException from ml_model.models import ModelCategory, ModelInput, ModelParameter from ml_model.services.base import SimpleService from ml_model.tasks import replicate_run -from django.core.files import File - class Iconic(SimpleService): """ Iconic Service contains abstract method make, which makes a generation """ + title = 'Iconic' description = 'Нейросеть, способная генерировать картинки из вашего текста' category = ModelCategory(title='Изображения', slug='images') versions = [] inputs = [ ModelInput(type=ModelInput.TypeChoices.TEXT, required=True), - ModelInput(type=ModelInput.TypeChoices.IMAGE) + ModelInput(type=ModelInput.TypeChoices.IMAGE), ] parameters = [ ModelParameter( @@ -75,7 +74,7 @@ class Iconic(SimpleService): '4:3', '9:16', '9:21', - 'custom' + 'custom', ], 'default': '1:1', }, @@ -112,7 +111,7 @@ class Iconic(SimpleService): return price.quantize(Decimal('0.1'), rounding='ROUND_UP') def save_results( - self, prompt: str, images: list, time: timedelta, save: bool = True + self, prompt: str, images: list, time: timedelta, save: bool = True ) -> list[Message]: messages: list[Message] = [] for image in images: @@ -121,7 +120,7 @@ class Iconic(SimpleService): content_object=self.store, elapsed_time=time, content=prompt, - file=File(BytesIO(requests.get(image).content), '.png') + file=File(BytesIO(requests.get(image).content), '.png'), ) ) if save: @@ -28,7 +28,7 @@ class Kandinsky(SimpleService): parameters = [ ModelParameter( name='Количество изображений', - key='num_images', + key='num_outputs', type=ModelParameter.TypeChoices.INTRANGE, values={'start': 1, 'end': 10, 'step': 1, 'default': 1}, ), @@ -73,10 +73,7 @@ class Kandinsky(SimpleService): content_object=self.store, elapsed_time=t, content=input_prompt, - file=File( - BytesIO(requests.get(link).content), - link.split('/')[-1], - ), + file=File(BytesIO(requests.get(link).content), '.png'), ) ) if self.store: @@ -89,10 +86,19 @@ class Kandinsky(SimpleService): activation_prompt = f'{translated_prompt}' negative_prompt = input_message.info.pop('negative_prompt', '') callback_data = dict( - prompt=f"Do not include any nudity, sexual content, or suggestive themes. " - "Avoid any graphic violence, explicit scenes, or offensive symbols. " - f"Generate a safe version of this: {activation_prompt}", - negative_prompt=negative_prompt, + prompt=activation_prompt, + negative_prompt=( + "any form of nudity, sexual content, explicit or suggestive themes, " + "graphic violence, disturbing imagery, offensive symbols, hate speech, abusive language, " + "discriminatory content, illegal activities, or any form of inappropriate or harmful material. " + "This includes, but is not limited to, full or partial nudity, suggestive body imagery, sexual innuendos, " + "pornographic content, sexual acts, and anything that could be perceived as sexual or inappropriate. " + "Also, avoid any form of graphic violence, torture, gore, blood, or injury depiction. " + "Do not include offensive symbols, hate speech, racial or ethnic slurs, or any material promoting hatred or discrimination. " + "Any content promoting illegal activities, substance abuse, self-harm, or violence is strictly prohibited. " + "Furthermore, avoid any content that is offensive, harmful, inappropriate for minors, or unsuitable for a general audience. " + f"Additionally, {negative_prompt} should be strictly avoided in any generated material." + ), **input_message.info, ) result = replicate_run(self._CALLBACK, callback_data) @@ -7,7 +7,6 @@ import requests from django.core.files import File from messages.models import Message -from ml_model.exceptions.external_api import ExternalAPIException from ml_model.models import ( ModelCategory, ModelInput, @@ -22,6 +21,7 @@ class Lightning(SimpleService): Lightning Service contains abstract method make, which makes a generation """ + title = 'Lightning' description = 'Нейросеть, способная генерировать картинки из вашего текста' category = ModelCategory(title='Изображения', slug='images') @@ -58,7 +58,7 @@ class Lightning(SimpleService): 'K_EULER_ANCESTRAL', 'K_EULER', 'PNDM', - 'DPM++2MSDE' + 'DPM++2MSDE', ], 'default': 'K_EULER', }, @@ -67,7 +67,7 @@ class Lightning(SimpleService): name='Количество изображений', key='num_outputs', type=ModelParameter.TypeChoices.INTRANGE, - values={'start': 1, 'end': 4, 'step': 1, 'default': 1} + values={'start': 1, 'end': 4, 'step': 1, 'default': 1}, ), ModelParameter( name='Точность запроса', @@ -95,7 +95,7 @@ class Lightning(SimpleService): return price.quantize(Decimal('0.1'), rounding='ROUND_UP') def save_results( - self, prompt: str, images: list, time: timedelta, save: bool = True + self, prompt: str, images: list, time: timedelta, save: bool = True ) -> list[Message]: messages: list[Message] = [] for image in images: @@ -104,7 +104,7 @@ class Lightning(SimpleService): content_object=self.store, elapsed_time=time, content=prompt, - file=File(BytesIO(requests.get(image).content), '.png') + file=File(BytesIO(requests.get(image).content), '.png'), ) ) if save: @@ -1,32 +1,30 @@ import time - -import requests from datetime import timedelta from decimal import Decimal -from replicate.exceptions import ReplicateError, ModelError from io import BytesIO +import requests +from django.core.files import File + from messages.models import Message -from ml_model.exceptions.external_api import ExternalAPIException, InvalidDataException from ml_model.models import ModelCategory, ModelInput, ModelParameter from ml_model.services.base import SimpleService from ml_model.tasks import replicate_run -from django.core.files import File - class Logoai(SimpleService): """ Logo AI Service contains abstract method make, which makes a generation """ + title = 'Logo AI' description = 'Нейросеть, способная генерировать фотографии из вашего текста' category = ModelCategory(title='Изображения', slug='images') versions = [] inputs = [ ModelInput(type=ModelInput.TypeChoices.TEXT, required=True), - ModelInput(type=ModelInput.TypeChoices.IMAGE) + ModelInput(type=ModelInput.TypeChoices.IMAGE), ] parameters = [ ModelParameter( @@ -58,7 +56,7 @@ class Logoai(SimpleService): 'KarrasDPM', 'K_EULER_ANCESTRAL', 'K_EULER', - 'PNDM' + 'PNDM', ], 'default': 'K_EULER', }, @@ -95,7 +93,7 @@ class Logoai(SimpleService): return price.quantize(Decimal('0.1'), rounding='ROUND_UP') def save_results( - self, prompt: str, images: list, time: timedelta, save: bool = True + self, prompt: str, images: list, time: timedelta, save: bool = True ) -> list[Message]: messages: list[Message] = [] for image in images: @@ -104,7 +102,7 @@ class Logoai(SimpleService): content_object=self.store, elapsed_time=time, content=prompt, - file=File(BytesIO(requests.get(image).content), '.png') + file=File(BytesIO(requests.get(image).content), '.png'), ) ) if save: @@ -12,49 +12,49 @@ from ml_model.services.base import SimpleService from ml_model.tasks import replicate_run -class Openjourney(SimpleService): +class Midjourney(SimpleService): """ - Openjourney Service + Midjourney Service contains abstract method make, which makes a generation """ - title = 'OpenJourney' + title = 'Midjourney' description = 'Нейросеть, способная генерировать фотографии из вашего текста' - price = Decimal('1.518') + price = Decimal('2') category = ModelCategory(title='Изображения', slug='images') - versions = [] inputs = [ModelInput(type=ModelInput.TypeChoices.TEXT, required=True)] parameters = [ ModelParameter( - name='Количество изображений', - key='num_images', - type=ModelParameter.TypeChoices.INTRANGE, - values={'start': 1, 'end': 10, 'step': 1, 'default': 1}, + name='Соотношение сторон', + key='aspect_ratio', + type=ModelParameter.TypeChoices.LIST, + values={ + 'availables': ['1:1', '16:9', '4:3', '3:2', '2:3', '3:4', '9:16', '21:9'], + 'default': '1:1', + }, ), ModelParameter( - name='Количество шагов', - key='num_inference_steps', + name='Количество изображений', + key='number_of_images', type=ModelParameter.TypeChoices.INTRANGE, - values={'start': 0, 'end': 100, 'step': 1, 'default': 10}, + values={'start': 1, 'end': 9, 'step': 1, 'default': 1}, ), ModelParameter( - name='Негативный промпт', - key='negative_prompt', - type=ModelParameter.TypeChoices.STR, + name='Оптимизация промпта', + key='prompt_optimizer', + type=ModelParameter.TypeChoices.BOOL, + values={'default': True}, ), ] - _CALLBACK = ( - 'prompthero/openjourney' - ':ad59ca21177f9e217b9075e7300cf6e14f7e5b4505b87b9689dbd866e9768969' - ) + _CALLBACK = 'minimax/image-01' def __init__(self, store): super().__init__(store) - def calculate_price(self, process_time: timedelta) -> Decimal: - price = Decimal(process_time.total_seconds()) * self.price - return price.quantize(Decimal('0.1'), rounding='ROUND_UP') + def calculate_price(self, input_message: Message) -> Decimal: + price = input_message.info.get('number_of_images', 1) * self.price + return price.quantize(Decimal('0.1'), rounding='ROUND_UP') def save_results( self, input_prompt: str, r: list[str], t: timedelta, save: bool = True @@ -66,10 +66,7 @@ class Openjourney(SimpleService): content_object=self.store, elapsed_time=t, content=input_prompt, - file=File( - BytesIO(requests.get(link).content), - link.split('/')[-1], - ), + file=File(BytesIO(requests.get(link).content), '.png'), ) ) if save: @@ -81,10 +78,10 @@ class Openjourney(SimpleService): translated_prompt = self.translate_prompt(input_message.content) activation_prompt = f'mdjrny-v4 style a highly detailed {translated_prompt}' callback_data = dict(prompt=activation_prompt, **input_message.info) - if input_message.file: - callback_data.update({'image': BytesIO(input_message.file.read())}) results = replicate_run(self._CALLBACK, callback_data) process_time = timedelta(seconds=(time.time() - start_time)) - self.handle_invoice(input_message.content_object.model, process_time=process_time) + self.handle_invoice( + input_message.content_object.model, input_message=input_message + ) msgs = self.save_results(input_message.content, results, process_time, save) return msgs @@ -64,10 +64,7 @@ class Musicgen(SimpleService): Message( content_object=self.store, elapsed_time=t, - file=File( - BytesIO(requests.get(r).content), - r.split('/')[-1], - ), + file=File(BytesIO(requests.get(r).content), '.wav'), ) ] if save: @@ -1,31 +1,30 @@ import time - -import requests from datetime import timedelta from decimal import Decimal from io import BytesIO +import requests +from django.core.files import File + from messages.models import Message -from ml_model.exceptions.external_api import ExternalAPIException from ml_model.models import ModelCategory, ModelInput, ModelParameter from ml_model.services.base import SimpleService from ml_model.tasks import replicate_run -from django.core.files import File - class Pulid(SimpleService): """ PuLID Service contains abstract method make, which makes a generation """ + title = 'PuLID' description = 'Нейросеть, способная генерировать фотографии из вашего текста' category = ModelCategory(title='Изображения', slug='images') versions = [] inputs = [ ModelInput(type=ModelInput.TypeChoices.TEXT), - ModelInput(type=ModelInput.TypeChoices.IMAGE, required=True) + ModelInput(type=ModelInput.TypeChoices.IMAGE, required=True), ] parameters = [ ModelParameter( @@ -92,8 +91,7 @@ class Pulid(SimpleService): PRICE = Decimal('0.374') _CALLBACK = ( - 'zsxkib/pulid' - ':43d309c37ab4e62361e5e29b8e9e867fb2dcbcec77ae91206a8d95ac5dd451a0' + 'zsxkib/pulid:43d309c37ab4e62361e5e29b8e9e867fb2dcbcec77ae91206a8d95ac5dd451a0' ) def calculate_price(self, process_time: timedelta) -> Decimal: @@ -101,7 +99,7 @@ class Pulid(SimpleService): return price.quantize(Decimal('0.1'), rounding='ROUND_UP') def save_results( - self, prompt: str, images: list, time: timedelta, save: bool = True + self, prompt: str, images: list, time: timedelta, save: bool = True ) -> list[Message]: messages: list[Message] = [] for image in images: @@ -110,7 +108,7 @@ class Pulid(SimpleService): content_object=self.store, elapsed_time=time, content=prompt, - file=File(BytesIO(requests.get(image).content), '.png') + file=File(BytesIO(requests.get(image).content), '.png'), ) ) if save: @@ -134,7 +132,7 @@ class Pulid(SimpleService): 'or partially rendered eyes, deformed eyeballs, cross-eyed, blurry, udity, partial' 'nudity, suggestive poses, revealing clothing, explicit content, offensive symbols, ' 'provocative expressions, graphic violence, inappropriate themes' - f'{input_message.info.pop('negative_prompt', '')}' + f'{input_message.info.pop("negative_prompt", "")}' ), **input_message.info, } @@ -15,6 +15,7 @@ from ml_model.models import ( ModelVersion, ) from ml_model.services.base import SimpleService +from ml_model.tasks import replicate_run class Recraft(SimpleService): @@ -97,11 +98,6 @@ class Recraft(SimpleService): versions[1].slug: Decimal('44'), } - def __init__(self, store: BaseStore) -> None: - super().__init__(store) - self.generate_url = 'https://api.replicate.com/v1/models/recraft-ai/' - self.get_url = 'https://api.replicate.com/v1/predictions/' - def _get_size(self, width: int, height: int) -> str: available_sizes = ( (1024, 1024), (1365, 1024), (1024, 1365), (1536, 1024), (1024, 1536), @@ -114,26 +110,6 @@ class Recraft(SimpleService): size = min(available_sizes, key=lambda size: abs(height - size[1])) return f'{size[0]}x{size[1]}' - def _call_api(self, payload: dict) -> list: - headers = { - 'Authorization': f'Bearer {settings.REPLICATE_API_KEY}', - 'Content-Type': 'application/json', - 'Prefer': 'wait', - } - data = {'input': payload} - response = requests.post( - url=f'{self.generate_url}{payload.get('version', 'recraft-v3')}/predictions', - headers=headers, - json=data, - ) - if response.status_code != 201: - raise Exception(response.json()) - - result = requests.get(url=f'{self.get_url}{response.json().get('id')}', headers=headers) - while result.json()['status'] not in ('succeeded', 'failed', 'canceled'): - result = requests.get(url=f'{self.get_url}{response.json().get('id')}', headers=headers) - return result.json()['output'] - def calculate_price(self, input_message: Message) -> Decimal: return self.payment_rules[input_message.info.get('version', 'recraft-v3')] @@ -187,6 +163,7 @@ class Recraft(SimpleService): start_time = time.time() extension = '.svg' if input_message.info.get('version', 'recraft-v3') == self.versions[1].slug else '.png' size = self._get_size(input_message.info.pop('width', 1024), input_message.info.pop('height', 1024)) + callback_url = f'recraft-ai/{input_message.info.get('version', 'recraft-v3')}' callback_data = dict( { 'prompt': ( @@ -198,7 +175,7 @@ class Recraft(SimpleService): **input_message.info } ) - image = self._call_api(payload=callback_data) + image = replicate_run(callback_url, callback_data) process_time = timedelta(seconds=(time.time() - start_time)) self.handle_invoice(input_message.content_object.model, input_message) message = self.save_results(input_message.content, image, extension, process_time, save) @@ -1,31 +1,30 @@ import time - -import requests from datetime import timedelta from decimal import Decimal from io import BytesIO +import requests +from django.core.files import File + from messages.models import Message -from ml_model.exceptions.external_api import ExternalAPIException from ml_model.models import ModelCategory, ModelInput, ModelParameter from ml_model.services.base import SimpleService from ml_model.tasks import replicate_run -from django.core.files import File - class Sdxlemoji(SimpleService): """ Sdxl-emoji Service contains abstract method make, which makes a generation """ + title = 'Sdxl-emoji' description = 'Нейросеть, способная генерировать фотографии из вашего текста' category = ModelCategory(title='Изображения', slug='images') versions = [] inputs = [ ModelInput(type=ModelInput.TypeChoices.TEXT, required=True), - ModelInput(type=ModelInput.TypeChoices.IMAGE) + ModelInput(type=ModelInput.TypeChoices.IMAGE), ] parameters = [ ModelParameter( @@ -63,7 +62,7 @@ class Sdxlemoji(SimpleService): 'KarrasDPM', 'K_EULER_ANCESTRAL', 'K_EULER', - 'PNDM' + 'PNDM', ], 'default': 'K_EULER', }, @@ -85,8 +84,7 @@ class Sdxlemoji(SimpleService): PRICE = Decimal('0.529') _CALLBACK = ( - 'fofr/sdxl-emoji' - ':dee76b5afde21b0f01ed7925f0665b7e879c50ee718c5f78a9d38e04d523cc5e' + 'fofr/sdxl-emoji:dee76b5afde21b0f01ed7925f0665b7e879c50ee718c5f78a9d38e04d523cc5e' ) def calculate_price(self, process_time: timedelta) -> Decimal: @@ -94,7 +92,7 @@ class Sdxlemoji(SimpleService): return price.quantize(Decimal('0.1'), rounding='ROUND_UP') def save_results( - self, prompt: str, images: list, time: timedelta, save: bool = True + self, prompt: str, images: list, time: timedelta, save: bool = True ) -> list[Message]: messages: list[Message] = [] for image in images: @@ -103,7 +101,7 @@ class Sdxlemoji(SimpleService): content_object=self.store, elapsed_time=time, content=prompt, - file=File(BytesIO(requests.get(image).content), '.png') + file=File(BytesIO(requests.get(image).content), '.png'), ) ) if save: @@ -18,6 +18,7 @@ class Stablediffusion(SimpleService): Stablediffusion Service contains abstract method make, which makes a generation """ + title = 'StableDiffusion' description = 'Нейросеть, способная генерировать картинки из вашего текста' category = ModelCategory(title='Изображения', slug='images') @@ -105,13 +106,12 @@ class Stablediffusion(SimpleService): key='aspect_ratio', type=ModelParameter.TypeChoices.LIST, values={ - 'availables': - [ - '1:1', - '16:9', - '9:16', - ], - 'default': '1:1' + 'availables': [ + '1:1', + '16:9', + '9:16', + ], + 'default': '1:1', }, ), ModelParameter( @@ -119,18 +119,17 @@ class Stablediffusion(SimpleService): key='aspect_ratio', type=ModelParameter.TypeChoices.LIST, values={ - 'availables': - [ - '1:1', - '4:3', - '3:4', - '3:2', - '16:9', - '9:16', - '24:10', - '10:24' - ], - 'default': '1:1' + 'availables': [ + '1:1', + '4:3', + '3:4', + '3:2', + '16:9', + '9:16', + '24:10', + '10:24', + ], + 'default': '1:1', }, ), ] @@ -141,19 +140,21 @@ class Stablediffusion(SimpleService): def calculate_price(self, input_message: Message) -> Decimal: if ( - input_message.info.get('version') or input_message.info.get('engine', 'sd3') + input_message.info.get('version') + or input_message.info.get('engine', 'sd3-turbo') ) == 'sd3': - return Decimal('71.5') + return Decimal('13') elif ( - input_message.info.get('version') or input_message.info.get('engine', 'sd3') + input_message.info.get('version') + or input_message.info.get('engine', 'sd3-turbo') ) == 'sd3-turbo': - return Decimal('44') + return Decimal('8') steps = input_message.info.get('steps', 30) default_price = Decimal('0.9') * self.TOKEN_PRICE return default_price if steps <= 30 else default_price * Decimal((steps / 30)) def save_results( - self, input_prompt: str, r: list[BytesIO], t: timedelta, save: bool = True + self, input_prompt: str, r: list[BytesIO], t: timedelta, save: bool = True ) -> list[Message]: out: list[Message] = [] for obj in r: @@ -181,11 +182,11 @@ class Stablediffusion(SimpleService): '16:9': (1344, 768), '9:16': (768, 1344), '24:10': (1536, 640), - '10:24': (640, 1536) + '10:24': (640, 1536), } start_time = time.time() info = input_message.info.copy() - model_name = info.get('version') or info.get('engine', 'sd3') + model_name = info.get('version') or info.get('engine', 'sd3-turbo') formatter = { 'width': int( aspect_rations[input_message.info.get('aspect_ratio', '1:1')][0] @@ -205,7 +206,7 @@ class Stablediffusion(SimpleService): if model_name in ('sd3', 'sd3-turbo'): callback_data = dict( prompt=translated_prompt, - model=model_name, + model='sd3-large' if model_name == 'sd3' else 'sd3-large-turbo', aspect_ratio=input_message.info.get('aspect_ratio', '1:1'), output_format='jpeg', ) @@ -15,6 +15,7 @@ from ml_model.models import ( ModelParameter, ModelPaymentRule, ModelSettings, + ModelStat, ModelVersion, NeuronModel, ) @@ -50,7 +51,6 @@ class ModelInputsInline(admin.TabularInline): class ModelVersionsInline(OrderedTabularInline): model = ModelVersion - fk_name = 'model' extra = 0 classes = ['collapse'] fields = ('name', 'description', 'slug', 'default', 'order', 'move_up_down_links') @@ -58,6 +58,13 @@ class ModelVersionsInline(OrderedTabularInline): ordering = ('order',) +class ModelStatInline(admin.TabularInline): + model = ModelStat + verbose_name_plural = 'Статистика по модели' + extra = 0 + classes = ['collapse'] + + @admin.register(ModelCategory) class ModelCategoryAdmin(admin.ModelAdmin): list_display = ['title', 'slug'] @@ -76,6 +83,7 @@ class NeuronModelModelAdmin( ModelSettingsInline, ModelVersionsInline, ModelPaymentRulesInline, + ModelStatInline, ModelInputsInline, ModelParametersInline, ] @@ -0,0 +1,12 @@ +# накинуть перевод через gettext_lazy + + +class GenerationException(Exception): + def __str__(self): + return 'Случилась ошибка во время генерации у этой модели, пожалуйста повторите попытку позже' + + +class NSFWDetectedException(Exception): ... + + +class LargeResourceConsumptionException(Exception): ... @@ -74,6 +74,17 @@ class NeuronModel(BaseModel, OrderedModel): def payment_rules(self) -> QuerySet['ModelPaymentRule']: return self.model_modelpaymentrules.all() + @property + def stats(self) -> QuerySet['ModelStat']: + return self.model_modelstats.all() + + @property + def first_stat(self) -> 'ModelStat': + try: + return self.stats[0] + except IndexError: + return None + @property def settings(self) -> 'ModelSettings': try: @@ -174,6 +185,8 @@ class ModelInput(ModelDepends, ModelVersionsDepends): TEXT = 'text', _('Text') IMAGE = 'image', _('Image') PDF = 'pdf', _('PDF') + DOCX = 'docx', _('DOCX') + DOC = 'doc', _('DOC') TXT = 'txt', _('Text File (Notebook)') ZIPARCHIVE = 'zip', _('ZIP Archive') AUDIO = 'audio', _('Audio') @@ -290,6 +303,19 @@ class ModelPaymentRule(ModelDepends, ModelVersionsDepends): verbose_name_plural = _('Payment Rules') +class ModelStat(ModelDepends): + generation_time = models.DurationField(verbose_name='Время генерации') + tokens_cost = models.DecimalField( + max_digits=50, decimal_places=10, verbose_name='Цена в токенах' + ) + created_at = models.DateTimeField(auto_now_add=True, verbose_name='Когда создано') + + class Meta: + verbose_name = 'Статистика по модели' + verbose_name_plural = 'Статистики по моделям' + ordering = ('-created_at',) + + class ModelConfiguration(models.Model): id = models.UUIDField( primary_key=True, default=uuid4, editable=False, verbose_name='ID' @@ -18,13 +18,20 @@ from ml_model.serializers import ( class NeuronModelResource(ModelResource): category = ie_fields.Field( - column_name='category', + column_name='Категория', attribute='category', + readonly=True, widget=ForeignKeyWidget(ModelCategory, 'slug'), ) - versions = ie_fields.Field() - inputs = ie_fields.Field() - parameters = ie_fields.Field() + versions = ie_fields.Field( + column_name='Версии', + ) + inputs = ie_fields.Field( + column_name='Входящие потоки', + ) + parameters = ie_fields.Field( + column_name='Параметры', + ) def dehydrate_versions(self, obj: NeuronModel): return ModelVersionSerializer(obj.versions, many=True).data @@ -107,7 +107,7 @@ def transcript_audio(payload: dict[str, Any]): def replicate_run(callback_url: str, payload: dict[str, Any]): replicate_client = replicate.Client(settings.REPLICATE_API_KEY) return replicate_client.run( - model_version=callback_url, + ref=callback_url, input=payload, ) @@ -56,6 +56,8 @@ class NeuronModelAPIView(APIView): """Retrieve model by slug""" return Response( NeuronModelSerializer( - NeuronModelSelector(request.user).get_model_by_slug(slug=slug, hidden_parameter=False) + NeuronModelSelector(request.user).get_model_by_slug( + slug=slug, hidden=False + ) ).data ) @@ -0,0 +1,20 @@ +# Generated by Django 5.0.11 on 2025-03-17 07:46 + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('payments', '0014_auto_20241116_1547'), + ] + + operations = [ + migrations.AddField( + model_name='paymentplan', + name='points', + field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(), default=[], help_text='Перечислять через запятую', size=None, verbose_name='Поинты'), + preserve_default=False, + ), + ] @@ -0,0 +1,19 @@ +# Generated by Django 5.0.11 on 2025-03-17 08:04 + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('payments', '0015_paymentplan_points'), + ] + + operations = [ + migrations.AlterField( + model_name='paymentplan', + name='points', + field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(), blank=True, help_text='Перечислять через запятую', null=True, size=None, verbose_name='Поинты'), + ), + ] @@ -0,0 +1,19 @@ +# Generated by Django 5.0.11 on 2025-03-17 08:15 + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('payments', '0016_alter_paymentplan_points'), + ] + + operations = [ + migrations.AlterField( + model_name='paymentplan', + name='points', + field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(), blank=True, default=list, help_text='Перечислять через запятую', size=None, verbose_name='Поинты'), + ), + ] @@ -2,6 +2,7 @@ from datetime import datetime from dateutil.relativedelta import relativedelta from django.contrib.auth import get_user_model +from django.contrib.postgres.fields import ArrayField from django.db import models from django.utils.translation import gettext_lazy as _ from django_celery_beat.models import PeriodicTask @@ -33,13 +34,20 @@ class PaymentPlan(BaseModel): default=MONTH, ) is_visible = models.BooleanField(default=True, verbose_name=_('Is visible')) + points = ArrayField( + default=list, + blank=True, + base_field=models.CharField(), + verbose_name='Поинты', + help_text='Перечислять через запятую', + ) accessed_models = models.ManyToManyField( NeuronModel, verbose_name='Доступные модели', ) def __str__(self) -> str: - return f"{self.title or 'Ошибка'}" + return f'{self.title or "Ошибка"}' class Meta: ordering = ['price'] @@ -83,7 +91,7 @@ class PaymentPlanUserInfo(BaseModel): return super().save(force_insert, force_update, using, update_fields) def __str__(self) -> str: - return f"{self.user.email or 'Ошибка'}" + return f'{self.user.email or "Ошибка"}' class Meta: verbose_name = _('User Balance') @@ -236,7 +236,9 @@ class AccruedTokensFilter(admin.SimpleListFilter): ] def queryset(self, request, queryset): - queryset = queryset.annotate(total_bonuses=Sum('account_referral_accruals')) + queryset = queryset.annotate( + total_bonuses=Sum('account_referral_accruals__amount') + ) match self.value(): case 'more-zero': return queryset.filter(total_bonuses__gt=0) @@ -271,4 +273,4 @@ class ReferralAccountAdmin(admin.ModelAdmin): @admin.display(description='Получено бонусов') def _accrued_bonuses(self, obj: ReferralAccount): - return f'{obj.accrued_bonuses.aggregate(total=Coalesce(Sum('amount'), Decimal(0), output_field=models.DecimalField()))['total']} токенов' + return f'{obj.accrued_bonuses.aggregate(total=Coalesce(Sum("amount"), Decimal(0), output_field=models.DecimalField()))["total"]} токенов' @@ -12,6 +12,7 @@ class PaymentPlanSerializer(serializers.Serializer): price = serializers.DecimalField(max_digits=10, decimal_places=2) tokens_per_plan = serializers.DecimalField(max_digits=50, decimal_places=2) duration = serializers.CharField(read_only=True) + points = serializers.ListField(read_only=True) accessed_models = serializers.SlugRelatedField( slug_field='slug', queryset=NeuronModel.objects.all(), many=True ) @@ -142,10 +142,8 @@ class MessagesAPIView(APIView): except Exception as exc: input_message.is_sent = False input_message.save() - logger.info(f'Error occured: {exc}') - return Response( - f'Error occured: {exc}', status=400 - ) + logger.exception(exc) + return Response(f'Error occured: {exc}', status=400) output_messages.insert(0, input_message) return Response(MessageSerializer(output_messages, many=True).data, 201) else: @@ -35,6 +35,8 @@ class GalleryAPIView(APIView): required=True, enum=['images', 'videos', 'audios'], ), + OpenApiParameter('limit', int, required=False), + OpenApiParameter('offset', int, required=False), ], responses={200: MessageSerializer(many=True)}, ) @@ -43,11 +45,24 @@ class GalleryAPIView(APIView): List all messages by strategy: images, videos, or audios """ - galleries = self.manager.objects.filter(user=request.user) - out = [] - for gallery in galleries: - out += gallery.output_messages - return Response(MessageSerializer(out, many=True).data, 200) + messages_ids = ( + self.manager.objects.filter(user=request.user) + .prefetch_related('messages') + .values_list('messages', flat=True) + ) + + return Response( + MessageSerializer( + Message.objects.filter(uid__in=messages_ids, from_model=True)[ + int(request.query_params.get('offset', '0')) : int( + request.query_params.get('offset', '0') + ) + + int(request.query_params.get('limit', '10')) + ], + many=True, + ).data, + 200, + ) class MediaAPIView(APIView): @@ -54,8 +54,7 @@ class APIKeyService(BaseService): api_key.name = new_name if expires_at is not None: api_key.expires_at = expires_at - if token_limit is not None: - api_key.token_limit = token_limit + api_key.token_limit = token_limit api_key.save() if serialize: @@ -5,18 +5,19 @@ stages: - Deploy default: - image: docker:rc-cli + image: docker:cli + services: + - docker:dind before_script: - echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" $CI_REGISTRY --password-stdin build: stage: Build + image: docker:latest script: - touch .env && export ENV=.env - docker compose -f stack.yml build - docker compose -f stack.yml push - services: - - docker:dind only: - main - staging @@ -28,8 +29,6 @@ deploy_staging: DOCKER_HOST: tcp://$STAGING_CLUSTER_HOST:2376 DOCKER_TLS_VERIFY: 1 DOCKER_CERT_PATH: "/certs" - services: - - docker:dind environment: name: staging deployment_tier: staging @@ -53,8 +52,6 @@ deploy_production: DOCKER_HOST: tcp://$PRODUCTION_CLUSTER_HOST:2376 DOCKER_TLS_VERIFY: 1 DOCKER_CERT_PATH: "/certs" - services: - - docker:dind environment: name: production url: https://backend.air.fail @@ -22,7 +22,8 @@ RUN --mount=target=/var/lib/apt/lists,type=cache,sharing=locked \ --mount=target=/var/cache/apt,type=cache,sharing=locked \ rm -f /etc/apt/apt.conf.d/docker-clean \ && apt-get update \ - && apt-get -y --no-install-recommends install -y gettext + && apt-get -y --no-install-recommends install -y gettext \ + && apt-get -y install antiword RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt @@ -23,7 +23,8 @@ RUN --mount=target=/var/lib/apt/lists,type=cache,sharing=locked \ --mount=target=/var/cache/apt,type=cache,sharing=locked \ rm -f /etc/apt/apt.conf.d/docker-clean \ && apt-get update \ - && apt-get -y --no-install-recommends install gettext + && apt-get -y --no-install-recommends install gettext \ + && apt-get -y install antiword RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt @@ -1,26 +1,26 @@ .DEFAULT_GOAL=start start: - cp --update=none .env.dist .env + cp -n .env.dist .env docker compose -f docker-compose.debug.yml --project-name air up .PHONY=start rebuild: - cp --update=none .env.dist .env + cp -n .env.dist .env docker compose -f docker-compose.debug.yml --project-name air up --build .PHONY=rebuild stop: - cp --update=none .env.dist .env + cp -n .env.dist .env docker compose -f docker-compose.debug.yml --project-name air down --remove-orphans .PHONY=stop cleanup: - cp --update=none .env.dist .env + cp -n .env.dist .env docker compose -f docker-compose.debug.yml --project-name air down --remove-orphans -v .PHONY=cleanup full-cleanup: - cp --update=none .env.dist .env + cp -n .env.dist .env docker compose -f docker-compose.debug.yml --project-name air down --remove-orphans -v --rmi local .PHONY=full-cleanup \ No newline at end of file @@ -1,41 +1,65 @@ services: app: restart: unless-stopped + container_name: app + user: '1000' build: context: . dockerfile: Dockerfile.dev command: - /bin/sh - -c - - python manage.py initialize_buckets && - python manage.py collectstatic --no-input && python manage.py migrate && - (python manage.py createsuperuser --no-input || true) && - python -m uvicorn --host 0.0.0.0 --workers 1 --timeout-keep-alive 300 --ws wsproto --loop uvloop --http httptools --lifespan off backend.asgi:application --log-level debug --reload + - | + python manage.py initialize_buckets + python manage.py collectstatic --no-input + (python manage.py createsuperuser --no-input || true) + python -m debugpy --wait-for-client --listen 0.0.0.0:5678 -m uvicorn backend.asgi:application --host 0.0.0.0 --workers 1 --timeout-keep-alive 300 --ws wsproto --loop uvloop --http httptools --lifespan off --log-level debug --reload volumes: - .:/code ports: - "8000:8000" + - "5678:5678" env_file: - .env depends_on: - - cache-mdb - - s3 - - db + cache-mdb: + condition: service_started + s3: + condition: service_started + db: + condition: service_started + + migrator: + restart: on-failure:1 + container_name: migrator + build: + context: . + dockerfile: Dockerfile.dev + command: + - /bin/sh + - -c + - python manage.py migrate + env_file: + - .env cache-mdb: + container_name: cache-mdb image: redis:alpine restart: unless-stopped celery-mdb: + container_name: celery-mdb image: redis:alpine restart: unless-stopped channels-mdb: + container_name: channels-mdb image: redis:alpine restart: unless-stopped celery: restart: unless-stopped + container_name: celery build: context: . dockerfile: Dockerfile.dev @@ -51,6 +75,7 @@ services: celery_beat: restart: unless-stopped + container_name: celery-beat build: context: . dockerfile: Dockerfile.dev @@ -63,8 +88,8 @@ services: - celery-mdb db: restart: unless-stopped - image: postgres:alpine container_name: db + image: postgres:alpine volumes: - pgdata:/var/lib/postgresql/data env_file: @@ -74,6 +99,7 @@ services: s3: image: webcenter/alpine-minio + container_name: s3 restart: unless-stopped volumes: - s3data:/data @@ -1,5 +1,5 @@ services: - app: + backend: restart: unless-stopped image: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA build: @@ -15,12 +15,27 @@ services: python manage.py collectstatic --no-input python manage.py compilemessages python -m uvicorn --host 0.0.0.0 --workers 1 --timeout-keep-alive 300 --ws wsproto --loop uvloop --http httptools --lifespan off --log-level info backend.asgi:application - ports: - - "8000:8000" env_file: - $ENV depends_on: - - cache-mdb + migrator: + condition: service_completed_successfully + cache-mdb: + condition: service_started + + migrator: + restart: on-failure:1 + container_name: migrator + build: + context: . + dockerfile: Dockerfile + command: + - /bin/sh + - -c + - python manage.py migrate + env_file: + - $ENV + celery: restart: unless-stopped image: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA @@ -66,7 +81,8 @@ services: networks: default: - name: "air" + name: infrastructure + external: true volumes: static: @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" @@ -6,6 +6,7 @@ version = "2.4.4" description = "Happy Eyeballs for asyncio" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "aiohappyeyeballs-2.4.4-py3-none-any.whl", hash = "sha256:a980909d50efcd44795c4afeca523296716d50cd756ddca6af8c65b996e27de8"}, {file = "aiohappyeyeballs-2.4.4.tar.gz", hash = "sha256:5fdd7d87889c63183afc18ce9271f9b0a7d32c2303e394468dd45d514a757745"}, @@ -17,6 +18,7 @@ version = "3.11.11" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "aiohttp-3.11.11-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a60804bff28662cbcf340a4d61598891f12eea3a66af48ecfdc975ceec21e3c8"}, {file = "aiohttp-3.11.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b4fa1cb5f270fb3eab079536b764ad740bb749ce69a94d4ec30ceee1b5940d5"}, @@ -114,6 +116,7 @@ version = "1.3.2" description = "aiosignal: a list of registered asynchronous callbacks" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5"}, {file = "aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54"}, @@ -128,6 +131,7 @@ version = "5.3.1" description = "Low-level AMQP client for Python (fork of amqplib)." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "amqp-5.3.1-py3-none-any.whl", hash = "sha256:43b3319e1b4e7d1251833a93d672b4af1e40f3d632d479b98661a95f117880a2"}, {file = "amqp-5.3.1.tar.gz", hash = "sha256:cddc00c725449522023bad949f70fff7b48f0b1ade74d170a6f10ab044739432"}, @@ -142,6 +146,7 @@ version = "0.7.0" description = "Reusable constraint types to use with typing.Annotated" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, @@ -153,6 +158,7 @@ version = "4.8.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a"}, {file = "anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a"}, @@ -174,6 +180,7 @@ version = "23.1.0" description = "Argon2 for Python" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "argon2_cffi-23.1.0-py3-none-any.whl", hash = "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea"}, {file = "argon2_cffi-23.1.0.tar.gz", hash = "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08"}, @@ -194,6 +201,7 @@ version = "21.2.0" description = "Low-level CFFI bindings for Argon2" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3"}, {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367"}, @@ -231,6 +239,7 @@ version = "3.8.1" description = "ASGI specs, helper code, and adapters" optional = false python-versions = ">=3.8" +groups = ["main", "typing"] files = [ {file = "asgiref-3.8.1-py3-none-any.whl", hash = "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47"}, {file = "asgiref-3.8.1.tar.gz", hash = "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590"}, @@ -245,6 +254,7 @@ version = "24.3.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308"}, {file = "attrs-24.3.0.tar.gz", hash = "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff"}, @@ -264,6 +274,7 @@ version = "24.4.2" description = "WebSocket client & server library, WAMP real-time framework" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "autobahn-24.4.2-py2.py3-none-any.whl", hash = "sha256:c56a2abe7ac78abbfb778c02892d673a4de58fd004d088cd7ab297db25918e81"}, {file = "autobahn-24.4.2.tar.gz", hash = "sha256:a2d71ef1b0cf780b6d11f8b205fd2c7749765e65795f2ea7d823796642ee92c9"}, @@ -293,6 +304,7 @@ version = "24.8.1" description = "Self-service finite-state machines for the programmer on the go." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "Automat-24.8.1-py3-none-any.whl", hash = "sha256:bf029a7bc3da1e2c24da2343e7598affaa9f10bf0ab63ff808566ce90551e02a"}, {file = "automat-24.8.1.tar.gz", hash = "sha256:b34227cf63f6325b8ad2399ede780675083e439b20c323d376373d8ee6306d88"}, @@ -307,6 +319,7 @@ version = "4.2.1" description = "Python multiprocessing fork with improvements and bugfixes" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "billiard-4.2.1-py3-none-any.whl", hash = "sha256:40b59a4ac8806ba2c2369ea98d876bc6108b051c227baffd928c644d15d8f3cb"}, {file = "billiard-4.2.1.tar.gz", hash = "sha256:12b641b0c539073fc8d3f5b8b7be998956665c4233c7c1fcd66a7e677c4fb36f"}, @@ -318,6 +331,7 @@ version = "5.5.0" description = "Extensible memoizing collections and decorators" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "cachetools-5.5.0-py3-none-any.whl", hash = "sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292"}, {file = "cachetools-5.5.0.tar.gz", hash = "sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a"}, @@ -329,6 +343,7 @@ version = "5.4.0" description = "Distributed Task Queue." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "celery-5.4.0-py3-none-any.whl", hash = "sha256:369631eb580cf8c51a82721ec538684994f8277637edde2dfc0dacd73ed97f64"}, {file = "celery-5.4.0.tar.gz", hash = "sha256:504a19140e8d3029d5acad88330c541d4c3f64c789d85f94756762d8bca7e706"}, @@ -386,6 +401,7 @@ version = "0.1.3" description = "celery stubs" optional = false python-versions = "*" +groups = ["typing"] files = [ {file = "celery-stubs-0.1.3.tar.gz", hash = "sha256:0fb5345820f8a2bd14e6ffcbef2d10181e12e40f8369f551d7acc99d8d514919"}, {file = "celery_stubs-0.1.3-py3-none-any.whl", hash = "sha256:dfb9ad27614a8af028b2055bb4a4ae99ca5e9a8d871428a506646d62153218d7"}, @@ -401,6 +417,7 @@ version = "2024.12.14" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" +groups = ["main", "typing"] files = [ {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"}, {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, @@ -412,6 +429,7 @@ version = "1.17.1" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, @@ -491,6 +509,7 @@ version = "4.2.0" description = "Brings async, event-driven capabilities to Django." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "channels-4.2.0-py3-none-any.whl", hash = "sha256:6b75bc8d6888fb7236e7e7bf1948520b72d296ad08216a242fc56b1db0ffde1a"}, {file = "channels-4.2.0.tar.gz", hash = "sha256:d9e707487431ba5dbce9af982970dab3b0efd786580fadb99e45dca5e39fdd59"}, @@ -511,6 +530,7 @@ version = "4.2.1" description = "Redis-backed ASGI channel layer implementation" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "channels_redis-4.2.1-py3-none-any.whl", hash = "sha256:2ca33105b3a04b5a327a9c47dd762b546f30b76a0cd3f3f593a23d91d346b6f4"}, {file = "channels_redis-4.2.1.tar.gz", hash = "sha256:8375e81493e684792efe6e6eca60ef3d7782ef76c6664057d2e5c31e80d636dd"}, @@ -532,6 +552,7 @@ version = "3.4.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" +groups = ["main", "typing"] files = [ {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, @@ -633,6 +654,7 @@ version = "8.1.8" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, @@ -647,6 +669,7 @@ version = "0.3.1" description = "Enables git-like *did-you-mean* feature in click" optional = false python-versions = ">=3.6.2" +groups = ["main"] files = [ {file = "click_didyoumean-0.3.1-py3-none-any.whl", hash = "sha256:5c4bb6007cfea5f2fd6583a2fb6701a22a41eb98957e63d0fac41c10e7c3117c"}, {file = "click_didyoumean-0.3.1.tar.gz", hash = "sha256:4f82fdff0dbe64ef8ab2279bd6aa3f6a99c3b28c05aa09cbfc07c9d7fbb5a463"}, @@ -661,6 +684,7 @@ version = "1.1.1" description = "An extension module for click to enable registering CLI commands via setuptools entry-points." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "click-plugins-1.1.1.tar.gz", hash = "sha256:46ab999744a9d831159c3411bb0c79346d94a444df9a3a3742e9ed63645f264b"}, {file = "click_plugins-1.1.1-py2.py3-none-any.whl", hash = "sha256:5d262006d3222f5057fd81e1623d4443e41dcda5dc815c06b442aa3c02889fc8"}, @@ -678,6 +702,7 @@ version = "0.3.0" description = "REPL plugin for Click" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "click-repl-0.3.0.tar.gz", hash = "sha256:17849c23dba3d667247dc4defe1757fff98694e90fe37474f3feebb69ced26a9"}, {file = "click_repl-0.3.0-py3-none-any.whl", hash = "sha256:fb7e06deb8da8de86180a33a9da97ac316751c094c6899382da7feeeeb51b812"}, @@ -696,10 +721,12 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main", "test"] files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +markers = {main = "platform_system == \"Windows\"", test = "sys_platform == \"win32\""} [[package]] name = "constantly" @@ -707,6 +734,7 @@ version = "23.10.4" description = "Symbolic constants in Python" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "constantly-23.10.4-py3-none-any.whl", hash = "sha256:3fd9b4d1c3dc1ec9757f3c52aef7e53ad9323dbe39f51dfd4c43853b68dfa3f9"}, {file = "constantly-23.10.4.tar.gz", hash = "sha256:aa92b70a33e2ac0bb33cd745eb61776594dc48764b06c35e0efd050b7f1c7cbd"}, @@ -718,6 +746,7 @@ version = "7.6.10" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" +groups = ["test"] files = [ {file = "coverage-7.6.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5c912978f7fbf47ef99cec50c4401340436d200d41d714c7a4766f377c5b7b78"}, {file = "coverage-7.6.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a01ec4af7dfeb96ff0078ad9a48810bb0cc8abcb0115180c6013a6b26237626c"}, @@ -792,6 +821,7 @@ version = "1.4.5" description = "A Python library that converts cron expressions into human readable strings." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "cron_descriptor-1.4.5-py3-none-any.whl", hash = "sha256:736b3ae9d1a99bc3dbfc5b55b5e6e7c12031e7ba5de716625772f8b02dcd6013"}, {file = "cron_descriptor-1.4.5.tar.gz", hash = "sha256:f51ce4ffc1d1f2816939add8524f206c376a42c87a5fca3091ce26725b3b1bca"}, @@ -806,6 +836,7 @@ version = "44.0.0" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = "!=3.9.0,!=3.9.1,>=3.7" +groups = ["main"] files = [ {file = "cryptography-44.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123"}, {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092"}, @@ -855,6 +886,7 @@ version = "4.1.2" description = "Django ASGI (HTTP/WebSocket) server" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "daphne-4.1.2-py3-none-any.whl", hash = "sha256:618d1322bb4d875342b99dd2a10da2d9aae7ee3645f765965fdc1e658ea5290a"}, {file = "daphne-4.1.2.tar.gz", hash = "sha256:fcbcace38eb86624ae247c7ffdc8ac12f155d7d19eafac4247381896d6f33761"}, @@ -874,6 +906,7 @@ version = "0.6.7" description = "Easily serialize dataclasses to and from JSON." optional = false python-versions = "<4.0,>=3.7" +groups = ["main"] files = [ {file = "dataclasses_json-0.6.7-py3-none-any.whl", hash = "sha256:0dbf33f26c8d5305befd61b39d2b3414e8a407bedc2834dea9b8d642666fb40a"}, {file = "dataclasses_json-0.6.7.tar.gz", hash = "sha256:b6b3e528266ea45b9535223bc53ca645f5208833c29229e847b3f26a1cc55fc0"}, @@ -889,6 +922,7 @@ version = "1.8.11" description = "An implementation of the Debug Adapter Protocol for Python" optional = false python-versions = ">=3.8" +groups = ["debug"] files = [ {file = "debugpy-1.8.11-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:2b26fefc4e31ff85593d68b9022e35e8925714a10ab4858fb1b577a8a48cb8cd"}, {file = "debugpy-1.8.11-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61bc8b3b265e6949855300e84dc93d02d7a3a637f2aec6d382afd4ceb9120c9f"}, @@ -924,6 +958,7 @@ version = "1.21.0" description = "Python library for the DeepL API." optional = false python-versions = "<4,>=3.6.2" +groups = ["main"] files = [ {file = "deepl-1.21.0-py3-none-any.whl", hash = "sha256:f9cb882b2cee4b0a28bc648e5af27f357e5e8ad5dad1d4a40cb23c754c2be628"}, {file = "deepl-1.21.0.tar.gz", hash = "sha256:fae768ba0cafbfcc7de3fcec58e2eafd45d0c917df9385f9bde2126968c35a9e"}, @@ -941,6 +976,7 @@ version = "0.7.1" description = "XML bomb protection for Python stdlib modules" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["main"] files = [ {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, @@ -952,6 +988,7 @@ version = "1.2.15" description = "Python @deprecated decorator to deprecate old python classes, functions or methods." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +groups = ["main"] files = [ {file = "Deprecated-1.2.15-py2.py3-none-any.whl", hash = "sha256:353bc4a8ac4bfc96800ddab349d89c25dec1079f65fd53acdcc1e0b975b21320"}, {file = "deprecated-1.2.15.tar.gz", hash = "sha256:683e561a90de76239796e6b6feac66b99030d2dd3fcf61ef996330f14bbb9b0d"}, @@ -969,6 +1006,7 @@ version = "20241021" description = "Repackaging of Google's Diff Match and Patch libraries." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "diff_match_patch-20241021-py3-none-any.whl", hash = "sha256:93cea333fb8b2bc0d181b0de5e16df50dd344ce64828226bda07728818936782"}, {file = "diff_match_patch-20241021.tar.gz", hash = "sha256:beae57a99fa48084532935ee2968b8661db861862ec82c6f21f4acdd6d835073"}, @@ -983,6 +1021,7 @@ version = "1.9.0" description = "Distro - an OS platform information API" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2"}, {file = "distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed"}, @@ -994,6 +1033,7 @@ version = "4.0.1" description = "Authentication and Registration in Django Rest Framework" optional = false python-versions = ">=3.5" +groups = ["main"] files = [ {file = "dj-rest-auth-4.0.1.tar.gz", hash = "sha256:ec87f934c83b520217399f4793506e36cccccc84e899623510ee9c7289f80573"}, ] @@ -1011,6 +1051,7 @@ version = "5.0.11" description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." optional = false python-versions = ">=3.10" +groups = ["main", "typing"] files = [ {file = "Django-5.0.11-py3-none-any.whl", hash = "sha256:09e8128f717266bf382d82ffa4933f13da05d82579abf008ede86acb15dec88b"}, {file = "Django-5.0.11.tar.gz", hash = "sha256:e7d98fa05ce09cb3e8d5ad6472fb602322acd1740bfdadc29c8404182d664f65"}, @@ -1031,6 +1072,7 @@ version = "7.1" description = "A slick ORM cache with automatic granular event-driven invalidation for Django." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "django_cacheops-7.1-py2.py3-none-any.whl", hash = "sha256:7d5e0f42e41ab4a8052130d33d9f3b26c47bef944ef2df0a64db92d70e51d87e"}, {file = "django_cacheops-7.1.tar.gz", hash = "sha256:ec079abb968557321ee208c6274820231820f98ca6377dda971f04981bc2ab52"}, @@ -1047,6 +1089,7 @@ version = "2.7.0" description = "Database-backed Periodic Tasks." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "django_celery_beat-2.7.0-py3-none-any.whl", hash = "sha256:851c680d8fbf608ca5fecd5836622beea89fa017bc2b3f94a5b8c648c32d84b1"}, {file = "django_celery_beat-2.7.0.tar.gz", hash = "sha256:8482034925e09b698c05ad61c36ed2a8dbc436724a3fe119215193a4ca6dc967"}, @@ -1066,6 +1109,7 @@ version = "4.6.0" description = "django-cors-headers is a Django application for handling the server headers required for Cross-Origin Resource Sharing (CORS)." optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "django_cors_headers-4.6.0-py3-none-any.whl", hash = "sha256:8edbc0497e611c24d5150e0055d3b178c6534b8ed826fb6f53b21c63f5d48ba3"}, {file = "django_cors_headers-4.6.0.tar.gz", hash = "sha256:14d76b4b4c8d39375baeddd89e4f08899051eeaf177cb02a29bd6eae8cf63aa8"}, @@ -1081,6 +1125,7 @@ version = "23.5" description = "Django-filter is a reusable Django application for allowing users to filter querysets dynamically." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "django-filter-23.5.tar.gz", hash = "sha256:67583aa43b91fe8c49f74a832d95f4d8442be628fd4c6d65e9f811f5153a4e5c"}, {file = "django_filter-23.5-py3-none-any.whl", hash = "sha256:99122a201d83860aef4fe77758b69dda913e874cc5e0eaa50a86b0b18d708400"}, @@ -1095,6 +1140,7 @@ version = "4.3.4" description = "Django application and library for importing and exporting data with included admin integration." optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "django_import_export-4.3.4-py3-none-any.whl", hash = "sha256:9b56e847ddcb22c0bfbb508bc3668f8b33f95d888002e931c4039d0466270230"}, {file = "django_import_export-4.3.4.tar.gz", hash = "sha256:9ba43ced4fefae614ee7e30da8fdb55d6fcf0450489e7d290299672e0830a436"}, @@ -1122,6 +1168,7 @@ version = "3.8.0" description = "The django-minio-backend provides a wrapper around the MinIO Python Library." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "django_minio_backend-3.8.0-py3-none-any.whl", hash = "sha256:1e5aa883d1df2694843ab79c9646af3a5d79aa1712732128e0d84e441d8d5057"}, {file = "django_minio_backend-3.8.0.tar.gz", hash = "sha256:67425eed262d64425beb25183980dac1abf7285af8f68c444a2f820cf0b120d7"}, @@ -1137,6 +1184,7 @@ version = "1.3.0" description = "Django Ninja - Fast Django REST framework" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "django_ninja-1.3.0-py3-none-any.whl", hash = "sha256:f58096b6c767d1403dfd6c49743f82d780d7b9688d9302ecab316ac1fa6131bb"}, {file = "django_ninja-1.3.0.tar.gz", hash = "sha256:5b320e2dc0f41a6032bfa7e1ebc33559ae1e911a426f0c6be6674a50b20819be"}, @@ -1157,6 +1205,7 @@ version = "2.4.0" description = "OAuth2 Provider for Django" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "django_oauth_toolkit-2.4.0-py3-none-any.whl", hash = "sha256:4931d6bf64b6aee32a42f989f218769d1876f3daa53c6bf883d8ab793fb302ee"}, {file = "django_oauth_toolkit-2.4.0.tar.gz", hash = "sha256:8975eaf697413a8d54208ee068bc5ad6d1ed76f1df84e4882fbb25e7e6966e1b"}, @@ -1175,6 +1224,7 @@ version = "3.7.4" description = "Allows Django models to be ordered and provides a simple admin interface for reordering them." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "django-ordered-model-3.7.4.tar.gz", hash = "sha256:f258b9762525c00a53009e82f8b8bf2a3aa315e8b453e281e8fdbbfe2b8cb3ba"}, {file = "django_ordered_model-3.7.4-py3-none-any.whl", hash = "sha256:dfcd3183fe0749dad1c9971cba1d6240ce7328742a30ddc92feca41107bb241d"}, @@ -1186,6 +1236,7 @@ version = "3.1.0" description = "Seamless polymorphic inheritance for Django models" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "django-polymorphic-3.1.0.tar.gz", hash = "sha256:d6955b5308bf6e41dcb22ba7c96f00b51dfa497a8a5ab1e9c06c7951bf417bf8"}, {file = "django_polymorphic-3.1.0-py3-none-any.whl", hash = "sha256:08bc4f4f4a773a19b2deced5a56deddd1ef56ebd15207bf4052e2901c25ef57e"}, @@ -1200,6 +1251,7 @@ version = "2.3.1" description = "Django middlewares to monitor your application with Prometheus.io." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "django-prometheus-2.3.1.tar.gz", hash = "sha256:f9c8b6c780c9419ea01043c63a437d79db2c33353451347894408184ad9c3e1e"}, {file = "django_prometheus-2.3.1-py2.py3-none-any.whl", hash = "sha256:cf9b26f7ba2e4568f08f8f91480a2882023f5908579681bcf06a4d2465f12168"}, @@ -1214,6 +1266,7 @@ version = "5.4.0" description = "Full featured redis cache backend for Django." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "django-redis-5.4.0.tar.gz", hash = "sha256:6a02abaa34b0fea8bf9b707d2c363ab6adc7409950b2db93602e6cb292818c42"}, {file = "django_redis-5.4.0-py3-none-any.whl", hash = "sha256:ebc88df7da810732e2af9987f7f426c96204bf89319df4c6da6ca9a2942edd5b"}, @@ -1232,6 +1285,7 @@ version = "4.2.7" description = "Mypy stubs for Django" optional = false python-versions = ">=3.8" +groups = ["typing"] files = [ {file = "django-stubs-4.2.7.tar.gz", hash = "sha256:8ccd2ff4ee5adf22b9e3b7b1a516d2e1c2191e9d94e672c35cc2bc3dd61e0f6b"}, {file = "django_stubs-4.2.7-py3-none-any.whl", hash = "sha256:4cf4de258fa71adc6f2799e983091b9d46cfc67c6eebc68fe111218c9a62b3b8"}, @@ -1253,6 +1307,7 @@ version = "5.1.2" description = "Monkey-patching and extensions for django-stubs" optional = false python-versions = ">=3.8" +groups = ["typing"] files = [ {file = "django_stubs_ext-5.1.2-py3-none-any.whl", hash = "sha256:6c559214538d6a26f631ca638ddc3251a0a891d607de8ce01d23d3201ad8ad6c"}, {file = "django_stubs_ext-5.1.2.tar.gz", hash = "sha256:421c0c3025a68e3ab8e16f065fad9ba93335ecefe2dd92a0cff97a665680266c"}, @@ -1268,6 +1323,7 @@ version = "7.1" description = "A Django app providing DB, form, and REST framework fields for zoneinfo and pytz timezone objects." optional = false python-versions = "<4.0,>=3.8" +groups = ["main"] files = [ {file = "django_timezone_field-7.1-py3-none-any.whl", hash = "sha256:93914713ed882f5bccda080eda388f7006349f25930b6122e9b07bf8db49c4b4"}, {file = "django_timezone_field-7.1.tar.gz", hash = "sha256:b3ef409d88a2718b566fabe10ea996f2838bc72b22d3a2900c0aa905c761380c"}, @@ -1282,6 +1338,7 @@ version = "3.15.2" description = "Web APIs for Django, made easy." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "djangorestframework-3.15.2-py3-none-any.whl", hash = "sha256:2b8871b062ba1aefc2de01f773875441a961fefbf79f5eed1e32b2f096944b20"}, {file = "djangorestframework-3.15.2.tar.gz", hash = "sha256:36fe88cd2d6c6bec23dca9804bab2ba5517a8bb9d8f47ebc68981b56840107ad"}, @@ -1296,6 +1353,7 @@ version = "5.4.0" description = "A minimal JSON Web Token authentication plugin for Django REST Framework" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "djangorestframework_simplejwt-5.4.0-py3-none-any.whl", hash = "sha256:7aec953db9ed4163430c16d086eecb0f028f814ce6bba62b06c25919261e9077"}, {file = "djangorestframework_simplejwt-5.4.0.tar.gz", hash = "sha256:cccecce1a0e1a4a240fae80da73e5fc23055bababb8b67de88fa47cd36822320"}, @@ -1320,6 +1378,7 @@ version = "3.14.5" description = "PEP-484 stubs for django-rest-framework" optional = false python-versions = ">=3.8" +groups = ["typing"] files = [ {file = "djangorestframework-stubs-3.14.5.tar.gz", hash = "sha256:5dd6f638aa5291fb7863e6166128a6ed20bf4986e2fc5cf334e6afc841797a09"}, {file = "djangorestframework_stubs-3.14.5-py3-none-any.whl", hash = "sha256:43d788fd50cda49b922cd411e59c5b8cdc3f3de49c02febae12ce42139f0269b"}, @@ -1337,12 +1396,24 @@ compatible-mypy = ["django-stubs[compatible-mypy]", "mypy (>=1.7.0,<1.8.0)"] coreapi = ["coreapi (>=2.0.0)"] markdown = ["types-Markdown (>=0.1.5)"] +[[package]] +name = "docx2txt" +version = "0.8" +description = "A pure python-based utility to extract text and images from docx files." +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "docx2txt-0.8.tar.gz", hash = "sha256:2c06d98d7cfe2d3947e5760a57d924e3ff07745b379c8737723922e7009236e5"}, +] + [[package]] name = "drf-social-oauth2" version = "2.1.0" description = "drf-social-oauth2 is a frameworks meant to be used with Django and Django Rest Framework." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "drf-social-oauth2-2.1.0.tar.gz", hash = "sha256:6ef656dbca4944ba1ad40299ecaa36532f9dab71ba8a10a2f03b1c7301d4f067"}, {file = "drf_social_oauth2-2.1.0-py3-none-any.whl", hash = "sha256:51293ae18496642fb3abf932db847dd1098dbfc8a606af6f3fcfb8d73940de36"}, @@ -1360,6 +1431,7 @@ version = "0.27.2" description = "Sane and flexible OpenAPI 3 schema generation for Django REST framework" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "drf-spectacular-0.27.2.tar.gz", hash = "sha256:a199492f2163c4101055075ebdbb037d59c6e0030692fc83a1a8c0fc65929981"}, {file = "drf_spectacular-0.27.2-py3-none-any.whl", hash = "sha256:b1c04bf8b2fbbeaf6f59414b4ea448c8787aba4d32f76055c3b13335cf7ec37b"}, @@ -1384,6 +1456,7 @@ version = "2024.12.1" description = "Serve self-contained distribution builds of Swagger UI and Redoc with Django" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "drf_spectacular_sidecar-2024.12.1-py3-none-any.whl", hash = "sha256:e30821d150d29294f3be2018aab31b55cd724158e9e690b51a215264751aa8c7"}, {file = "drf_spectacular_sidecar-2024.12.1.tar.gz", hash = "sha256:6be31df38bcf95681224b6550faa9344ee6dd5360dcf2b44afcc3f7460385613"}, @@ -1398,6 +1471,7 @@ version = "0.19.0" description = "ECDSA cryptographic signature library (pure python)" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.6" +groups = ["main"] files = [ {file = "ecdsa-0.19.0-py2.py3-none-any.whl", hash = "sha256:2cea9b88407fdac7bbeca0833b189e4c9c53f2ef1e1eaa29f6224dbc809b707a"}, {file = "ecdsa-0.19.0.tar.gz", hash = "sha256:60eaad1199659900dd0af521ed462b793bbdf867432b3948e87416ae4caf6bf8"}, @@ -1416,6 +1490,7 @@ version = "9.5.0" description = "simplified environment variable parsing" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "environs-9.5.0-py2.py3-none-any.whl", hash = "sha256:1e549569a3de49c05f856f40bce86979e7d5ffbbc4398e7f338574c220189124"}, {file = "environs-9.5.0.tar.gz", hash = "sha256:a76307b36fbe856bdca7ee9161e6c466fd7fcffc297109a118c59b54e27e30c9"}, @@ -1437,6 +1512,7 @@ version = "2.0.0" description = "An implementation of lxml.xmlfile for the standard library" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa"}, {file = "et_xmlfile-2.0.0.tar.gz", hash = "sha256:dab3f4764309081ce75662649be815c4c9081e88f0837825f90fd28317d4da54"}, @@ -1448,6 +1524,7 @@ version = "3.3.1" description = "A versatile test fixtures replacement based on thoughtbot's factory_bot for Ruby." optional = false python-versions = ">=3.8" +groups = ["test"] files = [ {file = "factory_boy-3.3.1-py2.py3-none-any.whl", hash = "sha256:7b1113c49736e1e9995bc2a18f4dbf2c52cf0f841103517010b1d825712ce3ca"}, {file = "factory_boy-3.3.1.tar.gz", hash = "sha256:8317aa5289cdfc45f9cae570feb07a6177316c82e34d14df3c2e1f22f26abef0"}, @@ -1460,12 +1537,53 @@ Faker = ">=0.7.0" dev = ["Django", "Pillow", "SQLAlchemy", "coverage", "flake8", "isort", "mongoengine", "mongomock", "mypy", "tox", "wheel (>=0.32.0)", "zest.releaser[recommended]"] doc = ["Sphinx", "sphinx-rtd-theme", "sphinxcontrib-spelling"] +[[package]] +name = "faiss-cpu" +version = "1.10.0" +description = "A library for efficient similarity search and clustering of dense vectors." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "faiss_cpu-1.10.0-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:6693474be296a7142ade1051ea18e7d85cedbfdee4b7eac9c52f83fed0467855"}, + {file = "faiss_cpu-1.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:70ebe60a560414dc8dd6cfe8fed105c8f002c0d11f765f5adfe8d63d42c0467f"}, + {file = "faiss_cpu-1.10.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:74c5712d4890f15c661ab7b1b75867812e9596e1469759956fad900999bedbb5"}, + {file = "faiss_cpu-1.10.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:473d158fbd638d6ad5fb64469ba79a9f09d3494b5f4e8dfb4f40ce2fc335dca4"}, + {file = "faiss_cpu-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:dcd0cb2ec84698cbe3df9ed247d2392f09bda041ad34b92d38fa916cd019ad4b"}, + {file = "faiss_cpu-1.10.0-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:8ff6924b0f00df278afe70940ae86302066466580724c2f3238860039e9946f1"}, + {file = "faiss_cpu-1.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cb80b530a9ded44a7d4031a7355a237aaa0ff1f150c1176df050e0254ea5f6f6"}, + {file = "faiss_cpu-1.10.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:7a9fef4039ed877d40e41d5563417b154c7f8cd57621487dad13c4eb4f32515f"}, + {file = "faiss_cpu-1.10.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:49b6647aa9e159a2c4603cbff2e1b313becd98ad6e851737ab325c74fe8e0278"}, + {file = "faiss_cpu-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:6f8c0ef8b615c12c7bf612bd1fc51cffa49c1ddaa6207c6981f01ab6782e6b3b"}, + {file = "faiss_cpu-1.10.0-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:2aca486fe2d680ea64a18d356206c91ff85db99fd34c19a757298c67c23262b1"}, + {file = "faiss_cpu-1.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c1108a4059c66c37c403183e566ca1ed0974a6af7557c92d49207639aab661bc"}, + {file = "faiss_cpu-1.10.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:449f3eb778d6d937e01a16a3170de4bb8aabfe87c7cb479b458fb790276310c5"}, + {file = "faiss_cpu-1.10.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9899c340f92bd94071d6faf4bef0ccb5362843daea42144d4ba857a2a1f67511"}, + {file = "faiss_cpu-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:345a52dbfa980d24b93c94410eadf82d1eef359c6a42e5e0768cca96539f1c3c"}, + {file = "faiss_cpu-1.10.0-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:cb8473d69c3964c1bf3f8eb3e04287bb3275f536e6d9635ef32242b5f506b45d"}, + {file = "faiss_cpu-1.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82ca5098de694e7b8495c1a8770e2c08df6e834922546dad0ae1284ff519ced6"}, + {file = "faiss_cpu-1.10.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:035e4d797e2db7fc0d0c90531d4a655d089ad5d1382b7a49358c1f2307b3a309"}, + {file = "faiss_cpu-1.10.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e02af3696a6b9e1f9072e502f48095a305de2163c42ceb1f6f6b1db9e7ffe574"}, + {file = "faiss_cpu-1.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:e71f7e24d5b02d3a51df47b77bd10f394a1b48a8331d5c817e71e9e27a8a75ac"}, + {file = "faiss_cpu-1.10.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:3118b5d7680b0e0a3cd64b3d29389d8384de4298739504fc661b658109540b4b"}, + {file = "faiss_cpu-1.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f71c5860c860df2320299f9e4f2ca1725beb559c04acb1cf961ed24e6218277a"}, + {file = "faiss_cpu-1.10.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:2f15b7957d474391fc63f02bfb8011b95317a580e4d9bd70c276f4bc179a17b3"}, + {file = "faiss_cpu-1.10.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:dadbbb834ddc34ca7e21411811833cebaae4c5a86198dd7c2a349dbe4e7e0398"}, + {file = "faiss_cpu-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:cb77a6a5f304890c23ffb4c566bc819c0e0cf34370b20ddff02477f2bbbaf7a3"}, + {file = "faiss_cpu-1.10.0.tar.gz", hash = "sha256:5bdca555f24bc036f4d67f8a5a4d6cc91b8d2126d4e78de496ca23ccd46e479d"}, +] + +[package.dependencies] +numpy = ">=1.25.0,<3.0" +packaging = "*" + [[package]] name = "faker" version = "33.3.1" description = "Faker is a Python package that generates fake data for you." optional = false python-versions = ">=3.8" +groups = ["test"] files = [ {file = "Faker-33.3.1-py3-none-any.whl", hash = "sha256:ac4cf2f967ce02c898efa50651c43180bd658a7707cfd676fcc5410ad1482c03"}, {file = "faker-33.3.1.tar.gz", hash = "sha256:49dde3b06a5602177bc2ad013149b6f60a290b7154539180d37b6f876ae79b20"}, @@ -1481,6 +1599,7 @@ version = "0.3.0" description = "A fast native implementation of diff algorithm with a pure python fallback" optional = false python-versions = "*" +groups = ["test"] files = [ {file = "fastdiff-0.3.0-py2.py3-none-any.whl", hash = "sha256:ca5f61f6ddf5a1564ddfd98132ad28e7abe4a88a638a8b014a2214f71e5918ec"}, {file = "fastdiff-0.3.0.tar.gz", hash = "sha256:4dfa09c47832a8c040acda3f1f55fc0ab4d666f0e14e6951e6da78d59acd945a"}, @@ -1496,6 +1615,7 @@ version = "1.2.0" description = "Infer file type and MIME type of any file/buffer. No external dependencies." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "filetype-1.2.0-py2.py3-none-any.whl", hash = "sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25"}, {file = "filetype-1.2.0.tar.gz", hash = "sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb"}, @@ -1507,6 +1627,7 @@ version = "1.5.1" description = "Let your Python tests travel through time" optional = false python-versions = ">=3.7" +groups = ["test"] files = [ {file = "freezegun-1.5.1-py3-none-any.whl", hash = "sha256:bf111d7138a8abe55ab48a71755673dbaa4ab87f4cff5634a4442dfec34c15f1"}, {file = "freezegun-1.5.1.tar.gz", hash = "sha256:b29dedfcda6d5e8e083ce71b2b542753ad48cfec44037b3fc79702e2980a89e9"}, @@ -1521,6 +1642,7 @@ version = "1.5.0" description = "A list-like structure which implements collections.abc.MutableSequence" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a"}, {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb"}, @@ -1622,6 +1744,7 @@ version = "2.0" description = "A fancy and practical functional tools" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "funcy-2.0-py2.py3-none-any.whl", hash = "sha256:53df23c8bb1651b12f095df764bfb057935d49537a56de211b098f4c79614bb0"}, {file = "funcy-2.0.tar.gz", hash = "sha256:3963315d59d41c6f30c04bc910e10ab50a3ac4a225868bfa96feed133df075cb"}, @@ -1633,6 +1756,7 @@ version = "24.11.1" description = "Coroutine-based network library" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "gevent-24.11.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:92fe5dfee4e671c74ffaa431fd7ffd0ebb4b339363d24d0d944de532409b935e"}, {file = "gevent-24.11.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7bfcfe08d038e1fa6de458891bca65c1ada6d145474274285822896a858c870"}, @@ -1689,19 +1813,24 @@ test = ["cffi (>=1.17.1)", "coverage (>=5.0)", "dnspython (>=1.16.0,<2.0)", "idn [[package]] name = "google-ai-generativelanguage" -version = "0.4.0" +version = "0.6.15" description = "Google Ai Generativelanguage API client library" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ - {file = "google-ai-generativelanguage-0.4.0.tar.gz", hash = "sha256:c8199066c08f74c4e91290778329bb9f357ba1ea5d6f82de2bc0d10552bf4f8c"}, - {file = "google_ai_generativelanguage-0.4.0-py3-none-any.whl", hash = "sha256:e4c425376c1ee26c78acbc49a24f735f90ebfa81bf1a06495fae509a2433232c"}, + {file = "google_ai_generativelanguage-0.6.15-py3-none-any.whl", hash = "sha256:5a03ef86377aa184ffef3662ca28f19eeee158733e45d7947982eb953c6ebb6c"}, + {file = "google_ai_generativelanguage-0.6.15.tar.gz", hash = "sha256:8f6d9dc4c12b065fe2d0289026171acea5183ebf2d0b11cefe12f3821e159ec3"}, ] [package.dependencies] -google-api-core = {version = ">=1.34.0,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" +google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} +google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" +proto-plus = [ + {version = ">=1.22.3,<2.0.0dev", markers = "python_version < \"3.13\""}, + {version = ">=1.25.0,<2.0.0dev", markers = "python_version >= \"3.13\""}, +] +protobuf = ">=3.20.2,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0dev" [[package]] name = "google-api-core" @@ -1709,6 +1838,7 @@ version = "2.24.0" description = "Google API client core library" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "google_api_core-2.24.0-py3-none-any.whl", hash = "sha256:10d82ac0fca69c82a25b3efdeefccf6f28e02ebb97925a8cce8edbfe379929d9"}, {file = "google_api_core-2.24.0.tar.gz", hash = "sha256:e255640547a597a4da010876d333208ddac417d60add22b6851a0c66a831fcaf"}, @@ -1732,12 +1862,32 @@ grpc = ["grpcio (>=1.33.2,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "grpcio-status grpcgcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] +[[package]] +name = "google-api-python-client" +version = "2.161.0" +description = "Google API Client Library for Python" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "google_api_python_client-2.161.0-py2.py3-none-any.whl", hash = "sha256:9476a5a4f200bae368140453df40f9cda36be53fa7d0e9a9aac4cdb859a26448"}, + {file = "google_api_python_client-2.161.0.tar.gz", hash = "sha256:324c0cce73e9ea0a0d2afd5937e01b7c2d6a4d7e2579cdb6c384f9699d6c9f37"}, +] + +[package.dependencies] +google-api-core = ">=1.31.5,<2.0.dev0 || >2.3.0,<3.0.0.dev0" +google-auth = ">=1.32.0,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0.dev0" +google-auth-httplib2 = ">=0.2.0,<1.0.0" +httplib2 = ">=0.19.0,<1.dev0" +uritemplate = ">=3.0.1,<5" + [[package]] name = "google-auth" version = "2.37.0" description = "Google Authentication Library" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "google_auth-2.37.0-py2.py3-none-any.whl", hash = "sha256:42664f18290a6be591be5329a96fe30184be1a1badb7292a7f686a9659de9ca0"}, {file = "google_auth-2.37.0.tar.gz", hash = "sha256:0054623abf1f9c83492c63d3f47e77f0a544caa3d40b2d98e099a611c2dd5d00"}, @@ -1756,21 +1906,40 @@ pyopenssl = ["cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] reauth = ["pyu2f (>=0.1.5)"] requests = ["requests (>=2.20.0,<3.0.0.dev0)"] +[[package]] +name = "google-auth-httplib2" +version = "0.2.0" +description = "Google Authentication Library: httplib2 transport" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "google-auth-httplib2-0.2.0.tar.gz", hash = "sha256:38aa7badf48f974f1eb9861794e9c0cb2a0511a4ec0679b1f886d108f5640e05"}, + {file = "google_auth_httplib2-0.2.0-py2.py3-none-any.whl", hash = "sha256:b65a0a2123300dd71281a7bf6e64d65a0759287df52729bdd1ae2e47dc311a3d"}, +] + +[package.dependencies] +google-auth = "*" +httplib2 = ">=0.19.0" + [[package]] name = "google-generativeai" -version = "0.3.2" +version = "0.8.4" description = "Google Generative AI High level API client library and tools." optional = false python-versions = ">=3.9" +groups = ["main"] files = [ - {file = "google_generativeai-0.3.2-py3-none-any.whl", hash = "sha256:8761147e6e167141932dc14a7b7af08f2310dd56668a78d206c19bb8bd85bcd7"}, + {file = "google_generativeai-0.8.4-py3-none-any.whl", hash = "sha256:e987b33ea6decde1e69191ddcaec6ef974458864d243de7191db50c21a7c5b82"}, ] [package.dependencies] -google-ai-generativelanguage = "0.4.0" +google-ai-generativelanguage = "0.6.15" google-api-core = "*" -google-auth = "*" +google-api-python-client = "*" +google-auth = ">=2.15.0" protobuf = "*" +pydantic = "*" tqdm = "*" typing-extensions = "*" @@ -1783,6 +1952,7 @@ version = "1.66.0" description = "Common protobufs used in Google APIs" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "googleapis_common_protos-1.66.0-py2.py3-none-any.whl", hash = "sha256:d7abcd75fabb2e0ec9f74466401f6c119a0b498e27370e9be4c94cb7e382b8ed"}, {file = "googleapis_common_protos-1.66.0.tar.gz", hash = "sha256:c3e7b33d15fdca5374cc0a7346dd92ffa847425cc4ea941d970f13680052ec8c"}, @@ -1800,6 +1970,7 @@ version = "4.0.0" description = "Free Google Translate API for Python. Translates totally free of charge." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "googletrans-py-4.0.0.tar.gz", hash = "sha256:487963819ced88f1f81d848786e2d3e02544833d161cc5edb178a1f74bde6d98"}, ] @@ -1814,6 +1985,8 @@ version = "3.1.1" description = "Lightweight in-process concurrent programming" optional = false python-versions = ">=3.7" +groups = ["main"] +markers = "python_version < \"3.14\" and (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\") or platform_python_implementation == \"CPython\"" files = [ {file = "greenlet-3.1.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:0bbae94a29c9e5c7e4a2b7f0aae5c17e8e90acbfd3bf6270eeba60c39fce3563"}, {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fde093fb93f35ca72a556cf72c92ea3ebfda3d79fc35bb19fbe685853869a83"}, @@ -1900,6 +2073,7 @@ version = "1.69.0" description = "HTTP/2-based RPC framework" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "grpcio-1.69.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:2060ca95a8db295ae828d0fc1c7f38fb26ccd5edf9aa51a0f44251f5da332e97"}, {file = "grpcio-1.69.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:2e52e107261fd8fa8fa457fe44bfadb904ae869d87c1280bf60f93ecd3e79278"}, @@ -1967,6 +2141,7 @@ version = "1.62.3" description = "Status proto mapping for gRPC" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "grpcio-status-1.62.3.tar.gz", hash = "sha256:289bdd7b2459794a12cf95dc0cb727bd4a1742c37bd823f760236c937e53a485"}, {file = "grpcio_status-1.62.3-py3-none-any.whl", hash = "sha256:f9049b762ba8de6b1086789d8315846e094edac2c50beaf462338b301a8fd4b8"}, @@ -1983,6 +2158,7 @@ version = "23.0.0" description = "WSGI HTTP Server for UNIX" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d"}, {file = "gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec"}, @@ -2005,6 +2181,7 @@ version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, @@ -2016,6 +2193,7 @@ version = "4.1.0" description = "HTTP/2 State-Machine based protocol implementation" optional = false python-versions = ">=3.6.1" +groups = ["main"] files = [ {file = "h2-4.1.0-py3-none-any.whl", hash = "sha256:03a46bcf682256c95b5fd9e9a99c1323584c3eec6440d379b9903d709476bc6d"}, {file = "h2-4.1.0.tar.gz", hash = "sha256:a83aca08fbe7aacb79fec788c9c0bac936343560ed9ec18b82a13a12c28d2abb"}, @@ -2031,6 +2209,7 @@ version = "4.0.0" description = "Pure-Python HPACK header compression" optional = false python-versions = ">=3.6.1" +groups = ["main"] files = [ {file = "hpack-4.0.0-py3-none-any.whl", hash = "sha256:84a076fad3dc9a9f8063ccb8041ef100867b1878b25ef0ee63847a5d53818a6c"}, {file = "hpack-4.0.0.tar.gz", hash = "sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095"}, @@ -2042,6 +2221,7 @@ version = "1.0.7" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"}, {file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"}, @@ -2057,12 +2237,28 @@ http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] trio = ["trio (>=0.22.0,<1.0)"] +[[package]] +name = "httplib2" +version = "0.22.0" +description = "A comprehensive HTTP client library." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main"] +files = [ + {file = "httplib2-0.22.0-py3-none-any.whl", hash = "sha256:14ae0a53c1ba8f3d37e9e27cf37eabb0fb9980f435ba405d546948b009dd64dc"}, + {file = "httplib2-0.22.0.tar.gz", hash = "sha256:d7a10bc5ef5ab08322488bde8c726eeee5c8618723fdb399597ec58f3d82df81"}, +] + +[package.dependencies] +pyparsing = {version = ">=2.4.2,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.0.2 || >3.0.2,<3.0.3 || >3.0.3,<4", markers = "python_version > \"3.0\""} + [[package]] name = "httptools" version = "0.6.4" description = "A collection of framework independent HTTP protocol utils." optional = false python-versions = ">=3.8.0" +groups = ["main"] files = [ {file = "httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0"}, {file = "httptools-0.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:345c288418f0944a6fe67be8e6afa9262b18c7626c3ef3c28adc5eabc06a68da"}, @@ -2118,6 +2314,7 @@ version = "0.27.0" description = "The next generation HTTP client." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5"}, {file = "httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5"}, @@ -2142,6 +2339,7 @@ version = "0.4.0" description = "Consume Server-Sent Event (SSE) messages with HTTPX." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "httpx-sse-0.4.0.tar.gz", hash = "sha256:1e81a3a3070ce322add1d3529ed42eb5f70817f45ed6ec915ab753f961139721"}, {file = "httpx_sse-0.4.0-py3-none-any.whl", hash = "sha256:f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f"}, @@ -2153,6 +2351,7 @@ version = "6.0.1" description = "HTTP/2 framing layer for Python" optional = false python-versions = ">=3.6.1" +groups = ["main"] files = [ {file = "hyperframe-6.0.1-py3-none-any.whl", hash = "sha256:0ec6bafd80d8ad2195c4f03aacba3a8265e57bc4cff261e802bf39970ed02a15"}, {file = "hyperframe-6.0.1.tar.gz", hash = "sha256:ae510046231dc8e9ecb1a6586f63d2347bf4c8905914aa84ba585ae85f28a914"}, @@ -2164,6 +2363,7 @@ version = "21.0.0" description = "A featureful, immutable, and correct URL for Python." optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main"] files = [ {file = "hyperlink-21.0.0-py2.py3-none-any.whl", hash = "sha256:e6b14c37ecb73e89c77d78cdb4c2cc8f3fb59a885c5b3f819ff4ed80f25af1b4"}, {file = "hyperlink-21.0.0.tar.gz", hash = "sha256:427af957daa58bc909471c6c40f74c5450fa123dd093fc53efd2e91d2705a56b"}, @@ -2178,6 +2378,7 @@ version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" +groups = ["main", "typing"] files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, @@ -2192,6 +2393,7 @@ version = "24.7.2" description = "A small library that versions your Python projects." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "incremental-24.7.2-py3-none-any.whl", hash = "sha256:8cb2c3431530bec48ad70513931a760f446ad6c25e8333ca5d95e24b0ed7b8fe"}, {file = "incremental-24.7.2.tar.gz", hash = "sha256:fb4f1d47ee60efe87d4f6f0ebb5f70b9760db2b2574c59c8e8912be4ebd464c9"}, @@ -2209,6 +2411,7 @@ version = "0.5.1" description = "A port of Ruby on Rails inflector to Python" optional = false python-versions = ">=3.5" +groups = ["main", "test"] files = [ {file = "inflection-0.5.1-py2.py3-none-any.whl", hash = "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"}, {file = "inflection-0.5.1.tar.gz", hash = "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417"}, @@ -2220,6 +2423,7 @@ version = "2.0.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.7" +groups = ["test"] files = [ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, @@ -2231,6 +2435,7 @@ version = "0.8.2" description = "Fast iterable JSON parser." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "jiter-0.8.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ca8577f6a413abe29b079bc30f907894d7eb07a865c4df69475e868d73e71c7b"}, {file = "jiter-0.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b25bd626bde7fb51534190c7e3cb97cee89ee76b76d7585580e22f34f5e3f393"}, @@ -2316,6 +2521,7 @@ 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.*" +groups = ["main"] files = [ {file = "jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade"}, {file = "jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c"}, @@ -2330,6 +2536,7 @@ version = "3.0.0" description = "Identify specific nodes in a JSON document (RFC 6901)" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942"}, {file = "jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef"}, @@ -2341,6 +2548,7 @@ version = "4.23.0" description = "An implementation of JSON Schema validation for Python" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566"}, {file = "jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4"}, @@ -2362,6 +2570,7 @@ version = "2024.10.1" description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "jsonschema_specifications-2024.10.1-py3-none-any.whl", hash = "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf"}, {file = "jsonschema_specifications-2024.10.1.tar.gz", hash = "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272"}, @@ -2376,6 +2585,7 @@ version = "1.5.6" description = "Implementation of JOSE Web standards" optional = false python-versions = ">= 3.8" +groups = ["main"] files = [ {file = "jwcrypto-1.5.6-py3-none-any.whl", hash = "sha256:150d2b0ebbdb8f40b77f543fb44ffd2baeff48788be71f67f03566692fd55789"}, {file = "jwcrypto-1.5.6.tar.gz", hash = "sha256:771a87762a0c081ae6166958a954f80848820b2ab066937dc8b8379d65b1b039"}, @@ -2391,6 +2601,7 @@ version = "5.4.2" description = "Messaging library for Python." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "kombu-5.4.2-py3-none-any.whl", hash = "sha256:14212f5ccf022fc0a70453bb025a1dcc32782a588c49ea866884047d66e14763"}, {file = "kombu-5.4.2.tar.gz", hash = "sha256:eef572dd2fd9fc614b37580e3caeafdd5af46c1eff31e7fba89138cdb406f2cf"}, @@ -2420,142 +2631,144 @@ zookeeper = ["kazoo (>=2.8.0)"] [[package]] name = "langchain" -version = "0.1.20" +version = "0.3.19" description = "Building applications with LLMs through composability" optional = false -python-versions = "<4.0,>=3.8.1" +python-versions = "<4.0,>=3.9" +groups = ["main"] files = [ - {file = "langchain-0.1.20-py3-none-any.whl", hash = "sha256:09991999fbd6c3421a12db3c7d1f52d55601fc41d9b2a3ef51aab2e0e9c38da9"}, - {file = "langchain-0.1.20.tar.gz", hash = "sha256:f35c95eed8c8375e02dce95a34f2fd4856a4c98269d6dc34547a23dba5beab7e"}, + {file = "langchain-0.3.19-py3-none-any.whl", hash = "sha256:1e16d97db9106640b7de4c69f8f5ed22eeda56b45b9241279e83f111640eff16"}, + {file = "langchain-0.3.19.tar.gz", hash = "sha256:b96f8a445f01d15d522129ffe77cc89c8468dbd65830d153a676de8f6b899e7b"}, ] [package.dependencies] aiohttp = ">=3.8.3,<4.0.0" -dataclasses-json = ">=0.5.7,<0.7" -langchain-community = ">=0.0.38,<0.1" -langchain-core = ">=0.1.52,<0.2.0" -langchain-text-splitters = ">=0.0.1,<0.1" -langsmith = ">=0.1.17,<0.2.0" -numpy = ">=1,<2" -pydantic = ">=1,<3" +langchain-core = ">=0.3.35,<1.0.0" +langchain-text-splitters = ">=0.3.6,<1.0.0" +langsmith = ">=0.1.17,<0.4" +numpy = {version = ">=1.26.2,<3", markers = "python_version >= \"3.12\""} +pydantic = ">=2.7.4,<3.0.0" PyYAML = ">=5.3" requests = ">=2,<3" SQLAlchemy = ">=1.4,<3" -tenacity = ">=8.1.0,<9.0.0" +tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<10" [package.extras] -azure = ["azure-ai-formrecognizer (>=3.2.1,<4.0.0)", "azure-ai-textanalytics (>=5.3.0,<6.0.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 (<2)"] -clarifai = ["clarifai (>=9.1.0)"] -cli = ["typer (>=0.9.0,<0.10.0)"] -cohere = ["cohere (>=4,<6)"] -docarray = ["docarray[hnswlib] (>=0.32.0,<0.33.0)"] -embeddings = ["sentence-transformers (>=2,<3)"] -extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "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)", "cohere (>=4,<6)", "couchbase (>=4.1.9,<5.0.0)", "dashvector (>=1.0.1,<2.0.0)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "langchain-openai (>=0.0.2,<0.1)", "lxml (>=4.9.3,<6.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.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 (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.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)", "rdflib (==7.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,<6)", "huggingface_hub (>=0,<1)", "manifest-ml (>=0.0.1,<0.0.2)", "nlpcloud (>=1,<2)", "openai (<2)", "openlm (>=0.0.5,<0.0.6)", "torch (>=1,<3)", "transformers (>=4,<5)"] -openai = ["openai (<2)", "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)"] +anthropic = ["langchain-anthropic"] +aws = ["langchain-aws"] +cohere = ["langchain-cohere"] +community = ["langchain-community"] +deepseek = ["langchain-deepseek"] +fireworks = ["langchain-fireworks"] +google-genai = ["langchain-google-genai"] +google-vertexai = ["langchain-google-vertexai"] +groq = ["langchain-groq"] +huggingface = ["langchain-huggingface"] +mistralai = ["langchain-mistralai"] +ollama = ["langchain-ollama"] +openai = ["langchain-openai"] +together = ["langchain-together"] +xai = ["langchain-xai"] [[package]] name = "langchain-community" -version = "0.0.38" +version = "0.3.18" description = "Community contributed LangChain integrations." optional = false -python-versions = "<4.0,>=3.8.1" +python-versions = "<4.0,>=3.9" +groups = ["main"] files = [ - {file = "langchain_community-0.0.38-py3-none-any.whl", hash = "sha256:ecb48660a70a08c90229be46b0cc5f6bc9f38f2833ee44c57dfab9bf3a2c121a"}, - {file = "langchain_community-0.0.38.tar.gz", hash = "sha256:127fc4b75bc67b62fe827c66c02e715a730fef8fe69bd2023d466bab06b5810d"}, + {file = "langchain_community-0.3.18-py3-none-any.whl", hash = "sha256:0d4a70144a1750045c4f726f9a43379ed2484178f76e4b8295bcef3a7fdf41d5"}, + {file = "langchain_community-0.3.18.tar.gz", hash = "sha256:fa2889a8f0b2d22b5c306fd1b070c0970e1f11b604bf55fad2f4a1d0bf68a077"}, ] [package.dependencies] aiohttp = ">=3.8.3,<4.0.0" dataclasses-json = ">=0.5.7,<0.7" -langchain-core = ">=0.1.52,<0.2.0" -langsmith = ">=0.1.0,<0.2.0" -numpy = ">=1,<2" +httpx-sse = ">=0.4.0,<1.0.0" +langchain = ">=0.3.19,<1.0.0" +langchain-core = ">=0.3.37,<1.0.0" +langsmith = ">=0.1.125,<0.4" +numpy = {version = ">=1.26.2,<3", markers = "python_version >= \"3.12\""} +pydantic-settings = ">=2.4.0,<3.0.0" PyYAML = ">=5.3" requests = ">=2,<3" SQLAlchemy = ">=1.4,<3" -tenacity = ">=8.1.0,<9.0.0" - -[package.extras] -cli = ["typer (>=0.9.0,<0.10.0)"] -extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "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)", "azure-ai-documentintelligence (>=1.0.0b1,<2.0.0)", "azure-identity (>=1.15.0,<2.0.0)", "azure-search-documents (==11.4.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.6,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cloudpickle (>=2.0.0)", "cohere (>=4,<5)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "elasticsearch (>=8.12.0,<9.0.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "friendli-client (>=1.2.4,<2.0.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "gradientai (>=1.4.0,<2.0.0)", "hdbcli (>=2.19.21,<3.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "httpx (>=0.24.1,<0.25.0)", "httpx-sse (>=0.4.0,<0.5.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "lxml (>=4.9.3,<6.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.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)", "nvidia-riva-client (>=2.14.0,<3.0.0)", "oci (>=2.119.1,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "oracle-ads (>=2.9.1,<3.0.0)", "oracledb (>=2.2.0,<3.0.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "premai (>=0.3.25,<0.4.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pyjwt (>=2.8.0,<3.0.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)", "rdflib (==7.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)", "tidb-vector (>=0.0.3,<1.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "tree-sitter (>=0.20.2,<0.21.0)", "tree-sitter-languages (>=1.8.0,<2.0.0)", "upstash-redis (>=0.15.0,<0.16.0)", "vdms (>=0.0.20,<0.0.21)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"] +tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<10" [[package]] name = "langchain-core" -version = "0.1.53" +version = "0.3.37" description = "Building applications with LLMs through composability" optional = false -python-versions = "<4.0,>=3.8.1" +python-versions = "<4.0,>=3.9" +groups = ["main"] files = [ - {file = "langchain_core-0.1.53-py3-none-any.whl", hash = "sha256:02a88a21e3bd294441b5b741625fa4b53b1c684fd58ba6e5d9028e53cbe8542f"}, - {file = "langchain_core-0.1.53.tar.gz", hash = "sha256:df3773a553b5335eb645827b99a61a7018cea4b11dc45efa2613fde156441cec"}, + {file = "langchain_core-0.3.37-py3-none-any.whl", hash = "sha256:8202fd6506ce139a3a1b1c4c3006216b1c7fffa40bdd1779f7d2c67f75eb5f79"}, + {file = "langchain_core-0.3.37.tar.gz", hash = "sha256:cda8786e616caa2f68f7cc9e811b9b50e3b63fb2094333318b348e5961a7ea01"}, ] [package.dependencies] jsonpatch = ">=1.33,<2.0" -langsmith = ">=0.1.0,<0.2.0" -packaging = ">=23.2,<24.0" -pydantic = ">=1,<3" +langsmith = ">=0.1.125,<0.4" +packaging = ">=23.2,<25" +pydantic = [ + {version = ">=2.5.2,<3.0.0", markers = "python_full_version < \"3.12.4\""}, + {version = ">=2.7.4,<3.0.0", markers = "python_full_version >= \"3.12.4\""}, +] PyYAML = ">=5.3" -tenacity = ">=8.1.0,<9.0.0" - -[package.extras] -extended-testing = ["jinja2 (>=3,<4)"] +tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<10.0.0" +typing-extensions = ">=4.7" [[package]] name = "langchain-google-genai" -version = "0.0.9" +version = "2.0.9" description = "An integration package connecting Google's genai package and LangChain" optional = false -python-versions = ">=3.9,<4.0" +python-versions = "<4.0,>=3.9" +groups = ["main"] files = [ - {file = "langchain_google_genai-0.0.9-py3-none-any.whl", hash = "sha256:82c0ca9540132a59b09fc38ff249a2dd06f8a587ed37c291a4fe7678d5566d15"}, - {file = "langchain_google_genai-0.0.9.tar.gz", hash = "sha256:466a228032bb06b0c1def822e57cbf2dfe9e4d1cc91dffa473a3025eb760f0ef"}, + {file = "langchain_google_genai-2.0.9-py3-none-any.whl", hash = "sha256:48d8c78c42048d54f40dff333db9d359746644e0feb0e08b5eabdf34ad7149ca"}, + {file = "langchain_google_genai-2.0.9.tar.gz", hash = "sha256:65205089da1f72688a0ed6e7c6914af308b6514ab8038fd8126ecb20f1df234c"}, ] [package.dependencies] -google-generativeai = ">=0.3.1,<0.4.0" -langchain-core = ">=0.1,<0.2" - -[package.extras] -images = ["pillow (>=10.1.0,<11.0.0)"] +filetype = ">=1.2.0,<2.0.0" +google-generativeai = ">=0.8.0,<0.9.0" +langchain-core = ">=0.3.27,<0.4.0" +pydantic = ">=2,<3" [[package]] name = "langchain-openai" -version = "0.0.2.post1" +version = "0.3.6" description = "An integration package connecting OpenAI and LangChain" optional = false -python-versions = ">=3.8.1,<4.0" +python-versions = "<4.0,>=3.9" +groups = ["main"] files = [ - {file = "langchain_openai-0.0.2.post1-py3-none-any.whl", hash = "sha256:ba468b94c23da9d8ccefe5d5a3c1c65b4b9702292523e53acc689a9110022e26"}, - {file = "langchain_openai-0.0.2.post1.tar.gz", hash = "sha256:f8e78db4a663feeac71d9f036b9422406c199ea3ef4c97d99ff392c93530e073"}, + {file = "langchain_openai-0.3.6-py3-none-any.whl", hash = "sha256:05f0869f6cc963e2ec9e2e54ea1038d9c2af784c67f0e217040dfc918b31649a"}, + {file = "langchain_openai-0.3.6.tar.gz", hash = "sha256:7daf92e1cd98865ab5213ec5bec2cbd6c28f011e250714978b3a99c7e4fc88ce"}, ] [package.dependencies] -langchain-core = ">=0.1.7,<0.2" -numpy = ">=1,<2" -openai = ">=1.6.1,<2.0.0" -tiktoken = ">=0.5.2,<0.6.0" +langchain-core = ">=0.3.35,<1.0.0" +openai = ">=1.58.1,<2.0.0" +tiktoken = ">=0.7,<1" [[package]] name = "langchain-text-splitters" -version = "0.0.2" +version = "0.3.6" description = "LangChain text splitting utilities" optional = false -python-versions = "<4.0,>=3.8.1" +python-versions = "<4.0,>=3.9" +groups = ["main"] files = [ - {file = "langchain_text_splitters-0.0.2-py3-none-any.whl", hash = "sha256:13887f32705862c1e1454213cb7834a63aae57c26fcd80346703a1d09c46168d"}, - {file = "langchain_text_splitters-0.0.2.tar.gz", hash = "sha256:ac8927dc0ba08eba702f6961c9ed7df7cead8de19a9f7101ab2b5ea34201b3c1"}, + {file = "langchain_text_splitters-0.3.6-py3-none-any.whl", hash = "sha256:e5d7b850f6c14259ea930be4a964a65fa95d9df7e1dbdd8bad8416db72292f4e"}, + {file = "langchain_text_splitters-0.3.6.tar.gz", hash = "sha256:c537972f4b7c07451df431353a538019ad9dadff7a1073ea363946cea97e1bee"}, ] [package.dependencies] -langchain-core = ">=0.1.28,<0.3" - -[package.extras] -extended-testing = ["beautifulsoup4 (>=4.12.3,<5.0.0)", "lxml (>=4.9.3,<6.0)"] +langchain-core = ">=0.3.34,<1.0.0" [[package]] name = "langchainhub" @@ -2563,6 +2776,7 @@ version = "0.1.21" description = "The LangChain Hub API client" optional = false python-versions = "<4.0,>=3.8.1" +groups = ["main"] files = [ {file = "langchainhub-0.1.21-py3-none-any.whl", hash = "sha256:1cc002dc31e0d132a776afd044361e2b698743df5202618cf2bad399246b895f"}, {file = "langchainhub-0.1.21.tar.gz", hash = "sha256:723383b3964a47dbaea6ad5d0ef728accefbc9d2c07480e800bdec43510a8c10"}, @@ -2579,6 +2793,7 @@ version = "0.0.46" description = "" optional = false python-versions = ">=3.8.1,<4.0.0" +groups = ["main"] files = [ {file = "langserve-0.0.46-py3-none-any.whl", hash = "sha256:0720710b9d545394f07394f95a9f2ad294fb33359945522e7dc3b9dcdbde1d70"}, {file = "langserve-0.0.46.tar.gz", hash = "sha256:a914c65d9fed356361fdd0ed6c23f765d4ea641eb0173eafd0a82fce9227229e"}, @@ -2602,6 +2817,7 @@ version = "0.1.147" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = false python-versions = "<4.0,>=3.8.1" +groups = ["main"] files = [ {file = "langsmith-0.1.147-py3-none-any.whl", hash = "sha256:7166fc23b965ccf839d64945a78e9f1157757add228b086141eb03a60d699a15"}, {file = "langsmith-0.1.147.tar.gz", hash = "sha256:2e933220318a4e73034657103b3b1a3a6109cc5db3566a7e8e03be8d6d7def7a"}, @@ -2626,6 +2842,7 @@ version = "5.3.0" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656"}, {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d"}, @@ -2780,6 +2997,7 @@ version = "3.25.1" description = "A lightweight library for converting complex datatypes to and from native Python datatypes." optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "marshmallow-3.25.1-py3-none-any.whl", hash = "sha256:ec5d00d873ce473b7f2ffcb7104286a376c354cab0c2fa12f5573dab03e87210"}, {file = "marshmallow-3.25.1.tar.gz", hash = "sha256:f4debda3bb11153d81ac34b0d582bf23053055ee11e791b54b4b35493468040a"}, @@ -2799,6 +3017,7 @@ version = "7.2.14" description = "MinIO Python SDK for Amazon S3 Compatible Cloud Storage" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "minio-7.2.14-py3-none-any.whl", hash = "sha256:868dfe907e1702ce4bec86df1f3ced577a73ca85f344ef898d94fe2b5237f8c1"}, {file = "minio-7.2.14.tar.gz", hash = "sha256:f5c24bf236fefd2edc567cd4455dc49a11ad8ff7ac984bb031b849d82f01222a"}, @@ -2817,6 +3036,7 @@ version = "1.1.0" description = "MessagePack serializer" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "msgpack-1.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7ad442d527a7e358a469faf43fda45aaf4ac3249c8310a82f0ccff9164e5dccd"}, {file = "msgpack-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:74bed8f63f8f14d75eec75cf3d04ad581da6b914001b474a5d3cd3372c8cc27d"}, @@ -2890,6 +3110,7 @@ version = "6.1.0" description = "multidict implementation" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"}, {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"}, @@ -2991,6 +3212,7 @@ version = "1.47.0" description = "read and write audio tags for many formats" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "mutagen-1.47.0-py3-none-any.whl", hash = "sha256:edd96f50c5907a9539d8e5bba7245f62c9f520aef333d13392a79a4f70aca719"}, {file = "mutagen-1.47.0.tar.gz", hash = "sha256:719fadef0a978c31b4cf3c956261b3c58b6948b32023078a2117b1de09f0fc99"}, @@ -3002,6 +3224,7 @@ version = "1.14.1" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" +groups = ["typing"] files = [ {file = "mypy-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:52686e37cf13d559f668aa398dd7ddf1f92c5d613e4f8cb262be2fb4fedb0fcb"}, {file = "mypy-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1fb545ca340537d4b45d3eecdb3def05e913299ca72c290326be19b3804b39c0"}, @@ -3060,6 +3283,7 @@ version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false python-versions = ">=3.5" +groups = ["main", "typing"] files = [ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, @@ -3071,6 +3295,7 @@ version = "1.3.0" description = "A network address manipulation library for Python" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "netaddr-1.3.0-py3-none-any.whl", hash = "sha256:c2c6a8ebe5554ce33b7d5b3a306b71bbb373e000bbbf2350dd5213cc56e3dbbe"}, {file = "netaddr-1.3.0.tar.gz", hash = "sha256:5c3c3d9895b551b763779ba7db7a03487dc1f8e3b385af819af341ae9ef6e48a"}, @@ -3085,6 +3310,7 @@ version = "1.26.4" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, @@ -3130,6 +3356,7 @@ version = "3.2.2" description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca"}, {file = "oauthlib-3.2.2.tar.gz", hash = "sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918"}, @@ -3146,6 +3373,7 @@ version = "1.59.7" description = "The official Python library for the openai API" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "openai-1.59.7-py3-none-any.whl", hash = "sha256:cfa806556226fa96df7380ab2e29814181d56fea44738c2b0e581b462c268692"}, {file = "openai-1.59.7.tar.gz", hash = "sha256:043603def78c00befb857df9f0a16ee76a3af5984ba40cb7ee5e2f40db4646bf"}, @@ -3171,6 +3399,7 @@ version = "3.1.5" description = "A Python library to read/write Excel 2010 xlsx/xlsm files" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "openpyxl-3.1.5-py2.py3-none-any.whl", hash = "sha256:5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2"}, {file = "openpyxl-3.1.5.tar.gz", hash = "sha256:cf0e3cf56142039133628b5acffe8ef0c12bc902d2aadd3e0fe5878dc08d1050"}, @@ -3185,6 +3414,7 @@ version = "3.10.14" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "orjson-3.10.14-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:849ea7845a55f09965826e816cdc7689d6cf74fe9223d79d758c714af955bcb6"}, {file = "orjson-3.10.14-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5947b139dfa33f72eecc63f17e45230a97e741942955a6c9e650069305eb73d"}, @@ -3269,6 +3499,7 @@ version = "23.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.7" +groups = ["main", "test"] files = [ {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, @@ -3280,6 +3511,7 @@ version = "10.4.0" description = "Python Imaging Library (Fork)" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e"}, {file = "pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d"}, @@ -3377,6 +3609,7 @@ version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" +groups = ["test"] files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, @@ -3392,6 +3625,7 @@ version = "0.21.1" description = "Python client for the Prometheus monitoring system." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "prometheus_client-0.21.1-py3-none-any.whl", hash = "sha256:594b45c410d6f4f8888940fe80b5cc2521b305a1fafe1c58609ef715a001f301"}, {file = "prometheus_client-0.21.1.tar.gz", hash = "sha256:252505a722ac04b0456be05c05f75f45d760c2911ffc45f2a06bcaed9f3ae3fb"}, @@ -3406,6 +3640,7 @@ version = "3.0.48" description = "Library for building powerful interactive command lines in Python" optional = false python-versions = ">=3.7.0" +groups = ["main"] files = [ {file = "prompt_toolkit-3.0.48-py3-none-any.whl", hash = "sha256:f49a827f90062e411f1ce1f854f2aedb3c23353244f8108b89283587397ac10e"}, {file = "prompt_toolkit-3.0.48.tar.gz", hash = "sha256:d6623ab0477a80df74e646bdbc93621143f5caf104206aa29294d53de1a03d90"}, @@ -3420,6 +3655,7 @@ version = "0.2.1" description = "Accelerated property cache" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6b3f39a85d671436ee3d12c017f8fdea38509e4f25b28eb25877293c98c243f6"}, {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d51fbe4285d5db5d92a929e3e21536ea3dd43732c5b177c7ef03f918dff9f2"}, @@ -3511,6 +3747,7 @@ version = "1.25.0" description = "Beautiful, Pythonic protocol buffers." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "proto_plus-1.25.0-py3-none-any.whl", hash = "sha256:c91fc4a65074ade8e458e95ef8bac34d4008daa7cce4a12d6707066fca648961"}, {file = "proto_plus-1.25.0.tar.gz", hash = "sha256:fbb17f57f7bd05a68b7707e745e26528b0b3c34e378db91eef93912c54982d91"}, @@ -3528,6 +3765,7 @@ version = "4.25.5" description = "" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "protobuf-4.25.5-cp310-abi3-win32.whl", hash = "sha256:5e61fd921603f58d2f5acb2806a929b4675f8874ff5f330b7d6f7e2e784bbcd8"}, {file = "protobuf-4.25.5-cp310-abi3-win_amd64.whl", hash = "sha256:4be0571adcbe712b282a330c6e89eae24281344429ae95c6d85e79e84780f5ea"}, @@ -3548,6 +3786,7 @@ version = "1.0.2" description = "psycopg2 integration with coroutine libraries" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "psycogreen-1.0.2.tar.gz", hash = "sha256:c429845a8a49cf2f76b71265008760bcd7c7c77d80b806db4dc81116dbcd130d"}, ] @@ -3558,6 +3797,7 @@ version = "2.9.10" description = "psycopg2 - Python-PostgreSQL Database Adapter" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "psycopg2-binary-2.9.10.tar.gz", hash = "sha256:4b3df0e6990aa98acda57d983942eff13d824135fe2250e6522edaa782a06de2"}, {file = "psycopg2_binary-2.9.10-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:0ea8e3d0ae83564f2fc554955d327fa081d065c8ca5cc6d2abb643e2c9c1200f"}, @@ -3606,7 +3846,6 @@ files = [ {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bb89f0a835bcfc1d42ccd5f41f04870c1b936d8507c6df12b7737febc40f0909"}, {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f0c2d907a1e102526dd2986df638343388b94c33860ff3bbe1384130828714b1"}, {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8157bed2f51db683f31306aa497311b560f2265998122abe1dce6428bd86567"}, - {file = "psycopg2_binary-2.9.10-cp313-cp313-win_amd64.whl", hash = "sha256:27422aa5f11fbcd9b18da48373eb67081243662f9b46e6fd07c3eb46e4535142"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:eb09aa7f9cecb45027683bb55aebaaf45a0df8bf6de68801a6afdc7947bb09d4"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b73d6d7f0ccdad7bc43e6d34273f70d587ef62f824d7261c4ae9b8b1b6af90e8"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce5ab4bf46a211a8e924d307c1b1fcda82368586a19d0a24f8ae166f5c784864"}, @@ -3635,6 +3874,7 @@ version = "0.6.1" description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629"}, {file = "pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034"}, @@ -3646,6 +3886,7 @@ version = "0.4.1" description = "A collection of ASN.1-based protocols modules" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pyasn1_modules-0.4.1-py3-none-any.whl", hash = "sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd"}, {file = "pyasn1_modules-0.4.1.tar.gz", hash = "sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c"}, @@ -3660,6 +3901,7 @@ version = "2.22" description = "C parser in Python" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, @@ -3671,6 +3913,7 @@ version = "3.21.0" description = "Cryptographic library for Python" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +groups = ["main"] files = [ {file = "pycryptodome-3.21.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:dad9bf36eda068e89059d1f07408e397856be9511d7113ea4b586642a429a4fd"}, {file = "pycryptodome-3.21.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:a1752eca64c60852f38bb29e2c86fca30d7672c024128ef5d70cc15868fa10f4"}, @@ -3712,6 +3955,7 @@ version = "2.10.5" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pydantic-2.10.5-py3-none-any.whl", hash = "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53"}, {file = "pydantic-2.10.5.tar.gz", hash = "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff"}, @@ -3732,6 +3976,7 @@ version = "2.27.2" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"}, {file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"}, @@ -3838,12 +4083,34 @@ files = [ [package.dependencies] typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" +[[package]] +name = "pydantic-settings" +version = "2.7.1" +description = "Settings management using Pydantic" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "pydantic_settings-2.7.1-py3-none-any.whl", hash = "sha256:590be9e6e24d06db33a4262829edef682500ef008565a969c73d39d5f8bfb3fd"}, + {file = "pydantic_settings-2.7.1.tar.gz", hash = "sha256:10c9caad35e64bfb3c2fbf70a078c0e25cc92499782e5200747f942a065dec93"}, +] + +[package.dependencies] +pydantic = ">=2.7.0" +python-dotenv = ">=0.21.0" + +[package.extras] +azure-key-vault = ["azure-identity (>=1.16.0)", "azure-keyvault-secrets (>=4.8.0)"] +toml = ["tomli (>=2.0.1)"] +yaml = ["pyyaml (>=6.0.1)"] + [[package]] name = "pyjwt" version = "2.10.1" description = "JSON Web Token implementation in Python" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb"}, {file = "pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953"}, @@ -3861,6 +4128,7 @@ version = "25.0.0" description = "Python wrapper module around the OpenSSL library" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "pyOpenSSL-25.0.0-py3-none-any.whl", hash = "sha256:424c247065e46e76a37411b9ab1782541c23bb658bf003772c3405fbaa128e90"}, {file = "pyopenssl-25.0.0.tar.gz", hash = "sha256:cd2cef799efa3936bb08e8ccb9433a575722b9dd986023f1cabc4ae64e9dac16"}, @@ -3874,12 +4142,40 @@ typing-extensions = {version = ">=4.9", markers = "python_version < \"3.13\" and docs = ["sphinx (!=5.2.0,!=5.2.0.post0,!=7.2.5)", "sphinx_rtd_theme"] test = ["pretend", "pytest (>=3.0.1)", "pytest-rerunfailures"] +[[package]] +name = "pypandoc" +version = "1.15" +description = "Thin wrapper for pandoc." +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "pypandoc-1.15-py3-none-any.whl", hash = "sha256:4ededcc76c8770f27aaca6dff47724578428eca84212a31479403a9731fc2b16"}, + {file = "pypandoc-1.15.tar.gz", hash = "sha256:ea25beebe712ae41d63f7410c08741a3cab0e420f6703f95bc9b3a749192ce13"}, +] + +[[package]] +name = "pyparsing" +version = "3.2.1" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pyparsing-3.2.1-py3-none-any.whl", hash = "sha256:506ff4f4386c4cec0590ec19e6302d3aedb992fdc02c761e90416f158dacf8e1"}, + {file = "pyparsing-3.2.1.tar.gz", hash = "sha256:61980854fd66de3a90028d679a954d5f2623e83144b5afe5ee86f43d762e5f0a"}, +] + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] + [[package]] name = "pypdf2" version = "3.0.1" description = "A pure-python PDF library capable of splitting, merging, cropping, and transforming PDF files" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "PyPDF2-3.0.1.tar.gz", hash = "sha256:a74408f69ba6271f71b9352ef4ed03dc53a31aa404d29b5d31f53bfecfee1440"}, {file = "pypdf2-3.0.1-py3-none-any.whl", hash = "sha256:d16e4205cfee272fbdc0568b68d82be796540b1537508cef59388f839c191928"}, @@ -3898,6 +4194,7 @@ version = "7.4.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" +groups = ["test"] files = [ {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, @@ -3918,6 +4215,7 @@ version = "4.1.0" description = "Pytest plugin for measuring coverage." optional = false python-versions = ">=3.7" +groups = ["test"] files = [ {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, @@ -3936,6 +4234,7 @@ version = "4.9.0" description = "A Django plugin for pytest." optional = false python-versions = ">=3.8" +groups = ["test"] files = [ {file = "pytest_django-4.9.0-py3-none-any.whl", hash = "sha256:1d83692cb39188682dbb419ff0393867e9904094a549a7d38a3154d5731b2b99"}, {file = "pytest_django-4.9.0.tar.gz", hash = "sha256:8bf7bc358c9ae6f6fc51b6cebb190fe20212196e6807121f11bd6a3b03428314"}, @@ -3954,6 +4253,7 @@ version = "2.7.0" description = "Factory Boy support for pytest." optional = false python-versions = ">=3.8" +groups = ["test"] files = [ {file = "pytest_factoryboy-2.7.0-py3-none-any.whl", hash = "sha256:bf3222db22d954fbf46f4bff902a0a8d82f3fc3594a47c04bbdc0546ff4c59a6"}, {file = "pytest_factoryboy-2.7.0.tar.gz", hash = "sha256:67fc54ec8669a3feb8ac60094dd57cd71eb0b20b2c319d2957873674c776a77b"}, @@ -3972,6 +4272,7 @@ version = "0.4.2" description = "Wrap tests with fixtures in freeze_time" optional = false python-versions = "*" +groups = ["test"] files = [ {file = "pytest-freezegun-0.4.2.zip", hash = "sha256:19c82d5633751bf3ec92caa481fb5cffaac1787bd485f0df6436fd6242176949"}, {file = "pytest_freezegun-0.4.2-py2.py3-none-any.whl", hash = "sha256:5318a6bfb8ba4b709c8471c94d0033113877b3ee02da5bfcd917c1889cde99a7"}, @@ -3987,6 +4288,7 @@ version = "3.14.0" description = "Thin-wrapper around the mock package for easier use with pytest" optional = false python-versions = ">=3.8" +groups = ["test"] files = [ {file = "pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0"}, {file = "pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f"}, @@ -4004,6 +4306,7 @@ version = "3.2.0" description = "Python Crontab API" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "python_crontab-3.2.0-py3-none-any.whl", hash = "sha256:82cb9b6a312d41ff66fd3caf3eed7115c28c195bfb50711bc2b4b9592feb9fe5"}, {file = "python_crontab-3.2.0.tar.gz", hash = "sha256:40067d1dd39ade3460b2ad8557c7651514cd3851deffff61c5c60e1227c5c36b"}, @@ -4022,6 +4325,7 @@ version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main", "test"] files = [ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, @@ -4036,6 +4340,7 @@ version = "1.1.2" description = "Create, read, and update Microsoft Word .docx files." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "python_docx-1.1.2-py3-none-any.whl", hash = "sha256:08c20d6058916fb19853fcf080f7f42b6270d89eac9fa5f8c15f691c0017fabe"}, {file = "python_docx-1.1.2.tar.gz", hash = "sha256:0cf1f22e95b9002addca7948e16f2cd7acdfd498047f1941ca5d293db7762efd"}, @@ -4051,6 +4356,7 @@ version = "1.0.1" description = "Read key-value pairs from a .env file and set them as environment variables" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, @@ -4065,6 +4371,7 @@ version = "3.3.0" description = "JOSE implementation in Python" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "python-jose-3.3.0.tar.gz", hash = "sha256:55779b5e6ad599c6336191246e95eb2293a9ddebd555f796a65f838f07e5d78a"}, {file = "python_jose-3.3.0-py2.py3-none-any.whl", hash = "sha256:9b1376b023f8b298536eedd47ae1089bcdb848f1535ab30555cd92002d78923a"}, @@ -4087,6 +4394,7 @@ version = "3.2.0" description = "OpenID support for modern servers and consumers." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "python3-openid-3.2.0.tar.gz", hash = "sha256:33fbf6928f401e0b790151ed2b5290b02545e8775f982485205a066f874aaeaf"}, {file = "python3_openid-3.2.0-py3-none-any.whl", hash = "sha256:6626f771e0417486701e0b4daff762e7212e820ca5b29fcc0d05f6f8736dfa6b"}, @@ -4105,6 +4413,7 @@ version = "2024.2" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"}, {file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"}, @@ -4116,6 +4425,7 @@ version = "6.0.2" description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, @@ -4178,6 +4488,7 @@ version = "5.2.1" description = "Python client for Redis database and key-value store" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "redis-5.2.1-py3-none-any.whl", hash = "sha256:ee7e1056b9aea0f04c6c2ed59452947f34c4940ee025f5dd83e6a6418b6989e4"}, {file = "redis-5.2.1.tar.gz", hash = "sha256:16f2e22dff21d5125e8481515e386711a34cbec50f0e44413dd7d9c060a54e0f"}, @@ -4193,6 +4504,7 @@ version = "0.35.1" description = "JSON Referencing + Python" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"}, {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"}, @@ -4208,6 +4520,7 @@ version = "2024.11.6" description = "Alternative regular expression module, to replace re." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91"}, {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0"}, @@ -4307,22 +4620,21 @@ files = [ [[package]] name = "replicate" -version = "0.10.0" +version = "1.0.4" description = "Python client for Replicate" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "replicate-0.10.0-py3-none-any.whl", hash = "sha256:71464d62259b22a17f5383e83ebaf158cace69ba0153a9de21061283ac2c3a4b"}, - {file = "replicate-0.10.0.tar.gz", hash = "sha256:f714944be0c65eef7b3ebf740eb132d573a52e811a02f0031b9f1ae077a50696"}, + {file = "replicate-1.0.4-py3-none-any.whl", hash = "sha256:f568f6271ff715067901b6094c23c37373bbcfd7de0ff9b85e9c9ead567e09e7"}, + {file = "replicate-1.0.4.tar.gz", hash = "sha256:f718601863ef1f419aa7dcdab1ea8770ba5489b571b86edf840cd506d68758ef"}, ] [package.dependencies] +httpx = ">=0.21.0,<1" packaging = "*" -pydantic = ">1" -requests = ">2" - -[package.extras] -dev = ["black", "mypy", "pytest", "responses", "ruff"] +pydantic = ">1.10.7" +typing_extensions = ">=4.5.0" [[package]] name = "requests" @@ -4330,6 +4642,7 @@ version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" +groups = ["main", "typing"] files = [ {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, @@ -4351,6 +4664,7 @@ version = "2.0.0" description = "OAuthlib authentication support for Requests." optional = false python-versions = ">=3.4" +groups = ["main"] files = [ {file = "requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9"}, {file = "requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36"}, @@ -4369,6 +4683,7 @@ version = "1.0.0" description = "A utility belt for advanced users of python-requests" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main"] files = [ {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"}, {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}, @@ -4383,6 +4698,7 @@ version = "0.22.3" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "rpds_py-0.22.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:6c7b99ca52c2c1752b544e310101b98a659b720b21db00e65edca34483259967"}, {file = "rpds_py-0.22.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:be2eb3f2495ba669d2a985f9b426c1797b7d48d6963899276d22f23e33d47e37"}, @@ -4495,6 +4811,7 @@ version = "4.9" description = "Pure-Python RSA implementation" optional = false python-versions = ">=3.6,<4" +groups = ["main"] files = [ {file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"}, {file = "rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"}, @@ -4505,28 +4822,30 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.4.10" +version = "0.9.9" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" -files = [ - {file = "ruff-0.4.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5c2c4d0859305ac5a16310eec40e4e9a9dec5dcdfbe92697acd99624e8638dac"}, - {file = "ruff-0.4.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a79489607d1495685cdd911a323a35871abfb7a95d4f98fc6f85e799227ac46e"}, - {file = "ruff-0.4.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1dd1681dfa90a41b8376a61af05cc4dc5ff32c8f14f5fe20dba9ff5deb80cd6"}, - {file = "ruff-0.4.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c75c53bb79d71310dc79fb69eb4902fba804a81f374bc86a9b117a8d077a1784"}, - {file = "ruff-0.4.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18238c80ee3d9100d3535d8eb15a59c4a0753b45cc55f8bf38f38d6a597b9739"}, - {file = "ruff-0.4.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d8f71885bce242da344989cae08e263de29752f094233f932d4f5cfb4ef36a81"}, - {file = "ruff-0.4.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:330421543bd3222cdfec481e8ff3460e8702ed1e58b494cf9d9e4bf90db52b9d"}, - {file = "ruff-0.4.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e9b6fb3a37b772628415b00c4fc892f97954275394ed611056a4b8a2631365e"}, - {file = "ruff-0.4.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f54c481b39a762d48f64d97351048e842861c6662d63ec599f67d515cb417f6"}, - {file = "ruff-0.4.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:67fe086b433b965c22de0b4259ddfe6fa541c95bf418499bedb9ad5fb8d1c631"}, - {file = "ruff-0.4.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:acfaaab59543382085f9eb51f8e87bac26bf96b164839955f244d07125a982ef"}, - {file = "ruff-0.4.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3cea07079962b2941244191569cf3a05541477286f5cafea638cd3aa94b56815"}, - {file = "ruff-0.4.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:338a64ef0748f8c3a80d7f05785930f7965d71ca260904a9321d13be24b79695"}, - {file = "ruff-0.4.10-py3-none-win32.whl", hash = "sha256:ffe3cd2f89cb54561c62e5fa20e8f182c0a444934bf430515a4b422f1ab7b7ca"}, - {file = "ruff-0.4.10-py3-none-win_amd64.whl", hash = "sha256:67f67cef43c55ffc8cc59e8e0b97e9e60b4837c8f21e8ab5ffd5d66e196e25f7"}, - {file = "ruff-0.4.10-py3-none-win_arm64.whl", hash = "sha256:dd1fcee327c20addac7916ca4e2653fbbf2e8388d8a6477ce5b4e986b68ae6c0"}, - {file = "ruff-0.4.10.tar.gz", hash = "sha256:3aa4f2bc388a30d346c56524f7cacca85945ba124945fe489952aadb6b5cd804"}, +groups = ["main"] +files = [ + {file = "ruff-0.9.9-py3-none-linux_armv6l.whl", hash = "sha256:628abb5ea10345e53dff55b167595a159d3e174d6720bf19761f5e467e68d367"}, + {file = "ruff-0.9.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b6cd1428e834b35d7493354723543b28cc11dc14d1ce19b685f6e68e07c05ec7"}, + {file = "ruff-0.9.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5ee162652869120ad260670706f3cd36cd3f32b0c651f02b6da142652c54941d"}, + {file = "ruff-0.9.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3aa0f6b75082c9be1ec5a1db78c6d4b02e2375c3068438241dc19c7c306cc61a"}, + {file = "ruff-0.9.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:584cc66e89fb5f80f84b05133dd677a17cdd86901d6479712c96597a3f28e7fe"}, + {file = "ruff-0.9.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abf3369325761a35aba75cd5c55ba1b5eb17d772f12ab168fbfac54be85cf18c"}, + {file = "ruff-0.9.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:3403a53a32a90ce929aa2f758542aca9234befa133e29f4933dcef28a24317be"}, + {file = "ruff-0.9.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:18454e7fa4e4d72cffe28a37cf6a73cb2594f81ec9f4eca31a0aaa9ccdfb1590"}, + {file = "ruff-0.9.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fadfe2c88724c9617339f62319ed40dcdadadf2888d5afb88bf3adee7b35bfb"}, + {file = "ruff-0.9.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6df104d08c442a1aabcfd254279b8cc1e2cbf41a605aa3e26610ba1ec4acf0b0"}, + {file = "ruff-0.9.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d7c62939daf5b2a15af48abbd23bea1efdd38c312d6e7c4cedf5a24e03207e17"}, + {file = "ruff-0.9.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9494ba82a37a4b81b6a798076e4a3251c13243fc37967e998efe4cce58c8a8d1"}, + {file = "ruff-0.9.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:4efd7a96ed6d36ef011ae798bf794c5501a514be369296c672dab7921087fa57"}, + {file = "ruff-0.9.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ab90a7944c5a1296f3ecb08d1cbf8c2da34c7e68114b1271a431a3ad30cb660e"}, + {file = "ruff-0.9.9-py3-none-win32.whl", hash = "sha256:6b4c376d929c25ecd6d87e182a230fa4377b8e5125a4ff52d506ee8c087153c1"}, + {file = "ruff-0.9.9-py3-none-win_amd64.whl", hash = "sha256:837982ea24091d4c1700ddb2f63b7070e5baec508e43b01de013dc7eff974ff1"}, + {file = "ruff-0.9.9-py3-none-win_arm64.whl", hash = "sha256:3ac78f127517209fe6d96ab00f3ba97cafe38718b23b1db3e96d8b2d39e37ddf"}, + {file = "ruff-0.9.9.tar.gz", hash = "sha256:0062ed13f22173e85f8f7056f9a24016e692efeea8704d1a5e8011b8aa850933"}, ] [[package]] @@ -4535,6 +4854,7 @@ version = "2.20.0" description = "Python client for Sentry (https://sentry.io)" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "sentry_sdk-2.20.0-py2.py3-none-any.whl", hash = "sha256:c359a1edf950eb5e80cffd7d9111f3dbeef57994cb4415df37d39fda2cf22364"}, {file = "sentry_sdk-2.20.0.tar.gz", hash = "sha256:afa82713a92facf847df3c6f63cec71eb488d826a50965def3d7722aa6f0fdab"}, @@ -4591,6 +4911,7 @@ version = "24.2.0" description = "Service identity verification for pyOpenSSL & cryptography." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "service_identity-24.2.0-py3-none-any.whl", hash = "sha256:6b047fbd8a84fd0bb0d55ebce4031e400562b9196e1e0d3e0fe2b8a59f6d4a85"}, {file = "service_identity-24.2.0.tar.gz", hash = "sha256:b8683ba13f0d39c6cd5d625d2c5f65421d6d707b013b375c355751557cbe8e09"}, @@ -4615,6 +4936,7 @@ version = "75.8.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "setuptools-75.8.0-py3-none-any.whl", hash = "sha256:e3982f444617239225d675215d51f6ba05f845d4eec313da4418fdbb56fb27e3"}, {file = "setuptools-75.8.0.tar.gz", hash = "sha256:c5afc8f407c626b8313a86e10311dd3f661c6cd9c09d4bf8c15c0e11f9f2b0e6"}, @@ -4635,6 +4957,7 @@ version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main", "test"] files = [ {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, @@ -4646,6 +4969,7 @@ version = "0.6.0" description = "Snapshot testing for pytest, unittest, Django, and Nose" optional = false python-versions = "*" +groups = ["test"] files = [ {file = "snapshottest-0.6.0-py2.py3-none-any.whl", hash = "sha256:9b177cffe0870c589df8ddbee0a770149c5474b251955bdbde58b7f32a4ec429"}, {file = "snapshottest-0.6.0.tar.gz", hash = "sha256:bbcaf81d92d8e330042e5c928e13d9f035e99e91b314fe55fda949c2f17b653c"}, @@ -4667,6 +4991,7 @@ version = "1.3.1" description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, @@ -4678,6 +5003,7 @@ version = "5.4.2" description = "Python Social Authentication, Django integration." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "social-auth-app-django-5.4.2.tar.gz", hash = "sha256:c8832c6cf13da6ad76f5613bcda2647d89ae7cfbc5217fadd13477a3406feaa8"}, {file = "social_auth_app_django-5.4.2-py3-none-any.whl", hash = "sha256:0c041a31707921aef9a930f143183c65d8c7b364381364a50f3f7c6fcc9d62f6"}, @@ -4693,6 +5019,7 @@ version = "4.5.4" description = "Python social authentication made simple." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "social-auth-core-4.5.4.tar.gz", hash = "sha256:d3dbeb0999ffd0e68aa4bd73f2ac698a18133fd11b3fc890e1366f18c8889fac"}, {file = "social_auth_core-4.5.4-py3-none-any.whl", hash = "sha256:33cf970a623c442376f9d4a86fb187579e4438649daa5b5be993d05e74d7b2db"}, @@ -4719,6 +5046,7 @@ version = "2.0.37" description = "Database Abstraction Library" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "SQLAlchemy-2.0.37-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:da36c3b0e891808a7542c5c89f224520b9a16c7f5e4d6a1156955605e54aef0e"}, {file = "SQLAlchemy-2.0.37-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e7402ff96e2b073a98ef6d6142796426d705addd27b9d26c3b32dbaa06d7d069"}, @@ -4814,6 +5142,7 @@ version = "0.5.3" description = "A non-validating SQL parser." optional = false python-versions = ">=3.8" +groups = ["main", "typing"] files = [ {file = "sqlparse-0.5.3-py3-none-any.whl", hash = "sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca"}, {file = "sqlparse-0.5.3.tar.gz", hash = "sha256:09f67787f56a0b16ecdbde1bfc7f5d9c3371ca683cfeaa8e6ff60b4807ec9272"}, @@ -4829,6 +5158,7 @@ version = "3.7.0" description = "Format agnostic tabular data library (XLS, JSON, YAML, CSV, etc.)" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "tablib-3.7.0-py3-none-any.whl", hash = "sha256:9a6930037cfe0f782377963ca3f2b1dae3fd4cdbf0883848f22f1447e7bb718b"}, {file = "tablib-3.7.0.tar.gz", hash = "sha256:f9db84ed398df5109bd69c11d46613d16cc572fb9ad3213f10d95e2b5f12c18e"}, @@ -4849,6 +5179,7 @@ version = "8.5.0" description = "Retry code until it succeeds" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "tenacity-8.5.0-py3-none-any.whl", hash = "sha256:b594c2a5945830c267ce6b79a166228323ed52718f30302c1359836112346687"}, {file = "tenacity-8.5.0.tar.gz", hash = "sha256:8bc6c0c8a09b31e6cad13c47afbed1a567518250a9a171418582ed8d9c20ca78"}, @@ -4864,6 +5195,7 @@ version = "2.5.0" description = "ANSI color formatting for output in terminal" optional = false python-versions = ">=3.9" +groups = ["test"] files = [ {file = "termcolor-2.5.0-py3-none-any.whl", hash = "sha256:37b17b5fc1e604945c2642c872a3764b5d547a48009871aea3edd3afa180afb8"}, {file = "termcolor-2.5.0.tar.gz", hash = "sha256:998d8d27da6d48442e8e1f016119076b690d962507531df4890fcd2db2ef8a6f"}, @@ -4874,47 +5206,43 @@ tests = ["pytest", "pytest-cov"] [[package]] name = "tiktoken" -version = "0.5.2" +version = "0.9.0" description = "tiktoken is a fast BPE tokeniser for use with OpenAI's models" optional = false -python-versions = ">=3.8" -files = [ - {file = "tiktoken-0.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8c4e654282ef05ec1bd06ead22141a9a1687991cef2c6a81bdd1284301abc71d"}, - {file = "tiktoken-0.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7b3134aa24319f42c27718c6967f3c1916a38a715a0fa73d33717ba121231307"}, - {file = "tiktoken-0.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6092e6e77730929c8c6a51bb0d7cfdf1b72b63c4d033d6258d1f2ee81052e9e5"}, - {file = "tiktoken-0.5.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72ad8ae2a747622efae75837abba59be6c15a8f31b4ac3c6156bc56ec7a8e631"}, - {file = "tiktoken-0.5.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:51cba7c8711afa0b885445f0637f0fcc366740798c40b981f08c5f984e02c9d1"}, - {file = "tiktoken-0.5.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3d8c7d2c9313f8e92e987d585ee2ba0f7c40a0de84f4805b093b634f792124f5"}, - {file = "tiktoken-0.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:692eca18c5fd8d1e0dde767f895c17686faaa102f37640e884eecb6854e7cca7"}, - {file = "tiktoken-0.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:138d173abbf1ec75863ad68ca289d4da30caa3245f3c8d4bfb274c4d629a2f77"}, - {file = "tiktoken-0.5.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7388fdd684690973fdc450b47dfd24d7f0cbe658f58a576169baef5ae4658607"}, - {file = "tiktoken-0.5.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a114391790113bcff670c70c24e166a841f7ea8f47ee2fe0e71e08b49d0bf2d4"}, - {file = "tiktoken-0.5.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca96f001e69f6859dd52926d950cfcc610480e920e576183497ab954e645e6ac"}, - {file = "tiktoken-0.5.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:15fed1dd88e30dfadcdd8e53a8927f04e1f6f81ad08a5ca824858a593ab476c7"}, - {file = "tiktoken-0.5.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:93f8e692db5756f7ea8cb0cfca34638316dcf0841fb8469de8ed7f6a015ba0b0"}, - {file = "tiktoken-0.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:bcae1c4c92df2ffc4fe9f475bf8148dbb0ee2404743168bbeb9dcc4b79dc1fdd"}, - {file = "tiktoken-0.5.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b76a1e17d4eb4357d00f0622d9a48ffbb23401dcf36f9716d9bd9c8e79d421aa"}, - {file = "tiktoken-0.5.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:01d8b171bb5df4035580bc26d4f5339a6fd58d06f069091899d4a798ea279d3e"}, - {file = "tiktoken-0.5.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42adf7d4fb1ed8de6e0ff2e794a6a15005f056a0d83d22d1d6755a39bffd9e7f"}, - {file = "tiktoken-0.5.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c3f894dbe0adb44609f3d532b8ea10820d61fdcb288b325a458dfc60fefb7db"}, - {file = "tiktoken-0.5.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:58ccfddb4e62f0df974e8f7e34a667981d9bb553a811256e617731bf1d007d19"}, - {file = "tiktoken-0.5.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58902a8bad2de4268c2a701f1c844d22bfa3cbcc485b10e8e3e28a050179330b"}, - {file = "tiktoken-0.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:5e39257826d0647fcac403d8fa0a474b30d02ec8ffc012cfaf13083e9b5e82c5"}, - {file = "tiktoken-0.5.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8bde3b0fbf09a23072d39c1ede0e0821f759b4fa254a5f00078909158e90ae1f"}, - {file = "tiktoken-0.5.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2ddee082dcf1231ccf3a591d234935e6acf3e82ee28521fe99af9630bc8d2a60"}, - {file = "tiktoken-0.5.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35c057a6a4e777b5966a7540481a75a31429fc1cb4c9da87b71c8b75b5143037"}, - {file = "tiktoken-0.5.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c4a049b87e28f1dc60509f8eb7790bc8d11f9a70d99b9dd18dfdd81a084ffe6"}, - {file = "tiktoken-0.5.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5bf5ce759089f4f6521ea6ed89d8f988f7b396e9f4afb503b945f5c949c6bec2"}, - {file = "tiktoken-0.5.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0c964f554af1a96884e01188f480dad3fc224c4bbcf7af75d4b74c4b74ae0125"}, - {file = "tiktoken-0.5.2-cp38-cp38-win_amd64.whl", hash = "sha256:368dd5726d2e8788e47ea04f32e20f72a2012a8a67af5b0b003d1e059f1d30a3"}, - {file = "tiktoken-0.5.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a2deef9115b8cd55536c0a02c0203512f8deb2447f41585e6d929a0b878a0dd2"}, - {file = "tiktoken-0.5.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2ed7d380195affbf886e2f8b92b14edfe13f4768ff5fc8de315adba5b773815e"}, - {file = "tiktoken-0.5.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c76fce01309c8140ffe15eb34ded2bb94789614b7d1d09e206838fc173776a18"}, - {file = "tiktoken-0.5.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60a5654d6a2e2d152637dd9a880b4482267dfc8a86ccf3ab1cec31a8c76bfae8"}, - {file = "tiktoken-0.5.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:41d4d3228e051b779245a8ddd21d4336f8975563e92375662f42d05a19bdff41"}, - {file = "tiktoken-0.5.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a5c1cdec2c92fcde8c17a50814b525ae6a88e8e5b02030dc120b76e11db93f13"}, - {file = "tiktoken-0.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:84ddb36faedb448a50b246e13d1b6ee3437f60b7169b723a4b2abad75e914f3e"}, - {file = "tiktoken-0.5.2.tar.gz", hash = "sha256:f54c581f134a8ea96ce2023ab221d4d4d81ab614efa0b2fbce926387deb56c80"}, +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "tiktoken-0.9.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:586c16358138b96ea804c034b8acf3f5d3f0258bd2bc3b0227af4af5d622e382"}, + {file = "tiktoken-0.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d9c59ccc528c6c5dd51820b3474402f69d9a9e1d656226848ad68a8d5b2e5108"}, + {file = "tiktoken-0.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0968d5beeafbca2a72c595e8385a1a1f8af58feaebb02b227229b69ca5357fd"}, + {file = "tiktoken-0.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92a5fb085a6a3b7350b8fc838baf493317ca0e17bd95e8642f95fc69ecfed1de"}, + {file = "tiktoken-0.9.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:15a2752dea63d93b0332fb0ddb05dd909371ededa145fe6a3242f46724fa7990"}, + {file = "tiktoken-0.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:26113fec3bd7a352e4b33dbaf1bd8948de2507e30bd95a44e2b1156647bc01b4"}, + {file = "tiktoken-0.9.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:f32cc56168eac4851109e9b5d327637f15fd662aa30dd79f964b7c39fbadd26e"}, + {file = "tiktoken-0.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:45556bc41241e5294063508caf901bf92ba52d8ef9222023f83d2483a3055348"}, + {file = "tiktoken-0.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03935988a91d6d3216e2ec7c645afbb3d870b37bcb67ada1943ec48678e7ee33"}, + {file = "tiktoken-0.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b3d80aad8d2c6b9238fc1a5524542087c52b860b10cbf952429ffb714bc1136"}, + {file = "tiktoken-0.9.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b2a21133be05dc116b1d0372af051cd2c6aa1d2188250c9b553f9fa49301b336"}, + {file = "tiktoken-0.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:11a20e67fdf58b0e2dea7b8654a288e481bb4fc0289d3ad21291f8d0849915fb"}, + {file = "tiktoken-0.9.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e88f121c1c22b726649ce67c089b90ddda8b9662545a8aeb03cfef15967ddd03"}, + {file = "tiktoken-0.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a6600660f2f72369acb13a57fb3e212434ed38b045fd8cc6cdd74947b4b5d210"}, + {file = "tiktoken-0.9.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95e811743b5dfa74f4b227927ed86cbc57cad4df859cb3b643be797914e41794"}, + {file = "tiktoken-0.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99376e1370d59bcf6935c933cb9ba64adc29033b7e73f5f7569f3aad86552b22"}, + {file = "tiktoken-0.9.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:badb947c32739fb6ddde173e14885fb3de4d32ab9d8c591cbd013c22b4c31dd2"}, + {file = "tiktoken-0.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:5a62d7a25225bafed786a524c1b9f0910a1128f4232615bf3f8257a73aaa3b16"}, + {file = "tiktoken-0.9.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2b0e8e05a26eda1249e824156d537015480af7ae222ccb798e5234ae0285dbdb"}, + {file = "tiktoken-0.9.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:27d457f096f87685195eea0165a1807fae87b97b2161fe8c9b1df5bd74ca6f63"}, + {file = "tiktoken-0.9.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cf8ded49cddf825390e36dd1ad35cd49589e8161fdcb52aa25f0583e90a3e01"}, + {file = "tiktoken-0.9.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc156cb314119a8bb9748257a2eaebd5cc0753b6cb491d26694ed42fc7cb3139"}, + {file = "tiktoken-0.9.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cd69372e8c9dd761f0ab873112aba55a0e3e506332dd9f7522ca466e817b1b7a"}, + {file = "tiktoken-0.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:5ea0edb6f83dc56d794723286215918c1cde03712cbbafa0348b33448faf5b95"}, + {file = "tiktoken-0.9.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c6386ca815e7d96ef5b4ac61e0048cd32ca5a92d5781255e13b31381d28667dc"}, + {file = "tiktoken-0.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:75f6d5db5bc2c6274b674ceab1615c1778e6416b14705827d19b40e6355f03e0"}, + {file = "tiktoken-0.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e15b16f61e6f4625a57a36496d28dd182a8a60ec20a534c5343ba3cafa156ac7"}, + {file = "tiktoken-0.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebcec91babf21297022882344c3f7d9eed855931466c3311b1ad6b64befb3df"}, + {file = "tiktoken-0.9.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e5fd49e7799579240f03913447c0cdfa1129625ebd5ac440787afc4345990427"}, + {file = "tiktoken-0.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:26242ca9dc8b58e875ff4ca078b9a94d2f0813e6a535dcd2205df5d49d927cc7"}, + {file = "tiktoken-0.9.0.tar.gz", hash = "sha256:d02a5ca6a938e0490e1ff957bc48c8b078c88cb83977be1625b1fd8aac792c5d"}, ] [package.dependencies] @@ -4930,6 +5258,7 @@ version = "4.67.1" description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"}, {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"}, @@ -4951,6 +5280,7 @@ version = "24.11.0" description = "An asynchronous networking framework written in Python" optional = false python-versions = ">=3.8.0" +groups = ["main"] files = [ {file = "twisted-24.11.0-py3-none-any.whl", hash = "sha256:fe403076c71f04d5d2d789a755b687c5637ec3bcd3b2b8252d76f2ba65f54261"}, {file = "twisted-24.11.0.tar.gz", hash = "sha256:695d0556d5ec579dcc464d2856b634880ed1319f45b10d19043f2b57eb0115b5"}, @@ -4989,6 +5319,7 @@ version = "23.1.1" description = "Compatibility API between asyncio/Twisted/Trollius" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "txaio-23.1.1-py2.py3-none-any.whl", hash = "sha256:aaea42f8aad50e0ecfb976130ada140797e9dcb85fad2cf72b0f37f8cefcb490"}, {file = "txaio-23.1.1.tar.gz", hash = "sha256:f9a9216e976e5e3246dfd112ad7ad55ca915606b60b84a757ac769bd404ff704"}, @@ -5005,6 +5336,7 @@ version = "10.2.0.20240822" description = "Typing stubs for Pillow" optional = false python-versions = ">=3.8" +groups = ["typing"] files = [ {file = "types-Pillow-10.2.0.20240822.tar.gz", hash = "sha256:559fb52a2ef991c326e4a0d20accb3bb63a7ba8d40eb493e0ecb0310ba52f0d3"}, {file = "types_Pillow-10.2.0.20240822-py3-none-any.whl", hash = "sha256:d9dab025aba07aeb12fd50a6799d4eac52a9603488eca09d7662543983f16c5d"}, @@ -5016,6 +5348,7 @@ version = "2.9.0.20241206" description = "Typing stubs for python-dateutil" optional = false python-versions = ">=3.8" +groups = ["typing"] files = [ {file = "types_python_dateutil-2.9.0.20241206-py3-none-any.whl", hash = "sha256:e248a4bc70a486d3e3ec84d0dc30eec3a5f979d6e7ee4123ae043eedbb987f53"}, {file = "types_python_dateutil-2.9.0.20241206.tar.gz", hash = "sha256:18f493414c26ffba692a72369fea7a154c502646301ebfe3d56a04b3767284cb"}, @@ -5027,6 +5360,7 @@ version = "2024.2.0.20241221" description = "Typing stubs for pytz" optional = false python-versions = ">=3.8" +groups = ["typing"] files = [ {file = "types_pytz-2024.2.0.20241221-py3-none-any.whl", hash = "sha256:8fc03195329c43637ed4f593663df721fef919b60a969066e22606edf0b53ad5"}, {file = "types_pytz-2024.2.0.20241221.tar.gz", hash = "sha256:06d7cde9613e9f7504766a0554a270c369434b50e00975b3a4a0f6eed0f2c1a9"}, @@ -5038,6 +5372,7 @@ version = "6.0.12.20241230" description = "Typing stubs for PyYAML" optional = false python-versions = ">=3.8" +groups = ["typing"] files = [ {file = "types_PyYAML-6.0.12.20241230-py3-none-any.whl", hash = "sha256:fa4d32565219b68e6dee5f67534c722e53c00d1cfc09c435ef04d7353e1e96e6"}, {file = "types_pyyaml-6.0.12.20241230.tar.gz", hash = "sha256:7f07622dbd34bb9c8b264fe860a17e0efcad00d50b5f27e93984909d9363498c"}, @@ -5049,6 +5384,7 @@ version = "2.32.0.20241016" description = "Typing stubs for requests" optional = false python-versions = ">=3.8" +groups = ["main", "typing"] files = [ {file = "types-requests-2.32.0.20241016.tar.gz", hash = "sha256:0d9cad2f27515d0e3e3da7134a1b6f28fb97129d86b867f24d9c726452634d95"}, {file = "types_requests-2.32.0.20241016-py3-none-any.whl", hash = "sha256:4195d62d6d3e043a4eaaf08ff8a62184584d2e8684e9d2aa178c7915a7da3747"}, @@ -5063,6 +5399,7 @@ version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" +groups = ["main", "test", "typing"] files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, @@ -5074,6 +5411,7 @@ version = "0.9.0" description = "Runtime inspection utilities for typing module." optional = false python-versions = "*" +groups = ["main"] 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"}, @@ -5089,10 +5427,12 @@ version = "2024.2" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" +groups = ["main", "typing"] files = [ {file = "tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"}, {file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"}, ] +markers = {typing = "sys_platform == \"win32\""} [[package]] name = "uritemplate" @@ -5100,6 +5440,7 @@ version = "4.1.1" description = "Implementation of RFC 6570 URI Templates" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "uritemplate-4.1.1-py2.py3-none-any.whl", hash = "sha256:830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e"}, {file = "uritemplate-4.1.1.tar.gz", hash = "sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0"}, @@ -5111,6 +5452,7 @@ version = "2.3.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" +groups = ["main", "typing"] files = [ {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, @@ -5128,6 +5470,7 @@ version = "0.34.0" description = "The lightning-fast ASGI server." optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "uvicorn-0.34.0-py3-none-any.whl", hash = "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4"}, {file = "uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9"}, @@ -5146,6 +5489,7 @@ version = "0.21.0" description = "Fast implementation of asyncio event loop on top of libuv" optional = false python-versions = ">=3.8.0" +groups = ["main"] files = [ {file = "uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f"}, {file = "uvloop-0.21.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:196274f2adb9689a289ad7d65700d37df0c0930fd8e4e743fa4834e850d7719d"}, @@ -5197,6 +5541,7 @@ version = "5.1.0" description = "Python promises." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "vine-5.1.0-py3-none-any.whl", hash = "sha256:40fdf3c48b2cfe1c38a49e9ae2da6fda88e4794c810050a728bd7413811fb1dc"}, {file = "vine-5.1.0.tar.gz", hash = "sha256:8b62e981d35c41049211cf62a0a1242d8c1ee9bd15bb196ce38aefd6799e61e0"}, @@ -5208,6 +5553,7 @@ version = "1.1.0" description = "Python extension to run WebAssembly binaries" optional = false python-versions = "*" +groups = ["test"] files = [ {file = "wasmer-1.1.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:c2af4b907ae2dabcac41e316e811d5937c93adf1f8b05c5d49427f8ce0f37630"}, {file = "wasmer-1.1.0-cp310-cp310-manylinux_2_24_x86_64.whl", hash = "sha256:ab1ae980021e5ec0bf0c6cdd3b979b1d15a5f3eb2b8a32da8dcb1156e4a1e484"}, @@ -5231,6 +5577,7 @@ version = "1.1.0" description = "The Cranelift compiler for the `wasmer` package (to compile WebAssembly module)" optional = false python-versions = "*" +groups = ["test"] files = [ {file = "wasmer_compiler_cranelift-1.1.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:9869910179f39696a020edc5689f7759257ac1cce569a7a0fcf340c59788baad"}, {file = "wasmer_compiler_cranelift-1.1.0-cp310-cp310-manylinux_2_24_x86_64.whl", hash = "sha256:405546ee864ac158a4107f374dfbb1c8d6cfb189829bdcd13050143a4bd98f28"}, @@ -5254,6 +5601,7 @@ version = "0.2.13" description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, @@ -5265,6 +5613,7 @@ version = "1.17.2" description = "Module for decorators, wrappers and monkey patching." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3d57c572081fed831ad2d26fd430d565b76aa277ed1d30ff4d40670b1c0dd984"}, {file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b5e251054542ae57ac7f3fba5d10bfff615b6c2fb09abeb37d2f1463f841ae22"}, @@ -5353,6 +5702,7 @@ version = "1.2.0" description = "WebSockets state-machine based protocol implementation" optional = false python-versions = ">=3.7.0" +groups = ["main"] files = [ {file = "wsproto-1.2.0-py3-none-any.whl", hash = "sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736"}, {file = "wsproto-1.2.0.tar.gz", hash = "sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065"}, @@ -5367,6 +5717,7 @@ version = "1.18.3" description = "Yet another URL library" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34"}, {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7"}, @@ -5463,6 +5814,7 @@ version = "2.5.0" description = "YooKassa API SDK Python Library" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "yookassa-2.5.0.tar.gz", hash = "sha256:5ddb279d6e867c74b66549e3096196606b5f04bf4927bde2513072b7a08ee3ff"}, ] @@ -5480,6 +5832,7 @@ version = "5.0" description = "Very basic event publishing system" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "zope.event-5.0-py3-none-any.whl", hash = "sha256:2832e95014f4db26c47a13fdaef84cef2f4df37e66b59d8f1f4a8f319a632c26"}, {file = "zope.event-5.0.tar.gz", hash = "sha256:bac440d8d9891b4068e2b5a2c5e2c9765a9df762944bda6955f96bb9b91e67cd"}, @@ -5498,6 +5851,7 @@ version = "7.2" description = "Interfaces for Python" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "zope.interface-7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ce290e62229964715f1011c3dbeab7a4a1e4971fd6f31324c4519464473ef9f2"}, {file = "zope.interface-7.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:05b910a5afe03256b58ab2ba6288960a2892dfeef01336dc4be6f1b9ed02ab0a"}, @@ -5547,6 +5901,6 @@ test = ["coverage[toml]", "zope.event", "zope.testing"] testing = ["coverage[toml]", "zope.event", "zope.testing"] [metadata] -lock-version = "2.0" +lock-version = "2.1" python-versions = "^3.12" -content-hash = "374eefaf72602369e3ec22a0277f3407a6387f6d20ec4a47be8c440f72729f74" +content-hash = "11aef76704403641d1d4f24a0e6525cb38c7fcf331df77983fd1da009dd8116d" @@ -9,7 +9,6 @@ package-mode = false [tool.poetry.dependencies] python = "^3.12" -replicate = "^0.10.0" deepl = "^1.15.0" django = "5.0.*" django-cors-headers = "^4.2.0" @@ -32,10 +31,7 @@ openpyxl = "^3.1.2" pypdf2 = "^3.0.1" python-docx = "^1.1.0" mutagen = "^1.47.0" -langchain = "^0.1.0" -langchain-openai = "^0.0.2" pillow = "^10.2.0" -langchain-google-genai = "^0.0.9" langserve = {extras = ["client"], version = "^0.0.46"} django-ordered-model = "^3.7.4" langchainhub = "^0.1.15" @@ -57,7 +53,16 @@ httptools = "^0.6.4" uvloop = "^0.21.0" wsproto = "^1.2.0" channels-redis = "^4.2.1" -tiktoken = "<0.6.0" +langchain = "^0.3.19" +langchain-openai = "^0.3.6" +langchain-google-genai = "^2.0.9" +tiktoken = "^0.9.0" +langchain-community = "^0.3.17" +docx2txt = "^0.8" +pypandoc = "^1.15" +faiss-cpu = "^1.10.0" +replicate = "^1.0.4" +ruff = "^0.9.9" [tool.poetry.group.test.dependencies] @@ -73,10 +78,6 @@ pytest-factoryboy = "^2.5.1" pytest-cov = "^4.1.0" -[tool.poetry.group.lint.dependencies] -ruff = "^0.4.8" - - [tool.poetry.group.typing.dependencies] mypy = "^1.5.1" django-stubs = "^4.2.4" @@ -1,3 +1,6 @@ +# implement caching (warning: this feature needs to setup only own runners with enabled containerd-snapshotters feature) +# implement docker compose generic structures for inheritance of stack and compose files + services: app: image: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA @@ -14,9 +17,10 @@ services: python manage.py compilemessages python -m uvicorn --host 0.0.0.0 --workers 8 --timeout-keep-alive 300 --ws wsproto --loop uvloop --http httptools --lifespan off --log-level info backend.asgi:application networks: + - default - infrastructure deploy: - replicas: 2 + replicas: 1 update_config: parallelism: 1 delay: 10s @@ -42,16 +46,34 @@ services: - traefik.http.middlewares.backend.redirectscheme.permanent=true env_file: - $ENV - depends_on: - - cache-mdb - - celery-mdb - + + migrator: + image: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA + build: + context: . + dockerfile: Dockerfile + deploy: + replicas: 1 + restart_policy: + condition: on-failure + delay: 5s + max_attempts: 3 + window: 30s + command: + - /bin/sh + - -c + - python manage.py migrate + env_file: + - $ENV + celery: image: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA build: context: . dockerfile: Dockerfile command: celery -A backend worker -l INFO --concurrency 8 + networks: + - default deploy: replicas: 1 update_config: @@ -70,8 +92,6 @@ services: - $ENV environment: - C_FORCE_ROOT=true - depends_on: - - celery-mdb celery_beat: image: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA @@ -79,6 +99,8 @@ services: context: . dockerfile: Dockerfile command: celery -A backend beat -l INFO + networks: + - default deploy: replicas: 1 update_config: @@ -95,8 +117,6 @@ services: - node.role == worker env_file: - $ENV - depends_on: - - celery-mdb static-server: image: $CI_REGISTRY_IMAGE/static-server:$CI_COMMIT_SHA @@ -141,6 +161,8 @@ services: celery-mdb: image: redis:alpine + networks: + - default deploy: replicas: 1 restart_policy: @@ -169,6 +191,7 @@ networks: infrastructure: name: infrastructure external: true + default: {} volumes: static: