From 11e071d0e5994a60465ee9a71831ddf525dda414 Mon Sep 17 00:00:00 2001 From: Rasul Kireev Date: Sat, 27 Dec 2025 23:35:09 +0300 Subject: [PATCH 1/3] init --- README.md | 3 +- core/agents/blog_post_outline_agent.py | 98 + core/agents/research_link_summary_agent.py | 90 + core/agents/schemas.py | 13 + core/content_generator/__init__.py | 7 + core/content_generator/pipeline.py | 598 ++++++ core/content_generator/tasks.py | 91 + core/content_generator/utils.py | 15 + ...eratedblogpostresearchquestion_and_more.py | 95 + ...edblogpostresearchlink_content_and_more.py | 44 + core/models.py | 177 +- core/tasks.py | 12 + poetry.lock | 1871 ++++++++++------- pyproject.toml | 1 + requirements.txt | 162 +- .../inspect_blog_post_title_suggestion.py | 168 ++ tuxseo/settings.py | 3 + 17 files changed, 2541 insertions(+), 907 deletions(-) create mode 100644 core/agents/blog_post_outline_agent.py create mode 100644 core/agents/research_link_summary_agent.py create mode 100644 core/content_generator/__init__.py create mode 100644 core/content_generator/pipeline.py create mode 100644 core/content_generator/tasks.py create mode 100644 core/content_generator/utils.py create mode 100644 core/migrations/0050_backlink_generatedblogpostresearchquestion_and_more.py create mode 100644 core/migrations/0051_rename_markdown_content_generatedblogpostresearchlink_content_and_more.py create mode 100644 snippets/inspect_blog_post_title_suggestion.py diff --git a/README.md b/README.md index 6b77932..3c8fae6 100644 --- a/README.md +++ b/README.md @@ -39,9 +39,8 @@ [![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://render.com/deploy?repo=https://github.com/rasulkireev/tuxseo) The only required env vars are: -- OPENAI_API_KEY -- TAVILY_API_KEY - GEMINI_API_KEY +- EXA_API_KEY - PERPLEXITY_API_KEY - JINA_READER_API_KEY - KEYWORDS_EVERYWHERE_API_KEY diff --git a/core/agents/blog_post_outline_agent.py b/core/agents/blog_post_outline_agent.py new file mode 100644 index 0000000..1f15e44 --- /dev/null +++ b/core/agents/blog_post_outline_agent.py @@ -0,0 +1,98 @@ +from __future__ import annotations + +from pydantic import BaseModel, Field +from pydantic_ai import Agent + +from core.agents.schemas import BlogPostGenerationContext +from core.agents.system_prompts import ( + add_language_specification, + add_project_details, + add_target_keywords, + add_title_details, + add_todays_date, +) +from core.choices import get_default_ai_model + + +class BlogPostOutlineSection(BaseModel): + title: str = Field(description="Section title (use plain text, no markdown prefixes)") + + +class BlogPostOutline(BaseModel): + sections: list[BlogPostOutlineSection] = Field( + description=( + "Ordered list of 4-8 section titles that will be used as H2 (##) headers in the blog post." # noqa: E501 + ) + ) + + +BLOG_POST_OUTLINE_SYSTEM_PROMPT = """ +You are an expert content strategist. + +Your task: propose only the middle-section outline for the blog post. + +Requirements: +- Generate 4-8 main topics that will be used as H2 (##) sections. +- Do NOT include markdown symbols in section titles (no leading #, ##, -, etc.). +- Keep titles short and descriptive. +- Do NOT include 'Introduction' or 'Conclusion' yet. + +Output must be a structured list of section titles only. +""" + + +def create_blog_post_outline_agent(model: str | None = None) -> Agent: + agent = Agent( + model or get_default_ai_model(), + output_type=BlogPostOutline, + deps_type=BlogPostGenerationContext, + system_prompt=BLOG_POST_OUTLINE_SYSTEM_PROMPT, + retries=2, + model_settings={"temperature": 0.7}, + ) + + agent.system_prompt(add_project_details) + agent.system_prompt(add_title_details) + agent.system_prompt(add_todays_date) + agent.system_prompt(add_language_specification) + agent.system_prompt(add_target_keywords) + + return agent + + +class BlogPostSectionResearchQuestions(BaseModel): + questions: list[str] = Field( + default_factory=list, + description="3-6 concrete research questions for a single section", + ) + + +BLOG_POST_SECTION_QUESTIONS_SYSTEM_PROMPT = """ +You are an expert content researcher. + +Given a blog post section title, generate 3-6 specific research questions to investigate. + +Requirements: +- Questions should be specific and searchable. +- Prefer questions that lead to concrete examples, comparisons, metrics, pitfalls, and best practices. +- Avoid vague or overly broad questions. +""" # noqa: E501 + + +def create_blog_post_section_research_questions_agent(model: str | None = None) -> Agent: + agent = Agent( + model or get_default_ai_model(), + output_type=BlogPostSectionResearchQuestions, + deps_type=BlogPostGenerationContext, + system_prompt=BLOG_POST_SECTION_QUESTIONS_SYSTEM_PROMPT, + retries=2, + model_settings={"temperature": 0.7}, + ) + + agent.system_prompt(add_project_details) + agent.system_prompt(add_title_details) + agent.system_prompt(add_todays_date) + agent.system_prompt(add_language_specification) + agent.system_prompt(add_target_keywords) + + return agent diff --git a/core/agents/research_link_summary_agent.py b/core/agents/research_link_summary_agent.py new file mode 100644 index 0000000..e38bfbe --- /dev/null +++ b/core/agents/research_link_summary_agent.py @@ -0,0 +1,90 @@ +from django.utils import timezone +from pydantic_ai import Agent, RunContext + +from core.agents.schemas import ( + ResearchLinkContextualSummaryContext, + TextSummary, + WebPageContent, +) +from core.choices import get_default_ai_model + + +def _add_webpage_content_from_web_page_content(ctx: RunContext[WebPageContent]) -> str: + return ( + "Web page content:\n" + f"Title: {ctx.deps.title}\n" + f"Description: {ctx.deps.description}\n" + f"Content: {ctx.deps.markdown_content}\n" + ) + + +def _add_webpage_content_from_contextual_deps( + ctx: RunContext[ResearchLinkContextualSummaryContext], +) -> str: + web_page_content = ctx.deps.web_page_content + return ( + "Web page content:\n" + f"URL: {ctx.deps.url}\n" + f"Title: {web_page_content.title}\n" + f"Description: {web_page_content.description}\n" + f"Content: {web_page_content.markdown_content}\n" + ) + + +def _add_blog_post_research_context(ctx: RunContext[ResearchLinkContextualSummaryContext]) -> str: + blog_post_generation_context = ctx.deps.blog_post_generation_context + project_details = blog_post_generation_context.project_details + title_suggestion = blog_post_generation_context.title_suggestion + target_keywords = title_suggestion.target_keywords or [] + + return ( + "Context for why we are summarizing this page:\n" + f"- Today's date: {timezone.now().strftime('%Y-%m-%d')}\n" + f"- Project: {project_details.name}\n" + f"- Project summary: {project_details.summary}\n" + f"- Blog post title: {ctx.deps.blog_post_title}\n" + f"- Blog post section: {ctx.deps.section_title}\n" + f"- Research question: {ctx.deps.research_question}\n" + f"- Target keywords: {', '.join(target_keywords) if target_keywords else 'None'}\n" + "\n" + "You must tailor the summary to help the writer answer the research question for that section.\n" # noqa: E501 + ) + + +def create_general_research_link_summary_agent(model=None): + agent = Agent( + model or get_default_ai_model(), + output_type=TextSummary, + deps_type=WebPageContent, + system_prompt=( + "You are an expert content summarizer. Summarize the web page content provided.\n" + "Return a concise 2-3 sentence summary that captures the main purpose and key information.\n" # noqa: E501 + "Focus on what the page is about and its main value proposition.\n" + ), + retries=2, + model_settings={"temperature": 0.4}, + ) + agent.system_prompt(_add_webpage_content_from_web_page_content) + return agent + + +def create_contextual_research_link_summary_agent(model=None): + agent = Agent( + model or get_default_ai_model(), + output_type=TextSummary, + deps_type=ResearchLinkContextualSummaryContext, + system_prompt=( + "You are a research assistant helping write a blog post.\n" + "Summarize the page in a way that is maximally useful for answering the research question.\n" # noqa: E501 + "Prefer concrete facts, definitions, steps, examples, and any notable stats. If the page is not relevant, say so clearly.\n" # noqa: E501 + "Output markdown that includes:\n" + "- A short paragraph summary\n" + "- 'Key takeaways' as 3-7 bullet points\n" + "- 'How this helps our section' as 1-3 bullet points\n" + ), + retries=2, + model_settings={"temperature": 0.3}, + ) + agent.system_prompt(_add_blog_post_research_context) + agent.system_prompt(_add_webpage_content_from_contextual_deps) + return agent diff --git a/core/agents/schemas.py b/core/agents/schemas.py index 6852bfc..163e66d 100644 --- a/core/agents/schemas.py +++ b/core/agents/schemas.py @@ -14,6 +14,10 @@ class WebPageContent(BaseModel): markdown_content: str +class TextSummary(BaseModel): + summary: str = Field(description="A concise summary of the provided content") + + class ProjectDetails(BaseModel): name: str = Field(description="Official name of the project or organization") type: str = Field( @@ -189,6 +193,15 @@ class BlogPostGenerationContext(BaseModel): content_type: str = Field(description="Type of content to generate (SEO or SHARING)") +class ResearchLinkContextualSummaryContext(BaseModel): + url: str = Field(description="Source URL of the research page") + web_page_content: WebPageContent + blog_post_generation_context: BlogPostGenerationContext + blog_post_title: str = Field(description="Title of the blog post being written") + section_title: str = Field(description="Title of the blog post section being written") + research_question: str = Field(description="Research question we are trying to answer") + + class GeneratedBlogPostSchema(BaseModel): description: str = Field( description="Meta description (150-160 characters) optimized for search engines" diff --git a/core/content_generator/__init__.py b/core/content_generator/__init__.py new file mode 100644 index 0000000..976578a --- /dev/null +++ b/core/content_generator/__init__.py @@ -0,0 +1,7 @@ +""" +Content generation pipeline package. + +This package contains: +- `pipeline.py`: pipeline "steps" that orchestrate content generation + research. +- `utils.py`: small reusable helpers for the pipeline. +""" diff --git a/core/content_generator/pipeline.py b/core/content_generator/pipeline.py new file mode 100644 index 0000000..dfc8a6b --- /dev/null +++ b/core/content_generator/pipeline.py @@ -0,0 +1,598 @@ +from __future__ import annotations + +from django.conf import settings +from django.db import transaction +from django.utils import timezone +from django.utils.dateparse import parse_datetime +from django.utils.text import slugify +from django_q.tasks import async_task +from exa_py import Exa + +from core.agents.blog_post_outline_agent import ( + create_blog_post_outline_agent, + create_blog_post_section_research_questions_agent, +) +from core.agents.research_link_summary_agent import ( + create_contextual_research_link_summary_agent, + create_general_research_link_summary_agent, +) +from core.agents.schemas import ( + BlogPostGenerationContext, + ResearchLinkContextualSummaryContext, + WebPageContent, +) +from core.choices import ContentType +from core.content_generator.utils import get_exa_date_range_iso_strings +from core.models import ( + GeneratedBlogPost, + GeneratedBlogPostResearchLink, + GeneratedBlogPostResearchQuestion, + GeneratedBlogPostSection, +) +from core.utils import get_markdown_content, run_agent_synchronously +from tuxseo.utils import get_tuxseo_logger + +logger = get_tuxseo_logger(__name__) + + +INTRODUCTION_SECTION_TITLE = "Introduction" +CONCLUSION_SECTION_TITLE = "Conclusion" +NON_RESEARCH_SECTION_TITLES = {INTRODUCTION_SECTION_TITLE, CONCLUSION_SECTION_TITLE} +MAX_RESEARCH_LINK_MARKDOWN_CHARS_FOR_SUMMARY = 25_000 + + +def _create_blog_post_generation_context( + *, title_suggestion, content_type_to_use: str +) -> BlogPostGenerationContext: + keywords_to_use = title_suggestion.get_blog_post_keywords() + return BlogPostGenerationContext( + project_details=title_suggestion.project.project_details, + title_suggestion=title_suggestion.title_suggestion_schema, + project_keywords=keywords_to_use, + project_pages=[], + content_type=content_type_to_use, + ) + + +def generate_sections_to_create(*, title_suggestion, content_type: str | None = None) -> list[str]: + """ + Step 1: Generate the section titles we will create (one AI query). + """ + if title_suggestion is None: + raise ValueError("title_suggestion is required") + + if not title_suggestion.project_id: + raise ValueError("title_suggestion must be associated to a project") + + content_type_to_use = content_type or title_suggestion.content_type or ContentType.SHARING + outline_context = _create_blog_post_generation_context( + title_suggestion=title_suggestion, + content_type_to_use=content_type_to_use, + ) + + outline_agent = create_blog_post_outline_agent() + outline_result = run_agent_synchronously( + outline_agent, + "Generate the blog post outline sections.", + deps=outline_context, + function_name="generate_sections_to_create", + model_name="GeneratedBlogPost", + ) + + outline_sections = ( + outline_result.output.sections if outline_result and outline_result.output else [] + ) + + middle_section_titles = [ + (section.title or "").strip() + for section in outline_sections + if (section.title or "").strip() + ] + + return [INTRODUCTION_SECTION_TITLE, *middle_section_titles, CONCLUSION_SECTION_TITLE] + + +def create_blog_post_and_sections( + *, title_suggestion, section_titles: list[str], content_type: str | None = None +): + """ + Step 1b: Persist the GeneratedBlogPost + GeneratedBlogPostSection rows. + """ + content_type_to_use = content_type or title_suggestion.content_type or ContentType.SHARING + tags = ", ".join(title_suggestion.target_keywords) if title_suggestion.target_keywords else "" + + with transaction.atomic(): + blog_post = GeneratedBlogPost.objects.create( + project=title_suggestion.project, + title_suggestion=title_suggestion, + title=title_suggestion.title, + description=title_suggestion.suggested_meta_description, + slug=slugify(title_suggestion.title), + tags=tags, + content="", + ) + + for section_order, section_title in enumerate(section_titles): + GeneratedBlogPostSection.objects.create( + blog_post=blog_post, + title=(section_title or "")[:250], + content="", + order=section_order, + ) + + logger.info( + "[ContentGenerator] Blog post initialized", + blog_post_id=blog_post.id, + title_suggestion_id=title_suggestion.id, + project_id=title_suggestion.project_id, + num_sections_created=len(section_titles), + content_type=content_type_to_use, + ) + + return blog_post + + +def queue_research_question_generation_for_sections(*, blog_post_id: int) -> int: + """ + Step 2: Queue one task per (research) section to generate questions. + """ + blog_post = ( + GeneratedBlogPost.objects.prefetch_related("blog_post_sections") + .filter(id=blog_post_id) + .first() + ) + if not blog_post: + raise ValueError(f"GeneratedBlogPost not found: {blog_post_id}") + + blog_post_sections = list(blog_post.blog_post_sections.all()) + research_sections = [ + section + for section in blog_post_sections + if (section.title or "").strip() not in NON_RESEARCH_SECTION_TITLES + ] + + for section in research_sections: + async_task( + "core.content_generator.tasks.generate_research_questions_for_section_task", + section.id, + group="Generate Research Questions", + ) + + logger.info( + "[ContentGenerator] Queued research question generation tasks", + blog_post_id=blog_post.id, + num_sections=len(blog_post_sections), + num_research_sections=len(research_sections), + ) + + return len(research_sections) + + +def init_blog_post_content_generation(title_suggestion, content_type: str | None = None): + """ + Pipeline entrypoint (currently stops after queuing tasks). + + Step 1: generate sections we will create + Step 2: queue tasks to generate questions for each section + Step 3: (handled by the tasks) queue tasks to fetch Exa links for each generated question + Step 4: next steps later + """ + section_titles = generate_sections_to_create( + title_suggestion=title_suggestion, content_type=content_type + ) + blog_post = create_blog_post_and_sections( + title_suggestion=title_suggestion, + section_titles=section_titles, + content_type=content_type, + ) + queue_research_question_generation_for_sections(blog_post_id=blog_post.id) + return blog_post + + +def populate_research_links_for_question_from_exa( + research_question_id: int, + num_results_per_question: int = 2, + months_back: int = 6, +): + """ + Step 3: Get links for one question from Exa (called via a task per question). + """ + research_question = ( + GeneratedBlogPostResearchQuestion.objects.select_related("blog_post") + .filter(id=research_question_id) + .first() + ) + if not research_question: + raise ValueError(f"GeneratedBlogPostResearchQuestion not found: {research_question_id}") + + blog_post = research_question.blog_post + if not blog_post: + raise ValueError(f"GeneratedBlogPost missing on research question: {research_question_id}") + + research_question_text = (research_question.question or "").strip() + if not research_question_text: + return 0 + + start_date_iso_format, end_date_iso_format = get_exa_date_range_iso_strings( + months_back=months_back + ) + exa = Exa(api_key=settings.EXA_API_KEY) + + exa_response = exa.search( + research_question_text, + end_crawl_date=end_date_iso_format, + end_published_date=end_date_iso_format, + start_crawl_date=start_date_iso_format, + start_published_date=start_date_iso_format, + num_results=num_results_per_question, + type="auto", + ) + + exa_results = ( + exa_response.results + if hasattr(exa_response, "results") + else (exa_response or {}).get("results", []) + ) + exa_results = exa_results or [] + + num_links_upserted = 0 + num_scrape_tasks_queued = 0 + + for result in exa_results: + if hasattr(result, "url"): + url = getattr(result, "url", "") or "" + title = getattr(result, "title", "") or "" + author = getattr(result, "author", "") or "" + published_date_raw = getattr(result, "publishedDate", None) + else: + url = (result or {}).get("url", "") or "" + title = (result or {}).get("title", "") or "" + author = (result or {}).get("author", "") or "" + published_date_raw = (result or {}).get("publishedDate") or (result or {}).get( + "published_date" + ) + + url = url.strip() + if not url.startswith(("http://", "https://")): + continue + + if len(url) > 200: + continue + + published_date = parse_datetime(published_date_raw) if published_date_raw else None + if published_date and timezone.is_naive(published_date): + published_date = timezone.make_aware( + published_date, timezone=timezone.get_current_timezone() + ) + + research_link, _created = GeneratedBlogPostResearchLink.objects.update_or_create( + blog_post=blog_post, + research_question=research_question, + url=url, + defaults={ + "title": title[:500], + "author": author[:250], + "published_date": published_date, + }, + ) + + num_links_upserted += 1 + + should_queue_scrape_task = not (research_link.content or "").strip() + if should_queue_scrape_task: + async_task( + "core.content_generator.tasks.scrape_research_link_content_task", + research_link.id, + group="Scrape Research Links", + ) + num_scrape_tasks_queued += 1 + + logger.info( + "[ContentGenerator] Exa research link search completed (single question)", + blog_post_id=blog_post.id, + research_question_id=research_question.id, + num_links_upserted=num_links_upserted, + num_scrape_tasks_queued=num_scrape_tasks_queued, + num_results_per_question=num_results_per_question, + months_back=months_back, + ) + + return num_links_upserted + + +def scrape_research_link_content(*, research_link_id: int) -> bool: + """ + Step 4a: For a single research link, fetch the page content using Jina Reader and store it. + + Returns: True if content is present after the operation, False otherwise. + """ + research_link = ( + GeneratedBlogPostResearchLink.objects.select_related( + "blog_post", + "blog_post__title_suggestion", + "blog_post__project", + "research_question", + "research_question__section", + ) + .filter(id=research_link_id) + .first() + ) + if not research_link: + raise ValueError(f"GeneratedBlogPostResearchLink not found: {research_link_id}") + + url = (research_link.url or "").strip() + if not url.startswith(("http://", "https://")): + logger.info( + "[ContentGenerator] Skipping scrape/summarize for invalid research link url", + research_link_id=research_link.id, + url=url, + ) + return 0 + + blog_post = research_link.blog_post + research_question = research_link.research_question + if not blog_post or not research_question: + raise ValueError(f"Research link missing blog_post/research_question: {research_link_id}") + + should_fetch_page_content = not (research_link.content or "").strip() + if not should_fetch_page_content: + logger.info( + "[ContentGenerator] Research link already scraped; skipping", + research_link_id=research_link.id, + blog_post_id=blog_post.id, + ) + return True + + page_title = research_link.title + page_description = research_link.description + page_markdown_content = research_link.content + + scraped_title, scraped_description, scraped_content = get_markdown_content(url) + if not scraped_content.strip(): + logger.warning( + "[ContentGenerator] Jina Reader returned empty content for research link", + research_link_id=research_link.id, + blog_post_id=blog_post.id, + url=url, + ) + return False + + page_title = scraped_title or page_title + page_description = scraped_description or "" + page_markdown_content = scraped_content + + if not (page_markdown_content or "").strip(): + logger.warning( + "[ContentGenerator] Research link has empty content; cannot summarize", + research_link_id=research_link.id, + blog_post_id=blog_post.id, + url=url, + ) + return False + + update_fields: list[str] = [] + + research_link.date_scraped = timezone.now() + update_fields.append("date_scraped") + + research_link.title = (page_title or "")[:500] + update_fields.append("title") + + research_link.description = page_description or "" + update_fields.append("description") + + research_link.content = page_markdown_content or "" + update_fields.append("content") + + research_link.save(update_fields=list(dict.fromkeys(update_fields))) + + logger.info( + "[ContentGenerator] Research link scraped", + research_link_id=research_link.id, + blog_post_id=blog_post.id, + research_question_id=research_question.id, + updated_fields=update_fields, + url=url, + ) + + return True + + +def analyze_research_link_content(*, research_link_id: int) -> int: + """ + Step 4b: For a single research link (that already has content), generate: + - a general page summary + - a blog-post-contextual summary for the research question/section + + Returns: number of fields updated on the research link. + """ + research_link = ( + GeneratedBlogPostResearchLink.objects.select_related( + "blog_post", + "blog_post__title_suggestion", + "blog_post__project", + "research_question", + "research_question__section", + ) + .filter(id=research_link_id) + .first() + ) + if not research_link: + raise ValueError(f"GeneratedBlogPostResearchLink not found: {research_link_id}") + + blog_post = research_link.blog_post + research_question = research_link.research_question + if not blog_post or not research_question: + raise ValueError(f"Research link missing blog_post/research_question: {research_link_id}") + + url = (research_link.url or "").strip() + page_markdown_content = (research_link.content or "").strip() + if not page_markdown_content: + logger.info( + "[ContentGenerator] Research link has no content yet; skipping analysis", + research_link_id=research_link.id, + blog_post_id=blog_post.id, + url=url, + ) + return 0 + + should_run_general_summary = not (research_link.general_summary or "").strip() + should_run_contextual_summary = not (research_link.summary_for_question_research or "").strip() + if not should_run_general_summary and not should_run_contextual_summary: + logger.info( + "[ContentGenerator] Research link already analyzed; skipping", + research_link_id=research_link.id, + blog_post_id=blog_post.id, + ) + return 0 + + webpage_content = WebPageContent( + title=(research_link.title or "").strip(), + description=(research_link.description or "").strip(), + markdown_content=page_markdown_content[:MAX_RESEARCH_LINK_MARKDOWN_CHARS_FOR_SUMMARY], + ) + + update_fields: list[str] = [] + + if should_run_general_summary: + general_summary_agent = create_general_research_link_summary_agent() + general_summary_result = run_agent_synchronously( + general_summary_agent, + "Summarize this page.", + deps=webpage_content, + function_name="analyze_research_link_content.general_summary", + model_name="GeneratedBlogPostResearchLink", + ) + research_link.general_summary = (general_summary_result.output.summary or "").strip() + update_fields.append("general_summary") + + if should_run_contextual_summary: + title_suggestion = blog_post.title_suggestion + if not title_suggestion: + raise ValueError(f"GeneratedBlogPost missing title_suggestion: {blog_post.id}") + + content_type_to_use = title_suggestion.content_type or ContentType.SHARING + blog_post_generation_context = _create_blog_post_generation_context( + title_suggestion=title_suggestion, + content_type_to_use=content_type_to_use, + ) + + section_title = (getattr(research_question.section, "title", "") or "").strip() + research_question_text = (research_question.question or "").strip() + + contextual_summary_agent = create_contextual_research_link_summary_agent() + contextual_summary_deps = ResearchLinkContextualSummaryContext( + url=url, + web_page_content=webpage_content, + blog_post_generation_context=blog_post_generation_context, + blog_post_title=(blog_post.title or title_suggestion.title or "").strip(), + section_title=section_title, + research_question=research_question_text, + ) + contextual_summary_result = run_agent_synchronously( + contextual_summary_agent, + "Summarize this page specifically to help answer the research question for the blog post section.", # noqa: E501 + deps=contextual_summary_deps, + function_name="analyze_research_link_content.contextual_summary", + model_name="GeneratedBlogPostResearchLink", + ) + research_link.summary_for_question_research = ( + contextual_summary_result.output.summary or "" + ).strip() + update_fields.append("summary_for_question_research") + + research_link.date_analyzed = timezone.now() + update_fields.append("date_analyzed") + + research_link.save(update_fields=list(dict.fromkeys(update_fields))) + + logger.info( + "[ContentGenerator] Research link analyzed", + research_link_id=research_link.id, + blog_post_id=blog_post.id, + research_question_id=research_question.id, + updated_fields=update_fields, + url=url, + ) + + return len(set(update_fields)) + + +def generate_research_questions_for_section(*, section_id: int) -> list[int]: + """ + Step 2 (task): Generate research questions for a single section. + + Returns: list of created GeneratedBlogPostResearchQuestion IDs. + """ + section = ( + GeneratedBlogPostSection.objects.select_related( + "blog_post", + "blog_post__title_suggestion", + "blog_post__project", + ) + .filter(id=section_id) + .first() + ) + if not section: + raise ValueError(f"GeneratedBlogPostSection not found: {section_id}") + + section_title = (section.title or "").strip() + if section_title in NON_RESEARCH_SECTION_TITLES: + logger.info( + "[ContentGenerator] Skipping research question generation for non-research section", + section_id=section.id, + section_title=section_title, + blog_post_id=section.blog_post_id, + ) + return [] + + blog_post = section.blog_post + if not blog_post or not blog_post.title_suggestion_id: + raise ValueError(f"Section is missing blog_post/title_suggestion: {section_id}") + + title_suggestion = blog_post.title_suggestion + content_type_to_use = title_suggestion.content_type or ContentType.SHARING + outline_context = _create_blog_post_generation_context( + title_suggestion=title_suggestion, + content_type_to_use=content_type_to_use, + ) + + research_questions_agent = create_blog_post_section_research_questions_agent() + questions_result = run_agent_synchronously( + research_questions_agent, + f"Generate research questions for section: {section_title}", + deps=outline_context, + function_name="generate_research_questions_for_section", + model_name="GeneratedBlogPost", + ) + + questions = ( + questions_result.output.questions if questions_result and questions_result.output else [] + ) + + questions_to_create = [] + for question in questions: + research_question_text = (question or "").strip() + if not research_question_text: + continue + questions_to_create.append( + GeneratedBlogPostResearchQuestion( + blog_post=blog_post, + section=section, + question=research_question_text[:250], + ) + ) + + created_questions = GeneratedBlogPostResearchQuestion.objects.bulk_create(questions_to_create) + created_question_ids = [ + created_question.id for created_question in created_questions if created_question.id + ] + + logger.info( + "[ContentGenerator] Research questions generated", + section_id=section.id, + blog_post_id=blog_post.id, + num_questions_created=len(created_question_ids), + ) + + return created_question_ids diff --git a/core/content_generator/tasks.py b/core/content_generator/tasks.py new file mode 100644 index 0000000..ca432a6 --- /dev/null +++ b/core/content_generator/tasks.py @@ -0,0 +1,91 @@ +from __future__ import annotations + +from django_q.tasks import async_task + +from core.content_generator.pipeline import ( + analyze_research_link_content, + generate_research_questions_for_section, + populate_research_links_for_question_from_exa, + scrape_research_link_content, +) +from tuxseo.utils import get_tuxseo_logger + +logger = get_tuxseo_logger(__name__) + + +def populate_research_links_for_question_from_exa_task( + research_question_id: int, + num_results_per_question: int = 2, + months_back: int = 6, +): + """ + Populate Exa research links for one research question. + """ + num_links = populate_research_links_for_question_from_exa( + research_question_id=research_question_id, + num_results_per_question=num_results_per_question, + months_back=months_back, + ) + logger.info( + "[ContentGenerator Tasks] Populated Exa research links for question", + research_question_id=research_question_id, + num_links_upserted=num_links, + ) + return f"Populated {num_links} research links for research question {research_question_id}" + + +def scrape_research_link_content_task(research_link_id: int): + """ + Fetch research link content using Jina Reader. + If content is successfully fetched, queue the analysis task. + """ + did_fetch_content = scrape_research_link_content(research_link_id=research_link_id) + logger.info( + "[ContentGenerator Tasks] Scraped research link", + research_link_id=research_link_id, + did_fetch_content=did_fetch_content, + ) + if did_fetch_content: + async_task( + "core.content_generator.tasks.analyze_research_link_content_task", + research_link_id, + group="Analyze Research Links", + ) + return f"Scraped research link {research_link_id} (did_fetch_content={did_fetch_content})" + + +def analyze_research_link_content_task(research_link_id: int): + """ + Analyze a research link that has already been scraped: + - generate general summary + - generate blog-post contextual summary for the research question/section + """ + num_fields_updated = analyze_research_link_content(research_link_id=research_link_id) + logger.info( + "[ContentGenerator Tasks] Analyzed research link", + research_link_id=research_link_id, + num_fields_updated=num_fields_updated, + ) + return f"Analyzed research link {research_link_id} (updated_fields={num_fields_updated})" + + +def generate_research_questions_for_section_task(section_id: int): + """ + Generate research questions for one section, then queue Exa research link tasks for each + created question. + """ + created_research_question_ids = generate_research_questions_for_section(section_id=section_id) + + for research_question_id in created_research_question_ids: + async_task( + "core.content_generator.tasks.populate_research_links_for_question_from_exa_task", + research_question_id, + group="Populate Research Links", + ) + + logger.info( + "[ContentGenerator Tasks] Generated research questions for section", + section_id=section_id, + num_questions_created=len(created_research_question_ids), + ) + return f"Generated {len(created_research_question_ids)} research questions for section {section_id}" # noqa: E501 diff --git a/core/content_generator/utils.py b/core/content_generator/utils.py new file mode 100644 index 0000000..c637adb --- /dev/null +++ b/core/content_generator/utils.py @@ -0,0 +1,15 @@ +from __future__ import annotations + +from datetime import timedelta + +from django.utils import timezone + + +def get_exa_date_range_iso_strings(*, months_back: int) -> tuple[str, str]: + """ + Exa expects date filters as strings (YYYY-MM-DD). + """ + current_datetime = timezone.now() + end_date_iso_format = current_datetime.date().isoformat() + start_date_iso_format = (current_datetime - timedelta(days=months_back * 30)).date().isoformat() + return start_date_iso_format, end_date_iso_format diff --git a/core/migrations/0050_backlink_generatedblogpostresearchquestion_and_more.py b/core/migrations/0050_backlink_generatedblogpostresearchquestion_and_more.py new file mode 100644 index 0000000..8e12c27 --- /dev/null +++ b/core/migrations/0050_backlink_generatedblogpostresearchquestion_and_more.py @@ -0,0 +1,95 @@ +# Generated by Django 5.2.8 on 2025-12-26 21:43 + +import django.db.models.deletion +import pgvector.django.vector +import uuid +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0049_alter_emailsent_email_type'), + ] + + operations = [ + migrations.CreateModel( + name='Backlink', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('uuid', models.UUIDField(default=uuid.uuid4, editable=False)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('deleted_at', models.DateTimeField(blank=True, null=True)), + ('linked_from_project_page', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='backlinks_from', to='core.project')), + ('linked_to_project_page', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='backlinks_to', to='core.project')), + ('linking_from_blog_post', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='backlinks', to='core.generatedblogpost')), + ('linkning_to_project_page', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='backlinks', to='core.projectpage')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='GeneratedBlogPostResearchQuestion', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('uuid', models.UUIDField(default=uuid.uuid4, editable=False)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('deleted_at', models.DateTimeField(blank=True, null=True)), + ('question', models.CharField(max_length=250)), + ('blog_post', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='research_questions', to='core.generatedblogpost')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='GeneratedBlogPostResearchLink', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('uuid', models.UUIDField(default=uuid.uuid4, editable=False)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('deleted_at', models.DateTimeField(blank=True, null=True)), + ('url', models.URLField()), + ('title', models.CharField(blank=True, default='', max_length=500)), + ('author', models.CharField(blank=True, default='', max_length=250)), + ('description', models.TextField(blank=True, default='')), + ('markdown_content', models.TextField(blank=True, default='')), + ('question', models.CharField(max_length=250)), + ('date_scraped', models.DateTimeField(blank=True, null=True)), + ('date_analyzed', models.DateTimeField(blank=True, null=True)), + ('summary', models.TextField(blank=True)), + ('embedding', pgvector.django.vector.VectorField(blank=True, default=None, dimensions=1024, null=True)), + ('blog_post', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='research_links', to='core.generatedblogpost')), + ('research_question', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='research_links', to='core.generatedblogpostresearchquestion')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='GeneratedBlogPostSection', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('uuid', models.UUIDField(default=uuid.uuid4, editable=False)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('deleted_at', models.DateTimeField(blank=True, null=True)), + ('title', models.CharField(max_length=250)), + ('content', models.TextField(blank=True, default='')), + ('order', models.IntegerField(default=0)), + ('blog_post', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='blog_post_sections', to='core.generatedblogpost')), + ], + options={ + 'abstract': False, + }, + ), + migrations.AddField( + model_name='generatedblogpostresearchquestion', + name='section', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='research_questions', to='core.generatedblogpostsection'), + ), + ] diff --git a/core/migrations/0051_rename_markdown_content_generatedblogpostresearchlink_content_and_more.py b/core/migrations/0051_rename_markdown_content_generatedblogpostresearchlink_content_and_more.py new file mode 100644 index 0000000..dde01ab --- /dev/null +++ b/core/migrations/0051_rename_markdown_content_generatedblogpostresearchlink_content_and_more.py @@ -0,0 +1,44 @@ +# Generated by Django 5.2.9 on 2025-12-27 12:14 + +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0050_backlink_generatedblogpostresearchquestion_and_more'), + ] + + operations = [ + migrations.RenameField( + model_name='generatedblogpostresearchlink', + old_name='markdown_content', + new_name='content', + ), + migrations.RenameField( + model_name='generatedblogpostresearchlink', + old_name='summary', + new_name='general_summary', + ), + migrations.RemoveField( + model_name='generatedblogpostresearchlink', + name='question', + ), + migrations.AddField( + model_name='generatedblogpostresearchlink', + name='published_date', + field=models.DateTimeField(blank=True, null=True), + ), + migrations.AddField( + model_name='generatedblogpostresearchlink', + name='summary_for_question_research', + field=models.TextField(blank=True, default=''), + ), + migrations.AlterField( + model_name='generatedblogpostresearchlink', + name='date_scraped', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + ] diff --git a/core/models.py b/core/models.py index c23e23f..8ac9f57 100644 --- a/core/models.py +++ b/core/models.py @@ -10,9 +10,7 @@ from django.db import models, transaction from django.urls import reverse from django.utils import timezone -from django.utils.text import slugify from django_q.tasks import async_task -from gpt_researcher import GPTResearcher from pgvector.django import HnswIndex, VectorField from core.agents import ( @@ -60,9 +58,7 @@ get_og_image_prompt, get_relevant_external_pages_for_blog_post, get_relevant_pages_for_blog_post, - process_generated_blog_content, run_agent_synchronously, - run_gptr_synchronously, ) from tuxseo.utils import get_tuxseo_logger @@ -805,85 +801,19 @@ def get_blog_post_keywords(self): return keywords_to_use def generate_content(self, content_type=ContentType.SHARING): - # query defines the research question researcher will analyze - # custom_prompt controls how the research findings are presented - - # Suggestion Instructions - query = "Write a post from the following suggestion:\n" - query += f"{self.title_suggestion_string_for_ai}\n\n" - - # Get keywords to use in the blog post - project_keywords = list( - self.project.project_keywords.filter(use=True).select_related("keyword") - ) - project_keyword_texts = [keyword.keyword.keyword_text for keyword in project_keywords] - post_suggestion_keywords = self.target_keywords or [] - keywords_to_use = list(set(project_keyword_texts + post_suggestion_keywords)) - newline_separator = "\n" - keywords_list = newline_separator.join([f"- {keyword}" for keyword in keywords_to_use]) - query += "The following keywords should be used (organically) in the blog post:\n" - query += keywords_list - query += "\n\n" - - query += "Quick reminder. You are writing a blog post for this company." - query += self.project.project_desctiption_string_for_ai - query += ". Make it look good, as the best solution for anyone reading the post." - query += "\n\n" - - # # Writing Instructions - # query += GENERATE_CONTENT_SYSTEM_PROMPTS[content_type] - # query += "\n" - query += GeneratedBlogPost.blog_post_structure_rules() - - agent = GPTResearcher( - query, - report_type="deep", - tone="Simple (written for young readers, using basic vocabulary and clear explanations)", # noqa: E501 - report_format="markdown", - ) - - result = run_gptr_synchronously(agent) + """ + Backward-compatible wrapper around the content generation pipeline. - # Create blog post with raw content first - slug = slugify(self.title) - tags = ", ".join(self.target_keywords) if self.target_keywords else "" + Historically, this method created the blog post content directly. It is now kept + as a thin wrapper to preserve existing call sites while the pipeline evolves. + """ + from core.content_generator.pipeline import init_blog_post_content_generation - blog_post = GeneratedBlogPost.objects.create( - project=self.project, + return init_blog_post_content_generation( title_suggestion=self, - title=self.title, # Temporary title, will be updated after processing - description=self.suggested_meta_description, - slug=slug, - tags=tags, - content=result, # Raw content from GPTResearcher + content_type=content_type, ) - # Insert links into the blog post content - blog_post.insert_links_into_post() - - # Process content after link insertion (extract title, clean up sections) - blog_post_title, blog_post_content = process_generated_blog_content( - generated_content=blog_post.content, # Use content after link insertion - fallback_title=self.title, - title_suggestion_id=self.id, - project_id=self.project.id, - ) - - # Update blog post with processed content and extracted title - blog_post.title = blog_post_title - blog_post.slug = slugify(blog_post_title) - blog_post.content = blog_post_content - blog_post.save(update_fields=["title", "slug", "content"]) - - if self.project.enable_automatic_og_image_generation: - async_task( - "core.tasks.generate_og_image_for_blog_post", - blog_post.id, - group="Generate OG Image", - ) - - return blog_post - class AutoSubmissionSetting(BaseModel): project = models.ForeignKey( @@ -930,6 +860,8 @@ class GeneratedBlogPost(BaseModel): on_delete=models.CASCADE, related_name="generated_blog_posts", ) + + # Final Output Items title = models.CharField(max_length=250) description = models.TextField(blank=True) slug = models.SlugField(max_length=250) @@ -938,6 +870,10 @@ class GeneratedBlogPost(BaseModel): icon = models.ImageField(upload_to="generated_blog_post_icons/", blank=True) image = models.ImageField(upload_to="generated_blog_post_images/", blank=True) + # Preparation + # GeneratedBlogPostSection model + + # Other posted = models.BooleanField(default=False) date_posted = models.DateTimeField(null=True, blank=True) @@ -1250,6 +1186,72 @@ def insert_links_into_post(self, max_pages=4, max_external_pages=3): return content_with_links +class GeneratedBlogPostSection(BaseModel): + blog_post = models.ForeignKey( + GeneratedBlogPost, + null=True, + blank=True, + on_delete=models.CASCADE, + related_name="blog_post_sections", + ) + title = models.CharField(max_length=250) + content = models.TextField(blank=True, default="") + order = models.IntegerField(default=0) + # GeneratedBlogPostResearchQuestion model + + +class GeneratedBlogPostResearchQuestion(BaseModel): + blog_post = models.ForeignKey( + GeneratedBlogPost, + null=True, + blank=True, + on_delete=models.CASCADE, + related_name="research_questions", + ) + section = models.ForeignKey( + GeneratedBlogPostSection, + null=True, + blank=True, + on_delete=models.CASCADE, + related_name="research_questions", + ) + question = models.CharField(max_length=250) + + +class GeneratedBlogPostResearchLink(BaseModel): + blog_post = models.ForeignKey( + GeneratedBlogPost, + null=True, + blank=True, + on_delete=models.CASCADE, + related_name="research_links", + ) + research_question = models.ForeignKey( + GeneratedBlogPostResearchQuestion, + null=True, + blank=True, + on_delete=models.CASCADE, + related_name="research_links", + ) + + # initial data + url = models.URLField(max_length=200) + title = models.CharField(max_length=500, blank=True, default="") + author = models.CharField(max_length=250, blank=True, default="") + published_date = models.DateTimeField(null=True, blank=True) + + # jina augmentation + date_scraped = models.DateTimeField(auto_now_add=True) + content = models.TextField(blank=True, default="") + description = models.TextField(blank=True, default="") + + # ai augmentation + date_analyzed = models.DateTimeField(null=True, blank=True) + summary_for_question_research = models.TextField(blank=True, default="") + general_summary = models.TextField(blank=True) + embedding = VectorField(dimensions=1024, default=None, null=True, blank=True) + + class ProjectPage(BaseModel): project = models.ForeignKey( Project, null=True, blank=True, on_delete=models.CASCADE, related_name="project_pages" @@ -1998,3 +2000,22 @@ class Meta: def __str__(self): return f"{self.email_type} to {self.email_address}" + + +class Backlink(BaseModel): + linked_to_project_page = models.ForeignKey( + Project, null=True, blank=True, on_delete=models.CASCADE, related_name="backlinks_to" + ) + linkning_to_project_page = models.ForeignKey( + ProjectPage, null=True, blank=True, on_delete=models.CASCADE, related_name="backlinks" + ) + + linked_from_project_page = models.ForeignKey( + Project, null=True, blank=True, on_delete=models.CASCADE, related_name="backlinks_from" + ) + linking_from_blog_post = models.ForeignKey( + GeneratedBlogPost, null=True, blank=True, on_delete=models.CASCADE, related_name="backlinks" + ) + + def __str__(self): + return f"{self.linking_from_blog_post.title} -> {self.linked_to_project_page.url}" diff --git a/core/tasks.py b/core/tasks.py index a5e3a70..9a56118 100644 --- a/core/tasks.py +++ b/core/tasks.py @@ -1780,3 +1780,15 @@ def generate_blog_post_content(suggestion_id: int, send_email: bool = True): project_id=suggestion.project.id if suggestion.project else None, ) return f"Unexpected error: {str(error)}" + + +def generate_research_questions_for_section_task(section_id: int): + """ + Generate research questions for one blog post section, then queue Exa research link tasks for + each created question. + """ + from core.content_generator.tasks import ( + generate_research_questions_for_section_task as delegated_task, + ) + + return delegated_task(section_id=section_id) diff --git a/poetry.lock b/poetry.lock index 6bc27a9..ba872be 100644 --- a/poetry.lock +++ b/poetry.lock @@ -250,23 +250,22 @@ vertex = ["google-auth[requests] (>=2,<3)"] [[package]] name = "anyio" -version = "4.11.0" +version = "4.12.0" description = "High-level concurrency and networking framework on top of asyncio or Trio" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc"}, - {file = "anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4"}, + {file = "anyio-4.12.0-py3-none-any.whl", hash = "sha256:dad2376a628f98eeca4881fc56cd06affd18f659b17a747d3ff0307ced94b1bb"}, + {file = "anyio-4.12.0.tar.gz", hash = "sha256:73c693b567b0c55130c104d0b43a9baf3aa6a31fc6110116509f27bf75e21ec0"}, ] [package.dependencies] idna = ">=2.8" -sniffio = ">=1.1" typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] -trio = ["trio (>=0.31.0)"] +trio = ["trio (>=0.31.0) ; python_version < \"3.10\"", "trio (>=0.32.0) ; python_version >= \"3.10\""] [[package]] name = "argcomplete" @@ -377,14 +376,14 @@ files = [ [[package]] name = "authlib" -version = "1.6.5" +version = "1.6.6" description = "The ultimate Python library in building OAuth and OpenID Connect servers and clients." optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "authlib-1.6.5-py2.py3-none-any.whl", hash = "sha256:3e0e0507807f842b02175507bdee8957a1d5707fd4afb17c32fb43fee90b6e3a"}, - {file = "authlib-1.6.5.tar.gz", hash = "sha256:6aaf9c79b7cc96c900f0b284061691c5d4e61221640a948fe690b556a6d6d10b"}, + {file = "authlib-1.6.6-py2.py3-none-any.whl", hash = "sha256:7d9e9bc535c13974313a87f53e8430eb6ea3d1cf6ae4f6efcd793f2e949143fd"}, + {file = "authlib-1.6.6.tar.gz", hash = "sha256:45770e8e056d0f283451d9996fbb59b70d45722b45d854d58f32878d0a40c38e"}, ] [package.dependencies] @@ -421,38 +420,38 @@ testing = ["jaraco.test", "pytest (!=8.0.*)", "pytest (>=6,!=8.1.*)", "pytest-ch [[package]] name = "beartype" -version = "0.22.6" +version = "0.22.9" description = "Unbearably fast near-real-time pure-Python runtime-static type-checker." optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "beartype-0.22.6-py3-none-any.whl", hash = "sha256:0584bc46a2ea2a871509679278cda992eadde676c01356ab0ac77421f3c9a093"}, - {file = "beartype-0.22.6.tar.gz", hash = "sha256:97fbda69c20b48c5780ac2ca60ce3c1bb9af29b3a1a0216898ffabdd523e48f4"}, + {file = "beartype-0.22.9-py3-none-any.whl", hash = "sha256:d16c9bbc61ea14637596c5f6fbff2ee99cbe3573e46a716401734ef50c3060c2"}, + {file = "beartype-0.22.9.tar.gz", hash = "sha256:8f82b54aa723a2848a56008d18875f91c1db02c32ef6a62319a002e3e25a975f"}, ] [package.extras] -dev = ["autoapi (>=0.9.0)", "celery", "click", "coverage (>=5.5)", "docutils (>=0.22.0)", "equinox ; sys_platform == \"linux\" and python_version < \"3.15.0\"", "fastmcp ; python_version < \"3.14.0\"", "jax[cpu] ; sys_platform == \"linux\" and python_version < \"3.15.0\"", "jaxtyping ; sys_platform == \"linux\"", "langchain ; python_version < \"3.14.0\" and sys_platform != \"darwin\" and platform_python_implementation != \"PyPy\"", "mypy (>=0.800) ; platform_python_implementation != \"PyPy\"", "nuitka (>=1.2.6) ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "numba ; python_version < \"3.14.0\"", "numpy ; python_version < \"3.15.0\" and sys_platform != \"darwin\" and platform_python_implementation != \"PyPy\"", "pandera (>=0.26.0) ; python_version < \"3.14.0\"", "poetry", "polars ; python_version < \"3.14.0\"", "pydata-sphinx-theme (<=0.7.2)", "pygments", "pyright (>=1.1.370)", "pytest (>=6.2.0)", "redis", "rich-click", "setuptools", "sphinx", "sphinx (>=4.2.0,<6.0.0)", "sphinxext-opengraph (>=0.7.5)", "sqlalchemy", "torch ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "tox (>=3.20.1)", "typer", "typing-extensions (>=3.10.0.0)", "xarray ; python_version < \"3.15.0\""] +dev = ["autoapi (>=0.9.0)", "celery", "click", "coverage (>=5.5)", "docutils (>=0.22.0)", "equinox ; sys_platform == \"linux\" and python_version < \"3.15.0\"", "fastmcp ; python_version < \"3.14.0\"", "jax[cpu] ; sys_platform == \"linux\" and python_version < \"3.15.0\"", "jaxtyping ; sys_platform == \"linux\"", "langchain ; python_version < \"3.14.0\" and sys_platform != \"darwin\" and platform_python_implementation != \"PyPy\"", "mypy (>=0.800) ; platform_python_implementation != \"PyPy\"", "nuitka (>=1.2.6) ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "numba ; python_version < \"3.14.0\"", "numpy ; python_version < \"3.15.0\" and sys_platform != \"darwin\" and platform_python_implementation != \"PyPy\"", "pandera (>=0.26.0) ; python_version < \"3.14.0\"", "poetry", "polars ; python_version < \"3.14.0\"", "pydata-sphinx-theme (<=0.7.2)", "pygments", "pyinstaller", "pyright (>=1.1.370)", "pytest (>=6.2.0)", "redis", "rich-click", "setuptools", "sphinx", "sphinx (>=4.2.0,<6.0.0)", "sphinxext-opengraph (>=0.7.5)", "sqlalchemy", "torch ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "tox (>=3.20.1)", "typer", "typing-extensions (>=3.10.0.0)", "xarray ; python_version < \"3.15.0\""] doc-ghp = ["mkdocs-material[imaging] (>=9.6.0)", "mkdocstrings-python (>=1.16.0)", "mkdocstrings-python-xref (>=1.16.0)"] doc-rtd = ["autoapi (>=0.9.0)", "pydata-sphinx-theme (<=0.7.2)", "setuptools", "sphinx (>=4.2.0,<6.0.0)", "sphinxext-opengraph (>=0.7.5)"] -test = ["celery", "click", "coverage (>=5.5)", "docutils (>=0.22.0)", "equinox ; sys_platform == \"linux\" and python_version < \"3.15.0\"", "fastmcp ; python_version < \"3.14.0\"", "jax[cpu] ; sys_platform == \"linux\" and python_version < \"3.15.0\"", "jaxtyping ; sys_platform == \"linux\"", "langchain ; python_version < \"3.14.0\" and sys_platform != \"darwin\" and platform_python_implementation != \"PyPy\"", "mypy (>=0.800) ; platform_python_implementation != \"PyPy\"", "nuitka (>=1.2.6) ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "numba ; python_version < \"3.14.0\"", "numpy ; python_version < \"3.15.0\" and sys_platform != \"darwin\" and platform_python_implementation != \"PyPy\"", "pandera (>=0.26.0) ; python_version < \"3.14.0\"", "poetry", "polars ; python_version < \"3.14.0\"", "pygments", "pyright (>=1.1.370)", "pytest (>=6.2.0)", "redis", "rich-click", "sphinx", "sqlalchemy", "torch ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "tox (>=3.20.1)", "typer", "typing-extensions (>=3.10.0.0)", "xarray ; python_version < \"3.15.0\""] -test-tox = ["celery", "click", "docutils (>=0.22.0)", "equinox ; sys_platform == \"linux\" and python_version < \"3.15.0\"", "fastmcp ; python_version < \"3.14.0\"", "jax[cpu] ; sys_platform == \"linux\" and python_version < \"3.15.0\"", "jaxtyping ; sys_platform == \"linux\"", "langchain ; python_version < \"3.14.0\" and sys_platform != \"darwin\" and platform_python_implementation != \"PyPy\"", "mypy (>=0.800) ; platform_python_implementation != \"PyPy\"", "nuitka (>=1.2.6) ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "numba ; python_version < \"3.14.0\"", "numpy ; python_version < \"3.15.0\" and sys_platform != \"darwin\" and platform_python_implementation != \"PyPy\"", "pandera (>=0.26.0) ; python_version < \"3.14.0\"", "poetry", "polars ; python_version < \"3.14.0\"", "pygments", "pyright (>=1.1.370)", "pytest (>=6.2.0)", "redis", "rich-click", "sphinx", "sqlalchemy", "torch ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "typer", "typing-extensions (>=3.10.0.0)", "xarray ; python_version < \"3.15.0\""] +test = ["celery", "click", "coverage (>=5.5)", "docutils (>=0.22.0)", "equinox ; sys_platform == \"linux\" and python_version < \"3.15.0\"", "fastmcp ; python_version < \"3.14.0\"", "jax[cpu] ; sys_platform == \"linux\" and python_version < \"3.15.0\"", "jaxtyping ; sys_platform == \"linux\"", "langchain ; python_version < \"3.14.0\" and sys_platform != \"darwin\" and platform_python_implementation != \"PyPy\"", "mypy (>=0.800) ; platform_python_implementation != \"PyPy\"", "nuitka (>=1.2.6) ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "numba ; python_version < \"3.14.0\"", "numpy ; python_version < \"3.15.0\" and sys_platform != \"darwin\" and platform_python_implementation != \"PyPy\"", "pandera (>=0.26.0) ; python_version < \"3.14.0\"", "poetry", "polars ; python_version < \"3.14.0\"", "pygments", "pyinstaller", "pyright (>=1.1.370)", "pytest (>=6.2.0)", "redis", "rich-click", "sphinx", "sqlalchemy", "torch ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "tox (>=3.20.1)", "typer", "typing-extensions (>=3.10.0.0)", "xarray ; python_version < \"3.15.0\""] +test-tox = ["celery", "click", "docutils (>=0.22.0)", "equinox ; sys_platform == \"linux\" and python_version < \"3.15.0\"", "fastmcp ; python_version < \"3.14.0\"", "jax[cpu] ; sys_platform == \"linux\" and python_version < \"3.15.0\"", "jaxtyping ; sys_platform == \"linux\"", "langchain ; python_version < \"3.14.0\" and sys_platform != \"darwin\" and platform_python_implementation != \"PyPy\"", "mypy (>=0.800) ; platform_python_implementation != \"PyPy\"", "nuitka (>=1.2.6) ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "numba ; python_version < \"3.14.0\"", "numpy ; python_version < \"3.15.0\" and sys_platform != \"darwin\" and platform_python_implementation != \"PyPy\"", "pandera (>=0.26.0) ; python_version < \"3.14.0\"", "poetry", "polars ; python_version < \"3.14.0\"", "pygments", "pyinstaller", "pyright (>=1.1.370)", "pytest (>=6.2.0)", "redis", "rich-click", "sphinx", "sqlalchemy", "torch ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "typer", "typing-extensions (>=3.10.0.0)", "xarray ; python_version < \"3.15.0\""] test-tox-coverage = ["coverage (>=5.5)"] [[package]] name = "beautifulsoup4" -version = "4.14.2" +version = "4.14.3" description = "Screen-scraping library" optional = false python-versions = ">=3.7.0" groups = ["main"] files = [ - {file = "beautifulsoup4-4.14.2-py3-none-any.whl", hash = "sha256:5ef6fa3a8cbece8488d66985560f97ed091e22bbc4e9c2338508a9d5de6d4515"}, - {file = "beautifulsoup4-4.14.2.tar.gz", hash = "sha256:2a98ab9f944a11acee9cc848508ec28d9228abfd522ef0fad6a02a72e0ded69e"}, + {file = "beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb"}, + {file = "beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86"}, ] [package.dependencies] -soupsieve = ">1.2" +soupsieve = ">=1.6.1" typing-extensions = ">=4.0.0" [package.extras] @@ -479,34 +478,34 @@ chardet = ">=3.0.2" [[package]] name = "boto3" -version = "1.41.5" +version = "1.42.16" description = "The AWS SDK for Python" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "boto3-1.41.5-py3-none-any.whl", hash = "sha256:bb278111bfb4c33dca8342bda49c9db7685e43debbfa00cc2a5eb854dd54b745"}, - {file = "boto3-1.41.5.tar.gz", hash = "sha256:bc7806bee681dfdff2fe2b74967b107a56274f1e66ebe4d20dc8eee1ea408d17"}, + {file = "boto3-1.42.16-py3-none-any.whl", hash = "sha256:37a43d42aebd06a8f93ee801ea1b7b5181ac42a30869ef403c9dadc160a748e5"}, + {file = "boto3-1.42.16.tar.gz", hash = "sha256:811391611db88c8a061f6e6fabbd7ca784ad9de04490a879f091cbaa9de7de74"}, ] [package.dependencies] -botocore = ">=1.41.5,<1.42.0" +botocore = ">=1.42.16,<1.43.0" jmespath = ">=0.7.1,<2.0.0" -s3transfer = ">=0.15.0,<0.16.0" +s3transfer = ">=0.16.0,<0.17.0" [package.extras] crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.41.5" +version = "1.42.16" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "botocore-1.41.5-py3-none-any.whl", hash = "sha256:3fef7fcda30c82c27202d232cfdbd6782cb27f20f8e7e21b20606483e66ee73a"}, - {file = "botocore-1.41.5.tar.gz", hash = "sha256:0367622b811597d183bfcaab4a350f0d3ede712031ce792ef183cabdee80d3bf"}, + {file = "botocore-1.42.16-py3-none-any.whl", hash = "sha256:b1f584a0f8645c12e07bf6ec9c18e05221a789f2a9b2d3c6291deb42f8c1c542"}, + {file = "botocore-1.42.16.tar.gz", hash = "sha256:29ee8555cd5d5023350405387cedcf3fe1c7f02fcb8060bf9e01602487482c25"}, ] [package.dependencies] @@ -515,7 +514,7 @@ python-dateutil = ">=2.1,<3.0.0" urllib3 = {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""} [package.extras] -crt = ["awscrt (==0.29.0)"] +crt = ["awscrt (==0.29.2)"] [[package]] name = "brotli" @@ -656,14 +655,14 @@ cffi = [ [[package]] name = "cachetools" -version = "6.2.2" +version = "6.2.4" description = "Extensible memoizing collections and decorators" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "cachetools-6.2.2-py3-none-any.whl", hash = "sha256:6c09c98183bf58560c97b2abfcedcbaf6a896a490f534b031b661d3723b45ace"}, - {file = "cachetools-6.2.2.tar.gz", hash = "sha256:8e6d266b25e539df852251cfd6f990b4bc3a141db73b939058d809ebd2590fc6"}, + {file = "cachetools-6.2.4-py3-none-any.whl", hash = "sha256:69a7a52634fed8b8bf6e24a050fb60bff1c9bd8f6d24572b99c32d4e71e62a51"}, + {file = "cachetools-6.2.4.tar.gz", hash = "sha256:82c5c05585e70b6ba2d3ae09ea60b79548872185d2f24ae1f2709d37299fd607"}, ] [[package]] @@ -937,25 +936,36 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} +[[package]] +name = "cloudpickle" +version = "3.1.2" +description = "Pickler class to extend the standard pickle.Pickler functionality" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "cloudpickle-3.1.2-py3-none-any.whl", hash = "sha256:9acb47f6afd73f60dc1df93bb801b472f05ff42fa6c84167d25cb206be1fbf4a"}, + {file = "cloudpickle-3.1.2.tar.gz", hash = "sha256:7fda9eb655c9c230dab534f1983763de5835249750e85fbcef43aaa30a9a2414"}, +] + [[package]] name = "cohere" -version = "5.20.0" +version = "5.20.1" description = "" optional = false python-versions = "<4.0,>=3.9" groups = ["main"] markers = "platform_system != \"Emscripten\"" files = [ - {file = "cohere-5.20.0-py3-none-any.whl", hash = "sha256:a95f17ed22be3f978363703beb6008b55000ce0e85124ddb976fa5b688014fea"}, - {file = "cohere-5.20.0.tar.gz", hash = "sha256:fb5ad5afa47447dd7eb090ad29bdb3a8181b0e758a3b03ba6ed8ca48d68d11a7"}, + {file = "cohere-5.20.1-py3-none-any.whl", hash = "sha256:d230fd13d95ba92ae927fce3dd497599b169883afc7954fe29b39fb8d5df5fc7"}, + {file = "cohere-5.20.1.tar.gz", hash = "sha256:50973f63d2c6138ff52ce37d8d6f78ccc539af4e8c43865e960d68e0bf835b6f"}, ] [package.dependencies] fastavro = ">=1.9.4,<2.0.0" httpx = ">=0.21.2" -httpx-sse = "0.4.0" pydantic = ">=1.9.2" -pydantic-core = ">=2.18.2,<3.0.0" +pydantic-core = ">=2.18.2" requests = ">=2.0.0,<3.0.0" tokenizers = ">=0.15,<1" types-requests = ">=2.0.0,<3.0.0" @@ -1111,14 +1121,14 @@ test = ["pytest", "ruff"] [[package]] name = "cyclopts" -version = "4.3.0" +version = "4.4.1" description = "Intuitive, easy CLIs based on type hints." optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "cyclopts-4.3.0-py3-none-any.whl", hash = "sha256:91a30b69faf128ada7cfeaefd7d9649dc222e8b2a8697f1fc99e4ee7b7ca44f3"}, - {file = "cyclopts-4.3.0.tar.gz", hash = "sha256:e95179cd0a959ce250ecfb2f0262a5996a92c1f9467bccad2f3d829e6833cef5"}, + {file = "cyclopts-4.4.1-py3-none-any.whl", hash = "sha256:67500e9fde90f335fddbf9c452d2e7c4f58209dffe52e7abb1e272796a963bde"}, + {file = "cyclopts-4.4.1.tar.gz", hash = "sha256:368a404926b46a49dc328a33ccd7e55ba879296a28e64a42afe2f6667704cecf"}, ] [package.dependencies] @@ -1129,8 +1139,9 @@ rich-rst = ">=1.3.1,<2.0.0" [package.extras] debug = ["ipdb (>=0.13.9)", "line-profiler (>=3.5.1)"] -dev = ["coverage[toml] (>=5.1)", "pre-commit (>=2.16.0)", "pydantic (>=2.11.2,<3.0.0)", "pytest (>=8.2.0)", "pytest-cov (>=3.0.0)", "pytest-mock (>=3.7.0)", "pyyaml (>=6.0.1)", "toml (>=0.10.2,<1.0.0)", "trio (>=0.10.0)"] +dev = ["coverage[toml] (>=5.1)", "mkdocs (>=1.4.0)", "pre-commit (>=2.16.0)", "pydantic (>=2.11.2,<3.0.0)", "pytest (>=8.2.0)", "pytest-cov (>=3.0.0)", "pytest-mock (>=3.7.0)", "pyyaml (>=6.0.1)", "syrupy (>=4.0.0)", "toml (>=0.10.2,<1.0.0)", "trio (>=0.10.0)"] docs = ["gitpython (>=3.1.31)", "myst-parser[linkify] (>=3.0.1,<5.0.0)", "sphinx (>=7.4.7,<8.2.0)", "sphinx-autodoc-typehints (>=1.25.2,<4.0.0)", "sphinx-copybutton (>=0.5,<1.0)", "sphinx-rtd-dark-mode (>=1.3.0,<2.0.0)", "sphinx-rtd-theme (>=3.0.0,<4.0.0)"] +mkdocs = ["markdown (>=3.3)", "mkdocs (>=1.4.0)", "pymdown-extensions (>=10.0)"] toml = ["tomli (>=2.0.0) ; python_version < \"3.11\""] trio = ["trio (>=0.10.0)"] yaml = ["pyyaml (>=6.0.1)"] @@ -1221,14 +1232,14 @@ postgres = ["psycopg (>=3.2.3,<4.0.0)"] [[package]] name = "django" -version = "5.2.8" +version = "5.2.9" description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "django-5.2.8-py3-none-any.whl", hash = "sha256:37e687f7bd73ddf043e2b6b97cfe02fcbb11f2dbb3adccc6a2b18c6daa054d7f"}, - {file = "django-5.2.8.tar.gz", hash = "sha256:23254866a5bb9a2cfa6004e8b809ec6246eba4b58a7589bc2772f1bcc8456c7f"}, + {file = "django-5.2.9-py3-none-any.whl", hash = "sha256:3a4ea88a70370557ab1930b332fd2887a9f48654261cdffda663fef5976bb00a"}, + {file = "django-5.2.9.tar.gz", hash = "sha256:16b5ccfc5e8c27e6c0561af551d2ea32852d7352c67d452ae3e76b4f6b2ca495"}, ] [package.dependencies] @@ -1335,36 +1346,36 @@ python-ipware = ">=2.0.3" [[package]] name = "django-mjml" -version = "1.4" +version = "1.5" description = "Use MJML in Django templates" optional = false -python-versions = ">=3.6" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "django_mjml-1.4-py3-none-any.whl", hash = "sha256:09dc440fcec64f3656b17646439336e6c15c5987103dfb6fe23eb1f1bf734d11"}, - {file = "django_mjml-1.4.tar.gz", hash = "sha256:a805b3721de92a4972bb6bd4a3bffa91579420e48297a55f3ffef6d8e926b0b4"}, + {file = "django_mjml-1.5-py3-none-any.whl", hash = "sha256:216faa121e6fdf6eee55061e63a6958a6ab04c6094323ebb8db42385c583ff2d"}, + {file = "django_mjml-1.5.tar.gz", hash = "sha256:3a6048859f2f9023ffdef95a63595ad66a572d9c8f4be06d3b2f6d84d412be8b"}, ] [package.dependencies] -django = ">=2.2,<5.3" +django = ">=2.2,<6.1" [package.extras] requests = ["requests (>=2.24)"] [[package]] name = "django-ninja" -version = "1.5.0" +version = "1.5.1" description = "Django Ninja - Fast Django REST framework" optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "django_ninja-1.5.0-py3-none-any.whl", hash = "sha256:e305fc42588406a202d4479263b501813ec863a3a4e11cb091fb905ecdf9bc62"}, - {file = "django_ninja-1.5.0.tar.gz", hash = "sha256:181bc8266a684be8c4cdd8f555d8ccbbc72e9fad86a5928ddccdd13faf73a1c5"}, + {file = "django_ninja-1.5.1-py3-none-any.whl", hash = "sha256:135aaa1117dce8dfd7a1e80b4487a8cccee3a4182c3c8b562d08ea94e4d2cbdf"}, + {file = "django_ninja-1.5.1.tar.gz", hash = "sha256:6acda68a64d60934c6fdccb4d97c3ac7f02cfefd78a5d87ae053effe081b17c7"}, ] [package.dependencies] -Django = ">=3.1,<6.0" +Django = ">=3.1,<6.1" pydantic = ">=2.0,<3.0.0" [package.extras] @@ -1407,18 +1418,18 @@ sentry-sdk = ">=1.5.5" [[package]] name = "django-q2" -version = "1.8.0" +version = "1.9.0" description = "A multiprocessing distributed task queue for Django" optional = false python-versions = "<4,>=3.9" groups = ["main"] files = [ - {file = "django_q2-1.8.0-py3-none-any.whl", hash = "sha256:78aaaf18dff1ad3e35bcf6556666f2c26494120f0b75961c13206e37d180dfaa"}, - {file = "django_q2-1.8.0.tar.gz", hash = "sha256:e86b9625c0ce57a5ae31ca8fd7e798d63b9ef91a227c52f8b47536ba50b2b284"}, + {file = "django_q2-1.9.0-py3-none-any.whl", hash = "sha256:4eded27644b0ffb291839c9f9c12fea6c0dec63ebd891fa6881b0b446098a49d"}, + {file = "django_q2-1.9.0.tar.gz", hash = "sha256:ef7facca96fae9c11ddf2c5252d3817975c7a9a6d989fa0d65487d8823d57799"}, ] [package.dependencies] -django = ">=4.2,<6" +django = ">=4.2" django-picklefield = ">=3.1,<4.0" django-q-sentry = {version = ">=0.1", optional = true, markers = "extra == \"sentry\""} @@ -1580,14 +1591,14 @@ test = ["pytest"] [[package]] name = "docutils" -version = "0.22.3" +version = "0.22.4" description = "Docutils -- Python Documentation Utilities" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "docutils-0.22.3-py3-none-any.whl", hash = "sha256:bd772e4aca73aff037958d44f2be5229ded4c09927fcf8690c577b66234d6ceb"}, - {file = "docutils-0.22.3.tar.gz", hash = "sha256:21486ae730e4ca9f622677b1412b879af1791efcfba517e4c6f60be543fc8cdd"}, + {file = "docutils-0.22.4-py3-none-any.whl", hash = "sha256:d0013f540772d1420576855455d050a2180186c91c15779301ac2ccb3eeb68de"}, + {file = "docutils-0.22.4.tar.gz", hash = "sha256:4db53b1fde9abecbb74d91230d32ab626d94f6badfc575d6db9194a49df29968"}, ] [[package]] @@ -1658,19 +1669,36 @@ dev = ["coverage", "pytest (>=7.4.4)"] [[package]] name = "eval-type-backport" -version = "0.3.0" +version = "0.3.1" description = "Like `typing._eval_type`, but lets older Python versions use newer typing features." optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" groups = ["main"] files = [ - {file = "eval_type_backport-0.3.0-py3-none-any.whl", hash = "sha256:975a10a0fe333c8b6260d7fdb637698c9a16c3a9e3b6eb943fee6a6f67a37fe8"}, - {file = "eval_type_backport-0.3.0.tar.gz", hash = "sha256:1638210401e184ff17f877e9a2fa076b60b5838790f4532a21761cc2be67aea1"}, + {file = "eval_type_backport-0.3.1-py3-none-any.whl", hash = "sha256:279ab641905e9f11129f56a8a78f493518515b83402b860f6f06dd7c011fdfa8"}, + {file = "eval_type_backport-0.3.1.tar.gz", hash = "sha256:57e993f7b5b69d271e37482e62f74e76a0276c82490cf8e4f0dffeb6b332d5ed"}, ] [package.extras] tests = ["pytest"] +[[package]] +name = "exa-py" +version = "2.0.2" +description = "Python SDK for Exa API." +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "exa_py-2.0.2-py3-none-any.whl", hash = "sha256:6b326d558d618dc72a9b048d9228197f6d63dfb890a7d9b6dbdcfdfd63e4040a"}, + {file = "exa_py-2.0.2.tar.gz", hash = "sha256:229210ddaddd3161319226306165605c97faa86c50c3ab8adcb9b7efce0b0f89"}, +] + +[package.dependencies] +openai = ">=1.10.0" +requests = "*" +typing-extensions = "*" + [[package]] name = "exceptiongroup" version = "1.3.1" @@ -1704,28 +1732,53 @@ files = [ [package.extras] tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich ; python_version >= \"3.11\""] +[[package]] +name = "fakeredis" +version = "2.33.0" +description = "Python implementation of redis API, can be used for testing purposes." +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "fakeredis-2.33.0-py3-none-any.whl", hash = "sha256:de535f3f9ccde1c56672ab2fdd6a8efbc4f2619fc2f1acc87b8737177d71c965"}, + {file = "fakeredis-2.33.0.tar.gz", hash = "sha256:d7bc9a69d21df108a6451bbffee23b3eba432c21a654afc7ff2d295428ec5770"}, +] + +[package.dependencies] +lupa = {version = ">=2.1", optional = true, markers = "extra == \"lua\""} +redis = {version = ">=4.3", markers = "python_version > \"3.8\""} +sortedcontainers = ">=2" + +[package.extras] +bf = ["pyprobables (>=0.6)"] +cf = ["pyprobables (>=0.6)"] +json = ["jsonpath-ng (>=1.6)"] +lua = ["lupa (>=2.1)"] +probabilistic = ["pyprobables (>=0.6)"] +valkey = ["valkey (>=6) ; python_version >= \"3.8\""] + [[package]] name = "fastapi" -version = "0.122.0" +version = "0.127.1" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "fastapi-0.122.0-py3-none-any.whl", hash = "sha256:a456e8915dfc6c8914a50d9651133bd47ec96d331c5b44600baa635538a30d67"}, - {file = "fastapi-0.122.0.tar.gz", hash = "sha256:cd9b5352031f93773228af8b4c443eedc2ac2aa74b27780387b853c3726fb94b"}, + {file = "fastapi-0.127.1-py3-none-any.whl", hash = "sha256:31d670a4f9373cc6d7994420f98e4dc46ea693145207abc39696746c83a44430"}, + {file = "fastapi-0.127.1.tar.gz", hash = "sha256:946a87ee5d931883b562b6bada787d6c8178becee2683cb3f9b980d593206359"}, ] [package.dependencies] annotated-doc = ">=0.0.2" -pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" +pydantic = ">=2.7.0" starlette = ">=0.40.0,<0.51.0" typing-extensions = ">=4.8.0" [package.extras] all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=3.1.5)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] -standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"] -standard-no-fastapi-cloud-cli = ["email-validator (>=2.0.0)", "fastapi-cli[standard-no-fastapi-cloud-cli] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"] +standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"] +standard-no-fastapi-cloud-cli = ["email-validator (>=2.0.0)", "fastapi-cli[standard-no-fastapi-cloud-cli] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"] [[package]] name = "fastavro" @@ -1792,14 +1845,14 @@ zstandard = ["zstandard"] [[package]] name = "fastmcp" -version = "2.13.1" +version = "2.14.0" description = "The fast, Pythonic way to build MCP servers and clients." optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "fastmcp-2.13.1-py3-none-any.whl", hash = "sha256:7a78b19785c4ec04a758d920c312769a497e3f6ab4c80feed504df1ed7de9f3c"}, - {file = "fastmcp-2.13.1.tar.gz", hash = "sha256:b9c664c51f1ff47c698225e7304267ae29a51913f681bd49e442b8682f9a5f90"}, + {file = "fastmcp-2.14.0-py3-none-any.whl", hash = "sha256:7b374c0bcaf1ef1ef46b9255ea84c607f354291eaf647ff56a47c69f5ec0c204"}, + {file = "fastmcp-2.14.0.tar.gz", hash = "sha256:c1f487b36a3e4b043dbf3330e588830047df2e06f8ef0920d62dfb34d0905727"}, ] [package.dependencies] @@ -1808,11 +1861,12 @@ cyclopts = ">=4.0.0" exceptiongroup = ">=1.2.2" httpx = ">=0.28.1" jsonschema-path = ">=0.3.4" -mcp = ">=1.19.0,<1.21.1 || >1.21.1,<2.0.0" +mcp = ">=1.23.1" openapi-pydantic = ">=0.5.1" platformdirs = ">=4.0.0" -py-key-value-aio = {version = ">=0.2.8,<0.3.0", extras = ["disk", "keyring", "memory"]} +py-key-value-aio = {version = ">=0.3.0,<0.4.0", extras = ["disk", "keyring", "memory"]} pydantic = {version = ">=2.11.7", extras = ["email"]} +pydocket = ">=0.15.2" pyperclip = ">=1.9.0" python-dotenv = ">=1.1.0" rich = ">=13.9.4" @@ -1927,14 +1981,14 @@ sgmllib3k = "*" [[package]] name = "filelock" -version = "3.20.0" +version = "3.20.1" description = "A platform independent file lock." optional = false python-versions = ">=3.10" groups = ["main", "dev"] files = [ - {file = "filelock-3.20.0-py3-none-any.whl", hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2"}, - {file = "filelock-3.20.0.tar.gz", hash = "sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4"}, + {file = "filelock-3.20.1-py3-none-any.whl", hash = "sha256:15d9e9a67306188a44baa72f569d2bfd803076269365fdea0934385da4dc361a"}, + {file = "filelock-3.20.1.tar.gz", hash = "sha256:b8360948b351b80f420878d8516519a2204b07aefcdcfd24912a5d33127f188c"}, ] [[package]] @@ -1951,70 +2005,62 @@ files = [ [[package]] name = "fonttools" -version = "4.60.1" +version = "4.61.1" description = "Tools to manipulate font files" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["main"] files = [ - {file = "fonttools-4.60.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9a52f254ce051e196b8fe2af4634c2d2f02c981756c6464dc192f1b6050b4e28"}, - {file = "fonttools-4.60.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7420a2696a44650120cdd269a5d2e56a477e2bfa9d95e86229059beb1c19e15"}, - {file = "fonttools-4.60.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee0c0b3b35b34f782afc673d503167157094a16f442ace7c6c5e0ca80b08f50c"}, - {file = "fonttools-4.60.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:282dafa55f9659e8999110bd8ed422ebe1c8aecd0dc396550b038e6c9a08b8ea"}, - {file = "fonttools-4.60.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4ba4bd646e86de16160f0fb72e31c3b9b7d0721c3e5b26b9fa2fc931dfdb2652"}, - {file = "fonttools-4.60.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0b0835ed15dd5b40d726bb61c846a688f5b4ce2208ec68779bc81860adb5851a"}, - {file = "fonttools-4.60.1-cp310-cp310-win32.whl", hash = "sha256:1525796c3ffe27bb6268ed2a1bb0dcf214d561dfaf04728abf01489eb5339dce"}, - {file = "fonttools-4.60.1-cp310-cp310-win_amd64.whl", hash = "sha256:268ecda8ca6cb5c4f044b1fb9b3b376e8cd1b361cef275082429dc4174907038"}, - {file = "fonttools-4.60.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7b4c32e232a71f63a5d00259ca3d88345ce2a43295bb049d21061f338124246f"}, - {file = "fonttools-4.60.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3630e86c484263eaac71d117085d509cbcf7b18f677906824e4bace598fb70d2"}, - {file = "fonttools-4.60.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5c1015318e4fec75dd4943ad5f6a206d9727adf97410d58b7e32ab644a807914"}, - {file = "fonttools-4.60.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e6c58beb17380f7c2ea181ea11e7db8c0ceb474c9dd45f48e71e2cb577d146a1"}, - {file = "fonttools-4.60.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ec3681a0cb34c255d76dd9d865a55f260164adb9fa02628415cdc2d43ee2c05d"}, - {file = "fonttools-4.60.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f4b5c37a5f40e4d733d3bbaaef082149bee5a5ea3156a785ff64d949bd1353fa"}, - {file = "fonttools-4.60.1-cp311-cp311-win32.whl", hash = "sha256:398447f3d8c0c786cbf1209711e79080a40761eb44b27cdafffb48f52bcec258"}, - {file = "fonttools-4.60.1-cp311-cp311-win_amd64.whl", hash = "sha256:d066ea419f719ed87bc2c99a4a4bfd77c2e5949cb724588b9dd58f3fd90b92bf"}, - {file = "fonttools-4.60.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:7b0c6d57ab00dae9529f3faf187f2254ea0aa1e04215cf2f1a8ec277c96661bc"}, - {file = "fonttools-4.60.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:839565cbf14645952d933853e8ade66a463684ed6ed6c9345d0faf1f0e868877"}, - {file = "fonttools-4.60.1-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8177ec9676ea6e1793c8a084a90b65a9f778771998eb919d05db6d4b1c0b114c"}, - {file = "fonttools-4.60.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:996a4d1834524adbb423385d5a629b868ef9d774670856c63c9a0408a3063401"}, - {file = "fonttools-4.60.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a46b2f450bc79e06ef3b6394f0c68660529ed51692606ad7f953fc2e448bc903"}, - {file = "fonttools-4.60.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6ec722ee589e89a89f5b7574f5c45604030aa6ae24cb2c751e2707193b466fed"}, - {file = "fonttools-4.60.1-cp312-cp312-win32.whl", hash = "sha256:b2cf105cee600d2de04ca3cfa1f74f1127f8455b71dbad02b9da6ec266e116d6"}, - {file = "fonttools-4.60.1-cp312-cp312-win_amd64.whl", hash = "sha256:992775c9fbe2cf794786fa0ffca7f09f564ba3499b8fe9f2f80bd7197db60383"}, - {file = "fonttools-4.60.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6f68576bb4bbf6060c7ab047b1574a1ebe5c50a17de62830079967b211059ebb"}, - {file = "fonttools-4.60.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:eedacb5c5d22b7097482fa834bda0dafa3d914a4e829ec83cdea2a01f8c813c4"}, - {file = "fonttools-4.60.1-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b33a7884fabd72bdf5f910d0cf46be50dce86a0362a65cfc746a4168c67eb96c"}, - {file = "fonttools-4.60.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2409d5fb7b55fd70f715e6d34e7a6e4f7511b8ad29a49d6df225ee76da76dd77"}, - {file = "fonttools-4.60.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c8651e0d4b3bdeda6602b85fdc2abbefc1b41e573ecb37b6779c4ca50753a199"}, - {file = "fonttools-4.60.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:145daa14bf24824b677b9357c5e44fd8895c2a8f53596e1b9ea3496081dc692c"}, - {file = "fonttools-4.60.1-cp313-cp313-win32.whl", hash = "sha256:2299df884c11162617a66b7c316957d74a18e3758c0274762d2cc87df7bc0272"}, - {file = "fonttools-4.60.1-cp313-cp313-win_amd64.whl", hash = "sha256:a3db56f153bd4c5c2b619ab02c5db5192e222150ce5a1bc10f16164714bc39ac"}, - {file = "fonttools-4.60.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:a884aef09d45ba1206712c7dbda5829562d3fea7726935d3289d343232ecb0d3"}, - {file = "fonttools-4.60.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8a44788d9d91df72d1a5eac49b31aeb887a5f4aab761b4cffc4196c74907ea85"}, - {file = "fonttools-4.60.1-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e852d9dda9f93ad3651ae1e3bb770eac544ec93c3807888798eccddf84596537"}, - {file = "fonttools-4.60.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:154cb6ee417e417bf5f7c42fe25858c9140c26f647c7347c06f0cc2d47eff003"}, - {file = "fonttools-4.60.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:5664fd1a9ea7f244487ac8f10340c4e37664675e8667d6fee420766e0fb3cf08"}, - {file = "fonttools-4.60.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:583b7f8e3c49486e4d489ad1deacfb8d5be54a8ef34d6df824f6a171f8511d99"}, - {file = "fonttools-4.60.1-cp314-cp314-win32.whl", hash = "sha256:66929e2ea2810c6533a5184f938502cfdaea4bc3efb7130d8cc02e1c1b4108d6"}, - {file = "fonttools-4.60.1-cp314-cp314-win_amd64.whl", hash = "sha256:f3d5be054c461d6a2268831f04091dc82753176f6ea06dc6047a5e168265a987"}, - {file = "fonttools-4.60.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:b6379e7546ba4ae4b18f8ae2b9bc5960936007a1c0e30b342f662577e8bc3299"}, - {file = "fonttools-4.60.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9d0ced62b59e0430b3690dbc5373df1c2aa7585e9a8ce38eff87f0fd993c5b01"}, - {file = "fonttools-4.60.1-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:875cb7764708b3132637f6c5fb385b16eeba0f7ac9fa45a69d35e09b47045801"}, - {file = "fonttools-4.60.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a184b2ea57b13680ab6d5fbde99ccef152c95c06746cb7718c583abd8f945ccc"}, - {file = "fonttools-4.60.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:026290e4ec76583881763fac284aca67365e0be9f13a7fb137257096114cb3bc"}, - {file = "fonttools-4.60.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f0e8817c7d1a0c2eedebf57ef9a9896f3ea23324769a9a2061a80fe8852705ed"}, - {file = "fonttools-4.60.1-cp314-cp314t-win32.whl", hash = "sha256:1410155d0e764a4615774e5c2c6fc516259fe3eca5882f034eb9bfdbee056259"}, - {file = "fonttools-4.60.1-cp314-cp314t-win_amd64.whl", hash = "sha256:022beaea4b73a70295b688f817ddc24ed3e3418b5036ffcd5658141184ef0d0c"}, - {file = "fonttools-4.60.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:122e1a8ada290423c493491d002f622b1992b1ab0b488c68e31c413390dc7eb2"}, - {file = "fonttools-4.60.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a140761c4ff63d0cb9256ac752f230460ee225ccef4ad8f68affc723c88e2036"}, - {file = "fonttools-4.60.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0eae96373e4b7c9e45d099d7a523444e3554360927225c1cdae221a58a45b856"}, - {file = "fonttools-4.60.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:596ecaca36367027d525b3b426d8a8208169d09edcf8c7506aceb3a38bfb55c7"}, - {file = "fonttools-4.60.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2ee06fc57512144d8b0445194c2da9f190f61ad51e230f14836286470c99f854"}, - {file = "fonttools-4.60.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b42d86938e8dda1cd9a1a87a6d82f1818eaf933348429653559a458d027446da"}, - {file = "fonttools-4.60.1-cp39-cp39-win32.whl", hash = "sha256:8b4eb332f9501cb1cd3d4d099374a1e1306783ff95489a1026bde9eb02ccc34a"}, - {file = "fonttools-4.60.1-cp39-cp39-win_amd64.whl", hash = "sha256:7473a8ed9ed09aeaa191301244a5a9dbe46fe0bf54f9d6cd21d83044c3321217"}, - {file = "fonttools-4.60.1-py3-none-any.whl", hash = "sha256:906306ac7afe2156fcf0042173d6ebbb05416af70f6b370967b47f8f00103bbb"}, - {file = "fonttools-4.60.1.tar.gz", hash = "sha256:ef00af0439ebfee806b25f24c8f92109157ff3fac5731dc7867957812e87b8d9"}, + {file = "fonttools-4.61.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c7db70d57e5e1089a274cbb2b1fd635c9a24de809a231b154965d415d6c6d24"}, + {file = "fonttools-4.61.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5fe9fd43882620017add5eabb781ebfbc6998ee49b35bd7f8f79af1f9f99a958"}, + {file = "fonttools-4.61.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8db08051fc9e7d8bc622f2112511b8107d8f27cd89e2f64ec45e9825e8288da"}, + {file = "fonttools-4.61.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a76d4cb80f41ba94a6691264be76435e5f72f2cb3cab0b092a6212855f71c2f6"}, + {file = "fonttools-4.61.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a13fc8aeb24bad755eea8f7f9d409438eb94e82cf86b08fe77a03fbc8f6a96b1"}, + {file = "fonttools-4.61.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b846a1fcf8beadeb9ea4f44ec5bdde393e2f1569e17d700bfc49cd69bde75881"}, + {file = "fonttools-4.61.1-cp310-cp310-win32.whl", hash = "sha256:78a7d3ab09dc47ac1a363a493e6112d8cabed7ba7caad5f54dbe2f08676d1b47"}, + {file = "fonttools-4.61.1-cp310-cp310-win_amd64.whl", hash = "sha256:eff1ac3cc66c2ac7cda1e64b4e2f3ffef474b7335f92fc3833fc632d595fcee6"}, + {file = "fonttools-4.61.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c6604b735bb12fef8e0efd5578c9fb5d3d8532d5001ea13a19cddf295673ee09"}, + {file = "fonttools-4.61.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5ce02f38a754f207f2f06557523cd39a06438ba3aafc0639c477ac409fc64e37"}, + {file = "fonttools-4.61.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:77efb033d8d7ff233385f30c62c7c79271c8885d5c9657d967ede124671bbdfb"}, + {file = "fonttools-4.61.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:75c1a6dfac6abd407634420c93864a1e274ebc1c7531346d9254c0d8f6ca00f9"}, + {file = "fonttools-4.61.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0de30bfe7745c0d1ffa2b0b7048fb7123ad0d71107e10ee090fa0b16b9452e87"}, + {file = "fonttools-4.61.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:58b0ee0ab5b1fc9921eccfe11d1435added19d6494dde14e323f25ad2bc30c56"}, + {file = "fonttools-4.61.1-cp311-cp311-win32.whl", hash = "sha256:f79b168428351d11e10c5aeb61a74e1851ec221081299f4cf56036a95431c43a"}, + {file = "fonttools-4.61.1-cp311-cp311-win_amd64.whl", hash = "sha256:fe2efccb324948a11dd09d22136fe2ac8a97d6c1347cf0b58a911dcd529f66b7"}, + {file = "fonttools-4.61.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f3cb4a569029b9f291f88aafc927dd53683757e640081ca8c412781ea144565e"}, + {file = "fonttools-4.61.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41a7170d042e8c0024703ed13b71893519a1a6d6e18e933e3ec7507a2c26a4b2"}, + {file = "fonttools-4.61.1-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:10d88e55330e092940584774ee5e8a6971b01fc2f4d3466a1d6c158230880796"}, + {file = "fonttools-4.61.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:15acc09befd16a0fb8a8f62bc147e1a82817542d72184acca9ce6e0aeda9fa6d"}, + {file = "fonttools-4.61.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e6bcdf33aec38d16508ce61fd81838f24c83c90a1d1b8c68982857038673d6b8"}, + {file = "fonttools-4.61.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5fade934607a523614726119164ff621e8c30e8fa1ffffbbd358662056ba69f0"}, + {file = "fonttools-4.61.1-cp312-cp312-win32.whl", hash = "sha256:75da8f28eff26defba42c52986de97b22106cb8f26515b7c22443ebc9c2d3261"}, + {file = "fonttools-4.61.1-cp312-cp312-win_amd64.whl", hash = "sha256:497c31ce314219888c0e2fce5ad9178ca83fe5230b01a5006726cdf3ac9f24d9"}, + {file = "fonttools-4.61.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c56c488ab471628ff3bfa80964372fc13504ece601e0d97a78ee74126b2045c"}, + {file = "fonttools-4.61.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dc492779501fa723b04d0ab1f5be046797fee17d27700476edc7ee9ae535a61e"}, + {file = "fonttools-4.61.1-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:64102ca87e84261419c3747a0d20f396eb024bdbeb04c2bfb37e2891f5fadcb5"}, + {file = "fonttools-4.61.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c1b526c8d3f615a7b1867f38a9410849c8f4aef078535742198e942fba0e9bd"}, + {file = "fonttools-4.61.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:41ed4b5ec103bd306bb68f81dc166e77409e5209443e5773cb4ed837bcc9b0d3"}, + {file = "fonttools-4.61.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b501c862d4901792adaec7c25b1ecc749e2662543f68bb194c42ba18d6eec98d"}, + {file = "fonttools-4.61.1-cp313-cp313-win32.whl", hash = "sha256:4d7092bb38c53bbc78e9255a59158b150bcdc115a1e3b3ce0b5f267dc35dd63c"}, + {file = "fonttools-4.61.1-cp313-cp313-win_amd64.whl", hash = "sha256:21e7c8d76f62ab13c9472ccf74515ca5b9a761d1bde3265152a6dc58700d895b"}, + {file = "fonttools-4.61.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fff4f534200a04b4a36e7ae3cb74493afe807b517a09e99cb4faa89a34ed6ecd"}, + {file = "fonttools-4.61.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d9203500f7c63545b4ce3799319fe4d9feb1a1b89b28d3cb5abd11b9dd64147e"}, + {file = "fonttools-4.61.1-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fa646ecec9528bef693415c79a86e733c70a4965dd938e9a226b0fc64c9d2e6c"}, + {file = "fonttools-4.61.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:11f35ad7805edba3aac1a3710d104592df59f4b957e30108ae0ba6c10b11dd75"}, + {file = "fonttools-4.61.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b931ae8f62db78861b0ff1ac017851764602288575d65b8e8ff1963fed419063"}, + {file = "fonttools-4.61.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b148b56f5de675ee16d45e769e69f87623a4944f7443850bf9a9376e628a89d2"}, + {file = "fonttools-4.61.1-cp314-cp314-win32.whl", hash = "sha256:9b666a475a65f4e839d3d10473fad6d47e0a9db14a2f4a224029c5bfde58ad2c"}, + {file = "fonttools-4.61.1-cp314-cp314-win_amd64.whl", hash = "sha256:4f5686e1fe5fce75d82d93c47a438a25bf0d1319d2843a926f741140b2b16e0c"}, + {file = "fonttools-4.61.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:e76ce097e3c57c4bcb67c5aa24a0ecdbd9f74ea9219997a707a4061fbe2707aa"}, + {file = "fonttools-4.61.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:9cfef3ab326780c04d6646f68d4b4742aae222e8b8ea1d627c74e38afcbc9d91"}, + {file = "fonttools-4.61.1-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a75c301f96db737e1c5ed5fd7d77d9c34466de16095a266509e13da09751bd19"}, + {file = "fonttools-4.61.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:91669ccac46bbc1d09e9273546181919064e8df73488ea087dcac3e2968df9ba"}, + {file = "fonttools-4.61.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c33ab3ca9d3ccd581d58e989d67554e42d8d4ded94ab3ade3508455fe70e65f7"}, + {file = "fonttools-4.61.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:664c5a68ec406f6b1547946683008576ef8b38275608e1cee6c061828171c118"}, + {file = "fonttools-4.61.1-cp314-cp314t-win32.whl", hash = "sha256:aed04cabe26f30c1647ef0e8fbb207516fd40fe9472e9439695f5c6998e60ac5"}, + {file = "fonttools-4.61.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2180f14c141d2f0f3da43f3a81bc8aa4684860f6b0e6f9e165a4831f24e6a23b"}, + {file = "fonttools-4.61.1-py3-none-any.whl", hash = "sha256:17d2bf5d541add43822bcf0c43d7d847b160c9bb01d15d5007d84e2217aaa371"}, + {file = "fonttools-4.61.1.tar.gz", hash = "sha256:6675329885c44657f826ef01d9e4fb33b9158e9d93c537d84ad8399539bc6f69"}, ] [package.dependencies] @@ -2023,16 +2069,16 @@ brotlicffi = {version = ">=0.8.0", optional = true, markers = "platform_python_i zopfli = {version = ">=0.1.4", optional = true, markers = "extra == \"woff\""} [package.extras] -all = ["brotli (>=1.0.1) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\"", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres ; platform_python_implementation == \"PyPy\"", "pycairo", "scipy ; platform_python_implementation != \"PyPy\"", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0) ; python_version <= \"3.12\"", "xattr ; sys_platform == \"darwin\"", "zopfli (>=0.1.4)"] +all = ["brotli (>=1.0.1) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\"", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres ; platform_python_implementation == \"PyPy\"", "pycairo", "scipy ; platform_python_implementation != \"PyPy\"", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.45.0)", "unicodedata2 (>=17.0.0) ; python_version <= \"3.14\"", "xattr ; sys_platform == \"darwin\"", "zopfli (>=0.1.4)"] graphite = ["lz4 (>=1.7.4.2)"] interpolatable = ["munkres ; platform_python_implementation == \"PyPy\"", "pycairo", "scipy ; platform_python_implementation != \"PyPy\""] lxml = ["lxml (>=4.0)"] pathops = ["skia-pathops (>=0.5.0)"] plot = ["matplotlib"] -repacker = ["uharfbuzz (>=0.23.0)"] +repacker = ["uharfbuzz (>=0.45.0)"] symfont = ["sympy"] type1 = ["xattr ; sys_platform == \"darwin\""] -unicode = ["unicodedata2 (>=15.1.0) ; python_version <= \"3.12\""] +unicode = ["unicodedata2 (>=17.0.0) ; python_version <= \"3.14\""] woff = ["brotli (>=1.0.1) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\"", "zopfli (>=0.1.4)"] [[package]] @@ -2177,14 +2223,14 @@ files = [ [[package]] name = "fsspec" -version = "2025.10.0" +version = "2025.12.0" description = "File-system specification" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["main"] files = [ - {file = "fsspec-2025.10.0-py3-none-any.whl", hash = "sha256:7c7712353ae7d875407f97715f0e1ffcc21e33d5b24556cb1e090ae9409ec61d"}, - {file = "fsspec-2025.10.0.tar.gz", hash = "sha256:b6789427626f068f9a83ca4e8a3cc050850b6c0f71f99ddb4f542b8266a26a59"}, + {file = "fsspec-2025.12.0-py3-none-any.whl", hash = "sha256:8bf1fe301b7d8acfa6e8571e3b1c3d158f909666642431cc78a1b7b4dbc5ec5b"}, + {file = "fsspec-2025.12.0.tar.gz", hash = "sha256:c505de011584597b1060ff778bb664c1bc022e87921b0e4f10cc9c44f9635973"}, ] [package.extras] @@ -2217,14 +2263,14 @@ tqdm = ["tqdm"] [[package]] name = "genai-prices" -version = "0.0.47" +version = "0.0.49" description = "Calculate prices for calling LLM inference APIs." optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "genai_prices-0.0.47-py3-none-any.whl", hash = "sha256:735e45950d2299276f2c00cd18075b77a124cd24ee58243f236ee29af3210594"}, - {file = "genai_prices-0.0.47.tar.gz", hash = "sha256:3b8c514f0ce5818b3944a371861586ed9bfe10d02598e62c350b5bd2916d03c2"}, + {file = "genai_prices-0.0.49-py3-none-any.whl", hash = "sha256:dd3efbebcd865d89cd849793530729e7f7e1ca59d2b17a091ad1aa6aa76daf0d"}, + {file = "genai_prices-0.0.49.tar.gz", hash = "sha256:a7f98f1537e6f89ed54f1cd8f560806e187033dcb42554fbecd4d635567120c5"}, ] [package.dependencies] @@ -2233,23 +2279,25 @@ pydantic = ">=2.10" [[package]] name = "google-auth" -version = "2.43.0" +version = "2.45.0" description = "Google Authentication Library" optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "google_auth-2.43.0-py2.py3-none-any.whl", hash = "sha256:af628ba6fa493f75c7e9dbe9373d148ca9f4399b5ea29976519e0a3848eddd16"}, - {file = "google_auth-2.43.0.tar.gz", hash = "sha256:88228eee5fc21b62a1b5fe773ca15e67778cb07dc8363adcb4a8827b52d81483"}, + {file = "google_auth-2.45.0-py2.py3-none-any.whl", hash = "sha256:82344e86dc00410ef5382d99be677c6043d72e502b625aa4f4afa0bdacca0f36"}, + {file = "google_auth-2.45.0.tar.gz", hash = "sha256:90d3f41b6b72ea72dd9811e765699ee491ab24139f34ebf1ca2b9cc0c38708f3"}, ] [package.dependencies] cachetools = ">=2.0.0,<7.0" pyasn1-modules = ">=0.2.1" +requests = {version = ">=2.20.0,<3.0.0", optional = true, markers = "extra == \"requests\""} rsa = ">=3.1.4,<5" [package.extras] aiohttp = ["aiohttp (>=3.6.2,<4.0.0)", "requests (>=2.20.0,<3.0.0)"] +cryptography = ["cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (>=38.0.3)"] enterprise-cert = ["cryptography", "pyopenssl"] pyjwt = ["cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (>=38.0.3)", "pyjwt (>=2.0)"] pyopenssl = ["cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] @@ -2260,22 +2308,24 @@ urllib3 = ["packaging", "urllib3"] [[package]] name = "google-genai" -version = "1.52.0" +version = "1.56.0" description = "GenAI Python SDK" optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "google_genai-1.52.0-py3-none-any.whl", hash = "sha256:c8352b9f065ae14b9322b949c7debab8562982f03bf71d44130cd2b798c20743"}, - {file = "google_genai-1.52.0.tar.gz", hash = "sha256:a74e8a4b3025f23aa98d6a0f84783119012ca6c336fd68f73c5d2b11465d7fc5"}, + {file = "google_genai-1.56.0-py3-none-any.whl", hash = "sha256:9e6b11e0c105ead229368cb5849a480e4d0185519f8d9f538d61ecfcf193b052"}, + {file = "google_genai-1.56.0.tar.gz", hash = "sha256:0491af33c375f099777ae207d9621f044e27091fafad4c50e617eba32165e82f"}, ] [package.dependencies] anyio = ">=4.8.0,<5.0.0" -google-auth = ">=2.14.1,<3.0.0" +distro = ">=1.7.0,<2" +google-auth = {version = ">=2.45.0,<3.0.0", extras = ["requests"]} httpx = ">=0.28.1,<1.0.0" pydantic = ">=2.9.0,<3.0.0" requests = ">=2.28.1,<3.0.0" +sniffio = "*" tenacity = ">=8.2.3,<9.2.0" typing-extensions = ">=4.11.0,<5.0.0" websockets = ">=13.0.0,<15.1.0" @@ -2461,66 +2511,60 @@ requirements-txt = ["arxiv-client", "azure-storage-blob", "duckduckgo-search", " [[package]] name = "greenlet" -version = "3.2.4" +version = "3.3.0" description = "Lightweight in-process concurrent programming" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["main"] files = [ - {file = "greenlet-3.2.4-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:8c68325b0d0acf8d91dde4e6f930967dd52a5302cd4062932a6b2e7c2969f47c"}, - {file = "greenlet-3.2.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:94385f101946790ae13da500603491f04a76b6e4c059dab271b3ce2e283b2590"}, - {file = "greenlet-3.2.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f10fd42b5ee276335863712fa3da6608e93f70629c631bf77145021600abc23c"}, - {file = "greenlet-3.2.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c8c9e331e58180d0d83c5b7999255721b725913ff6bc6cf39fa2a45841a4fd4b"}, - {file = "greenlet-3.2.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:58b97143c9cc7b86fc458f215bd0932f1757ce649e05b640fea2e79b54cedb31"}, - {file = "greenlet-3.2.4-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c2ca18a03a8cfb5b25bc1cbe20f3d9a4c80d8c3b13ba3df49ac3961af0b1018d"}, - {file = "greenlet-3.2.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9fe0a28a7b952a21e2c062cd5756d34354117796c6d9215a87f55e38d15402c5"}, - {file = "greenlet-3.2.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8854167e06950ca75b898b104b63cc646573aa5fef1353d4508ecdd1ee76254f"}, - {file = "greenlet-3.2.4-cp310-cp310-win_amd64.whl", hash = "sha256:73f49b5368b5359d04e18d15828eecc1806033db5233397748f4ca813ff1056c"}, - {file = "greenlet-3.2.4-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:96378df1de302bc38e99c3a9aa311967b7dc80ced1dcc6f171e99842987882a2"}, - {file = "greenlet-3.2.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1ee8fae0519a337f2329cb78bd7a8e128ec0f881073d43f023c7b8d4831d5246"}, - {file = "greenlet-3.2.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:94abf90142c2a18151632371140b3dba4dee031633fe614cb592dbb6c9e17bc3"}, - {file = "greenlet-3.2.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:4d1378601b85e2e5171b99be8d2dc85f594c79967599328f95c1dc1a40f1c633"}, - {file = "greenlet-3.2.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0db5594dce18db94f7d1650d7489909b57afde4c580806b8d9203b6e79cdc079"}, - {file = "greenlet-3.2.4-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2523e5246274f54fdadbce8494458a2ebdcdbc7b802318466ac5606d3cded1f8"}, - {file = "greenlet-3.2.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1987de92fec508535687fb807a5cea1560f6196285a4cde35c100b8cd632cc52"}, - {file = "greenlet-3.2.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:55e9c5affaa6775e2c6b67659f3a71684de4c549b3dd9afca3bc773533d284fa"}, - {file = "greenlet-3.2.4-cp311-cp311-win_amd64.whl", hash = "sha256:9c40adce87eaa9ddb593ccb0fa6a07caf34015a29bf8d344811665b573138db9"}, - {file = "greenlet-3.2.4-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3b67ca49f54cede0186854a008109d6ee71f66bd57bb36abd6d0a0267b540cdd"}, - {file = "greenlet-3.2.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ddf9164e7a5b08e9d22511526865780a576f19ddd00d62f8a665949327fde8bb"}, - {file = "greenlet-3.2.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f28588772bb5fb869a8eb331374ec06f24a83a9c25bfa1f38b6993afe9c1e968"}, - {file = "greenlet-3.2.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:5c9320971821a7cb77cfab8d956fa8e39cd07ca44b6070db358ceb7f8797c8c9"}, - {file = "greenlet-3.2.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c60a6d84229b271d44b70fb6e5fa23781abb5d742af7b808ae3f6efd7c9c60f6"}, - {file = "greenlet-3.2.4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b3812d8d0c9579967815af437d96623f45c0f2ae5f04e366de62a12d83a8fb0"}, - {file = "greenlet-3.2.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:abbf57b5a870d30c4675928c37278493044d7c14378350b3aa5d484fa65575f0"}, - {file = "greenlet-3.2.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:20fb936b4652b6e307b8f347665e2c615540d4b42b3b4c8a321d8286da7e520f"}, - {file = "greenlet-3.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:a7d4e128405eea3814a12cc2605e0e6aedb4035bf32697f72deca74de4105e02"}, - {file = "greenlet-3.2.4-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:1a921e542453fe531144e91e1feedf12e07351b1cf6c9e8a3325ea600a715a31"}, - {file = "greenlet-3.2.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd3c8e693bff0fff6ba55f140bf390fa92c994083f838fece0f63be121334945"}, - {file = "greenlet-3.2.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:710638eb93b1fa52823aa91bf75326f9ecdfd5e0466f00789246a5280f4ba0fc"}, - {file = "greenlet-3.2.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c5111ccdc9c88f423426df3fd1811bfc40ed66264d35aa373420a34377efc98a"}, - {file = "greenlet-3.2.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d76383238584e9711e20ebe14db6c88ddcedc1829a9ad31a584389463b5aa504"}, - {file = "greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23768528f2911bcd7e475210822ffb5254ed10d71f4028387e5a99b4c6699671"}, - {file = "greenlet-3.2.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:00fadb3fedccc447f517ee0d3fd8fe49eae949e1cd0f6a611818f4f6fb7dc83b"}, - {file = "greenlet-3.2.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d25c5091190f2dc0eaa3f950252122edbbadbb682aa7b1ef2f8af0f8c0afefae"}, - {file = "greenlet-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b"}, - {file = "greenlet-3.2.4-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:49a30d5fda2507ae77be16479bdb62a660fa51b1eb4928b524975b3bde77b3c0"}, - {file = "greenlet-3.2.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:299fd615cd8fc86267b47597123e3f43ad79c9d8a22bebdce535e53550763e2f"}, - {file = "greenlet-3.2.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c17b6b34111ea72fc5a4e4beec9711d2226285f0386ea83477cbb97c30a3f3a5"}, - {file = "greenlet-3.2.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b4a1870c51720687af7fa3e7cda6d08d801dae660f75a76f3845b642b4da6ee1"}, - {file = "greenlet-3.2.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:061dc4cf2c34852b052a8620d40f36324554bc192be474b9e9770e8c042fd735"}, - {file = "greenlet-3.2.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44358b9bf66c8576a9f57a590d5f5d6e72fa4228b763d0e43fee6d3b06d3a337"}, - {file = "greenlet-3.2.4-cp314-cp314-win_amd64.whl", hash = "sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01"}, - {file = "greenlet-3.2.4-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:b6a7c19cf0d2742d0809a4c05975db036fdff50cd294a93632d6a310bf9ac02c"}, - {file = "greenlet-3.2.4-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:27890167f55d2387576d1f41d9487ef171849ea0359ce1510ca6e06c8bece11d"}, - {file = "greenlet-3.2.4-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:18d9260df2b5fbf41ae5139e1be4e796d99655f023a636cd0e11e6406cca7d58"}, - {file = "greenlet-3.2.4-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:671df96c1f23c4a0d4077a325483c1503c96a1b7d9db26592ae770daa41233d4"}, - {file = "greenlet-3.2.4-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:16458c245a38991aa19676900d48bd1a6f2ce3e16595051a4db9d012154e8433"}, - {file = "greenlet-3.2.4-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9913f1a30e4526f432991f89ae263459b1c64d1608c0d22a5c79c287b3c70df"}, - {file = "greenlet-3.2.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b90654e092f928f110e0007f572007c9727b5265f7632c2fa7415b4689351594"}, - {file = "greenlet-3.2.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:81701fd84f26330f0d5f4944d4e92e61afe6319dcd9775e39396e39d7c3e5f98"}, - {file = "greenlet-3.2.4-cp39-cp39-win32.whl", hash = "sha256:65458b409c1ed459ea899e939f0e1cdb14f58dbc803f2f93c5eab5694d32671b"}, - {file = "greenlet-3.2.4-cp39-cp39-win_amd64.whl", hash = "sha256:d2e685ade4dafd447ede19c31277a224a239a0a1a4eca4e6390efedf20260cfb"}, - {file = "greenlet-3.2.4.tar.gz", hash = "sha256:0dca0d95ff849f9a364385f36ab49f50065d76964944638be9691e1832e9f86d"}, + {file = "greenlet-3.3.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:6f8496d434d5cb2dce025773ba5597f71f5410ae499d5dd9533e0653258cdb3d"}, + {file = "greenlet-3.3.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b96dc7eef78fd404e022e165ec55327f935b9b52ff355b067eb4a0267fc1cffb"}, + {file = "greenlet-3.3.0-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:73631cd5cccbcfe63e3f9492aaa664d278fda0ce5c3d43aeda8e77317e38efbd"}, + {file = "greenlet-3.3.0-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b299a0cb979f5d7197442dccc3aee67fce53500cd88951b7e6c35575701c980b"}, + {file = "greenlet-3.3.0-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7dee147740789a4632cace364816046e43310b59ff8fb79833ab043aefa72fd5"}, + {file = "greenlet-3.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:39b28e339fc3c348427560494e28d8a6f3561c8d2bcf7d706e1c624ed8d822b9"}, + {file = "greenlet-3.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b3c374782c2935cc63b2a27ba8708471de4ad1abaa862ffdb1ef45a643ddbb7d"}, + {file = "greenlet-3.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:b49e7ed51876b459bd645d83db257f0180e345d3f768a35a85437a24d5a49082"}, + {file = "greenlet-3.3.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e29f3018580e8412d6aaf5641bb7745d38c85228dacf51a73bd4e26ddf2a6a8e"}, + {file = "greenlet-3.3.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a687205fb22794e838f947e2194c0566d3812966b41c78709554aa883183fb62"}, + {file = "greenlet-3.3.0-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4243050a88ba61842186cb9e63c7dfa677ec146160b0efd73b855a3d9c7fcf32"}, + {file = "greenlet-3.3.0-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:670d0f94cd302d81796e37299bcd04b95d62403883b24225c6b5271466612f45"}, + {file = "greenlet-3.3.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cb3a8ec3db4a3b0eb8a3c25436c2d49e3505821802074969db017b87bc6a948"}, + {file = "greenlet-3.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2de5a0b09eab81fc6a382791b995b1ccf2b172a9fec934747a7a23d2ff291794"}, + {file = "greenlet-3.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4449a736606bd30f27f8e1ff4678ee193bc47f6ca810d705981cfffd6ce0d8c5"}, + {file = "greenlet-3.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:7652ee180d16d447a683c04e4c5f6441bae7ba7b17ffd9f6b3aff4605e9e6f71"}, + {file = "greenlet-3.3.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:b01548f6e0b9e9784a2c99c5651e5dc89ffcbe870bc5fb2e5ef864e9cc6b5dcb"}, + {file = "greenlet-3.3.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:349345b770dc88f81506c6861d22a6ccd422207829d2c854ae2af8025af303e3"}, + {file = "greenlet-3.3.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e8e18ed6995e9e2c0b4ed264d2cf89260ab3ac7e13555b8032b25a74c6d18655"}, + {file = "greenlet-3.3.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c024b1e5696626890038e34f76140ed1daf858e37496d33f2af57f06189e70d7"}, + {file = "greenlet-3.3.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:047ab3df20ede6a57c35c14bf5200fcf04039d50f908270d3f9a7a82064f543b"}, + {file = "greenlet-3.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2d9ad37fc657b1102ec880e637cccf20191581f75c64087a549e66c57e1ceb53"}, + {file = "greenlet-3.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:83cd0e36932e0e7f36a64b732a6f60c2fc2df28c351bae79fbaf4f8092fe7614"}, + {file = "greenlet-3.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a7a34b13d43a6b78abf828a6d0e87d3385680eaf830cd60d20d52f249faabf39"}, + {file = "greenlet-3.3.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:a1e41a81c7e2825822f4e068c48cb2196002362619e2d70b148f20a831c00739"}, + {file = "greenlet-3.3.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9f515a47d02da4d30caaa85b69474cec77b7929b2e936ff7fb853d42f4bf8808"}, + {file = "greenlet-3.3.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7d2d9fd66bfadf230b385fdc90426fcd6eb64db54b40c495b72ac0feb5766c54"}, + {file = "greenlet-3.3.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30a6e28487a790417d036088b3bcb3f3ac7d8babaa7d0139edbaddebf3af9492"}, + {file = "greenlet-3.3.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:087ea5e004437321508a8d6f20efc4cfec5e3c30118e1417ea96ed1d93950527"}, + {file = "greenlet-3.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ab97cf74045343f6c60a39913fa59710e4bd26a536ce7ab2397adf8b27e67c39"}, + {file = "greenlet-3.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5375d2e23184629112ca1ea89a53389dddbffcf417dad40125713d88eb5f96e8"}, + {file = "greenlet-3.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:9ee1942ea19550094033c35d25d20726e4f1c40d59545815e1128ac58d416d38"}, + {file = "greenlet-3.3.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:60c2ef0f578afb3c8d92ea07ad327f9a062547137afe91f38408f08aacab667f"}, + {file = "greenlet-3.3.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a5d554d0712ba1de0a6c94c640f7aeba3f85b3a6e1f2899c11c2c0428da9365"}, + {file = "greenlet-3.3.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3a898b1e9c5f7307ebbde4102908e6cbfcb9ea16284a3abe15cab996bee8b9b3"}, + {file = "greenlet-3.3.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:dcd2bdbd444ff340e8d6bdf54d2f206ccddbb3ccfdcd3c25bf4afaa7b8f0cf45"}, + {file = "greenlet-3.3.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5773edda4dc00e173820722711d043799d3adb4f01731f40619e07ea2750b955"}, + {file = "greenlet-3.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ac0549373982b36d5fd5d30beb8a7a33ee541ff98d2b502714a09f1169f31b55"}, + {file = "greenlet-3.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d198d2d977460358c3b3a4dc844f875d1adb33817f0613f663a656f463764ccc"}, + {file = "greenlet-3.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:73f51dd0e0bdb596fb0417e475fa3c5e32d4c83638296e560086b8d7da7c4170"}, + {file = "greenlet-3.3.0-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:d6ed6f85fae6cdfdb9ce04c9bf7a08d666cfcfb914e7d006f44f840b46741931"}, + {file = "greenlet-3.3.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9125050fcf24554e69c4cacb086b87b3b55dc395a8b3ebe6487b045b2614388"}, + {file = "greenlet-3.3.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:87e63ccfa13c0a0f6234ed0add552af24cc67dd886731f2261e46e241608bee3"}, + {file = "greenlet-3.3.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2662433acbca297c9153a4023fe2161c8dcfdcc91f10433171cf7e7d94ba2221"}, + {file = "greenlet-3.3.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3c6e9b9c1527a78520357de498b0e709fb9e2f49c3a513afd5a249007261911b"}, + {file = "greenlet-3.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:286d093f95ec98fdd92fcb955003b8a3d054b4e2cab3e2707a5039e7b50520fd"}, + {file = "greenlet-3.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c10513330af5b8ae16f023e8ddbfb486ab355d04467c4679c5cfe4659975dd9"}, + {file = "greenlet-3.3.0.tar.gz", hash = "sha256:a82bb225a4e9e4d653dd2fb7b8b2d36e4fb25bc0165422a11e48b88e9e6f78fb"}, ] [package.extras] @@ -2547,14 +2591,14 @@ pypi = ["pip (>=24.0)", "platformdirs (>=4.2)", "wheel (>=0.42)"] [[package]] name = "groq" -version = "0.36.0" +version = "1.0.0" description = "The official Python library for the groq API" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "groq-0.36.0-py3-none-any.whl", hash = "sha256:ac7eeae31a5c2e76d30ea678f0b1a9168ff906c4440f5ec3a42ac74d5b4fdb3c"}, - {file = "groq-0.36.0.tar.gz", hash = "sha256:766fa1ae34918552c6488767b16d4bd0ee3f0fb7809cd9f7760c90d13f32c63a"}, + {file = "groq-1.0.0-py3-none-any.whl", hash = "sha256:6e22bf92ffad988f01d2d4df7729add66b8fd5dbfb2154b5bbf3af245b72c731"}, + {file = "groq-1.0.0.tar.gz", hash = "sha256:66cb7bb729e6eb644daac7ce8efe945e99e4eb33657f733ee6f13059ef0c25a9"}, ] [package.dependencies] @@ -2575,6 +2619,7 @@ description = "HTTP/2-based RPC framework" optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.13\"" files = [ {file = "grpcio-1.67.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:8b0341d66a57f8a3119b77ab32207072be60c9bf79760fa609c5609f2deb1f3f"}, {file = "grpcio-1.67.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:f5a27dddefe0e2357d3e617b9079b4bfdc91341a91565111a21ed6ebbc51b22d"}, @@ -2636,6 +2681,84 @@ files = [ [package.extras] protobuf = ["grpcio-tools (>=1.67.1)"] +[[package]] +name = "grpcio" +version = "1.76.0" +description = "HTTP/2-based RPC framework" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version >= \"3.14\"" +files = [ + {file = "grpcio-1.76.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:65a20de41e85648e00305c1bb09a3598f840422e522277641145a32d42dcefcc"}, + {file = "grpcio-1.76.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:40ad3afe81676fd9ec6d9d406eda00933f218038433980aa19d401490e46ecde"}, + {file = "grpcio-1.76.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:035d90bc79eaa4bed83f524331d55e35820725c9fbb00ffa1904d5550ed7ede3"}, + {file = "grpcio-1.76.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:4215d3a102bd95e2e11b5395c78562967959824156af11fa93d18fdd18050990"}, + {file = "grpcio-1.76.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:49ce47231818806067aea3324d4bf13825b658ad662d3b25fada0bdad9b8a6af"}, + {file = "grpcio-1.76.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8cc3309d8e08fd79089e13ed4819d0af72aa935dd8f435a195fd152796752ff2"}, + {file = "grpcio-1.76.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:971fd5a1d6e62e00d945423a567e42eb1fa678ba89072832185ca836a94daaa6"}, + {file = "grpcio-1.76.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9d9adda641db7207e800a7f089068f6f645959f2df27e870ee81d44701dd9db3"}, + {file = "grpcio-1.76.0-cp310-cp310-win32.whl", hash = "sha256:063065249d9e7e0782d03d2bca50787f53bd0fb89a67de9a7b521c4a01f1989b"}, + {file = "grpcio-1.76.0-cp310-cp310-win_amd64.whl", hash = "sha256:a6ae758eb08088d36812dd5d9af7a9859c05b1e0f714470ea243694b49278e7b"}, + {file = "grpcio-1.76.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:2e1743fbd7f5fa713a1b0a8ac8ebabf0ec980b5d8809ec358d488e273b9cf02a"}, + {file = "grpcio-1.76.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:a8c2cf1209497cf659a667d7dea88985e834c24b7c3b605e6254cbb5076d985c"}, + {file = "grpcio-1.76.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:08caea849a9d3c71a542827d6df9d5a69067b0a1efbea8a855633ff5d9571465"}, + {file = "grpcio-1.76.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f0e34c2079d47ae9f6188211db9e777c619a21d4faba6977774e8fa43b085e48"}, + {file = "grpcio-1.76.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8843114c0cfce61b40ad48df65abcfc00d4dba82eae8718fab5352390848c5da"}, + {file = "grpcio-1.76.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8eddfb4d203a237da6f3cc8a540dad0517d274b5a1e9e636fd8d2c79b5c1d397"}, + {file = "grpcio-1.76.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:32483fe2aab2c3794101c2a159070584e5db11d0aa091b2c0ea9c4fc43d0d749"}, + {file = "grpcio-1.76.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dcfe41187da8992c5f40aa8c5ec086fa3672834d2be57a32384c08d5a05b4c00"}, + {file = "grpcio-1.76.0-cp311-cp311-win32.whl", hash = "sha256:2107b0c024d1b35f4083f11245c0e23846ae64d02f40b2b226684840260ed054"}, + {file = "grpcio-1.76.0-cp311-cp311-win_amd64.whl", hash = "sha256:522175aba7af9113c48ec10cc471b9b9bd4f6ceb36aeb4544a8e2c80ed9d252d"}, + {file = "grpcio-1.76.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:81fd9652b37b36f16138611c7e884eb82e0cec137c40d3ef7c3f9b3ed00f6ed8"}, + {file = "grpcio-1.76.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:04bbe1bfe3a68bbfd4e52402ab7d4eb59d72d02647ae2042204326cf4bbad280"}, + {file = "grpcio-1.76.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d388087771c837cdb6515539f43b9d4bf0b0f23593a24054ac16f7a960be16f4"}, + {file = "grpcio-1.76.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:9f8f757bebaaea112c00dba718fc0d3260052ce714e25804a03f93f5d1c6cc11"}, + {file = "grpcio-1.76.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:980a846182ce88c4f2f7e2c22c56aefd515daeb36149d1c897f83cf57999e0b6"}, + {file = "grpcio-1.76.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f92f88e6c033db65a5ae3d97905c8fea9c725b63e28d5a75cb73b49bda5024d8"}, + {file = "grpcio-1.76.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4baf3cbe2f0be3289eb68ac8ae771156971848bb8aaff60bad42005539431980"}, + {file = "grpcio-1.76.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:615ba64c208aaceb5ec83bfdce7728b80bfeb8be97562944836a7a0a9647d882"}, + {file = "grpcio-1.76.0-cp312-cp312-win32.whl", hash = "sha256:45d59a649a82df5718fd9527ce775fd66d1af35e6d31abdcdc906a49c6822958"}, + {file = "grpcio-1.76.0-cp312-cp312-win_amd64.whl", hash = "sha256:c088e7a90b6017307f423efbb9d1ba97a22aa2170876223f9709e9d1de0b5347"}, + {file = "grpcio-1.76.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:26ef06c73eb53267c2b319f43e6634c7556ea37672029241a056629af27c10e2"}, + {file = "grpcio-1.76.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:45e0111e73f43f735d70786557dc38141185072d7ff8dc1829d6a77ac1471468"}, + {file = "grpcio-1.76.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:83d57312a58dcfe2a3a0f9d1389b299438909a02db60e2f2ea2ae2d8034909d3"}, + {file = "grpcio-1.76.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:3e2a27c89eb9ac3d81ec8835e12414d73536c6e620355d65102503064a4ed6eb"}, + {file = "grpcio-1.76.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61f69297cba3950a524f61c7c8ee12e55c486cb5f7db47ff9dcee33da6f0d3ae"}, + {file = "grpcio-1.76.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6a15c17af8839b6801d554263c546c69c4d7718ad4321e3166175b37eaacca77"}, + {file = "grpcio-1.76.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:25a18e9810fbc7e7f03ec2516addc116a957f8cbb8cbc95ccc80faa072743d03"}, + {file = "grpcio-1.76.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:931091142fd8cc14edccc0845a79248bc155425eee9a98b2db2ea4f00a235a42"}, + {file = "grpcio-1.76.0-cp313-cp313-win32.whl", hash = "sha256:5e8571632780e08526f118f74170ad8d50fb0a48c23a746bef2a6ebade3abd6f"}, + {file = "grpcio-1.76.0-cp313-cp313-win_amd64.whl", hash = "sha256:f9f7bd5faab55f47231ad8dba7787866b69f5e93bc306e3915606779bbfb4ba8"}, + {file = "grpcio-1.76.0-cp314-cp314-linux_armv7l.whl", hash = "sha256:ff8a59ea85a1f2191a0ffcc61298c571bc566332f82e5f5be1b83c9d8e668a62"}, + {file = "grpcio-1.76.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:06c3d6b076e7b593905d04fdba6a0525711b3466f43b3400266f04ff735de0cd"}, + {file = "grpcio-1.76.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fd5ef5932f6475c436c4a55e4336ebbe47bd3272be04964a03d316bbf4afbcbc"}, + {file = "grpcio-1.76.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:b331680e46239e090f5b3cead313cc772f6caa7d0fc8de349337563125361a4a"}, + {file = "grpcio-1.76.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2229ae655ec4e8999599469559e97630185fdd53ae1e8997d147b7c9b2b72cba"}, + {file = "grpcio-1.76.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:490fa6d203992c47c7b9e4a9d39003a0c2bcc1c9aa3c058730884bbbb0ee9f09"}, + {file = "grpcio-1.76.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:479496325ce554792dba6548fae3df31a72cef7bad71ca2e12b0e58f9b336bfc"}, + {file = "grpcio-1.76.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1c9b93f79f48b03ada57ea24725d83a30284a012ec27eab2cf7e50a550cbbbcc"}, + {file = "grpcio-1.76.0-cp314-cp314-win32.whl", hash = "sha256:747fa73efa9b8b1488a95d0ba1039c8e2dca0f741612d80415b1e1c560febf4e"}, + {file = "grpcio-1.76.0-cp314-cp314-win_amd64.whl", hash = "sha256:922fa70ba549fce362d2e2871ab542082d66e2aaf0c19480ea453905b01f384e"}, + {file = "grpcio-1.76.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:8ebe63ee5f8fa4296b1b8cfc743f870d10e902ca18afc65c68cf46fd39bb0783"}, + {file = "grpcio-1.76.0-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:3bf0f392c0b806905ed174dcd8bdd5e418a40d5567a05615a030a5aeddea692d"}, + {file = "grpcio-1.76.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0b7604868b38c1bfd5cf72d768aedd7db41d78cb6a4a18585e33fb0f9f2363fd"}, + {file = "grpcio-1.76.0-cp39-cp39-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:e6d1db20594d9daba22f90da738b1a0441a7427552cc6e2e3d1297aeddc00378"}, + {file = "grpcio-1.76.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d099566accf23d21037f18a2a63d323075bebace807742e4b0ac210971d4dd70"}, + {file = "grpcio-1.76.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ebea5cc3aa8ea72e04df9913492f9a96d9348db876f9dda3ad729cfedf7ac416"}, + {file = "grpcio-1.76.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0c37db8606c258e2ee0c56b78c62fc9dee0e901b5dbdcf816c2dd4ad652b8b0c"}, + {file = "grpcio-1.76.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ebebf83299b0cb1721a8859ea98f3a77811e35dce7609c5c963b9ad90728f886"}, + {file = "grpcio-1.76.0-cp39-cp39-win32.whl", hash = "sha256:0aaa82d0813fd4c8e589fac9b65d7dd88702555f702fb10417f96e2a2a6d4c0f"}, + {file = "grpcio-1.76.0-cp39-cp39-win_amd64.whl", hash = "sha256:acab0277c40eff7143c2323190ea57b9ee5fd353d8190ee9652369fae735668a"}, + {file = "grpcio-1.76.0.tar.gz", hash = "sha256:7be78388d6da1a25c0d5ec506523db58b18be22d9c37d8d3a32c08be4987bd73"}, +] + +[package.dependencies] +typing-extensions = ">=4.12,<5.0" + +[package.extras] +protobuf = ["grpcio-tools (>=1.76.0)"] + [[package]] name = "gunicorn" version = "23.0.0" @@ -2793,14 +2916,14 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "httpx-aiohttp" -version = "0.1.9" +version = "0.1.12" description = "Aiohttp transport for HTTPX" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "httpx_aiohttp-0.1.9-py3-none-any.whl", hash = "sha256:3dc2845568b07742588710fcf3d72db2cbcdf2acc93376edf85f789c4d8e5fda"}, - {file = "httpx_aiohttp-0.1.9.tar.gz", hash = "sha256:4ee8b22e6f2e7c80cd03be29eff98bfe7d89bd77f021ce0b578ee76b73b4bfe6"}, + {file = "httpx_aiohttp-0.1.12-py3-none-any.whl", hash = "sha256:5b0eac39a7f360fa7867a60bcb46bb1024eada9c01cbfecdb54dc1edb3fb7141"}, + {file = "httpx_aiohttp-0.1.12.tar.gz", hash = "sha256:81feec51fd82c0ecfa0e9aaf1b1a6c2591260d5e2bcbeb7eb0277a78e610df2c"}, ] [package.dependencies] @@ -2809,26 +2932,26 @@ httpx = ">=0.27.0" [[package]] name = "httpx-sse" -version = "0.4.0" +version = "0.4.3" description = "Consume Server-Sent Event (SSE) messages with HTTPX." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" 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"}, + {file = "httpx_sse-0.4.3-py3-none-any.whl", hash = "sha256:0ac1c9fe3c0afad2e0ebb25a934a59f4c7823b60792691f779fad2c5568830fc"}, + {file = "httpx_sse-0.4.3.tar.gz", hash = "sha256:9b1ed0127459a66014aec3c56bebd93da3c1bc8bb6618c8082039a44889a755d"}, ] [[package]] name = "huggingface-hub" -version = "1.1.5" +version = "1.2.3" description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub" optional = false python-versions = ">=3.9.0" groups = ["main"] files = [ - {file = "huggingface_hub-1.1.5-py3-none-any.whl", hash = "sha256:e88ecc129011f37b868586bbcfae6c56868cae80cd56a79d61575426a3aa0d7d"}, - {file = "huggingface_hub-1.1.5.tar.gz", hash = "sha256:40ba5c9a08792d888fde6088920a0a71ab3cd9d5e6617c81a797c657f1fd9968"}, + {file = "huggingface_hub-1.2.3-py3-none-any.whl", hash = "sha256:c9b7a91a9eedaa2149cdc12bdd8f5a11780e10de1f1024718becf9e41e5a4642"}, + {file = "huggingface_hub-1.2.3.tar.gz", hash = "sha256:4ba57f17004fd27bb176a6b7107df579865d4cde015112db59184c51f5602ba7"}, ] [package.dependencies] @@ -2887,14 +3010,14 @@ all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2 [[package]] name = "importlib-metadata" -version = "8.7.0" +version = "8.7.1" description = "Read metadata from Python packages" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd"}, - {file = "importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000"}, + {file = "importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151"}, + {file = "importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb"}, ] [package.dependencies] @@ -2904,10 +3027,10 @@ zipp = ">=3.20" check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -enabler = ["pytest-enabler (>=2.2)"] +enabler = ["pytest-enabler (>=3.4)"] perf = ["ipython"] -test = ["flufl.flake8", "importlib_resources (>=1.3) ; python_version < \"3.9\"", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] -type = ["pytest-mypy"] +test = ["flufl.flake8", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +type = ["mypy (<1.19) ; platform_python_implementation == \"PyPy\"", "pytest-mypy (>=1.0.1)"] [[package]] name = "iniconfig" @@ -2992,33 +3115,37 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-ena [[package]] name = "jaraco-context" -version = "6.0.1" +version = "6.0.2" description = "Useful decorators and context managers" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "jaraco.context-6.0.1-py3-none-any.whl", hash = "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4"}, - {file = "jaraco_context-6.0.1.tar.gz", hash = "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3"}, + {file = "jaraco_context-6.0.2-py3-none-any.whl", hash = "sha256:55fc21af4b4f9ca94aa643b6ee7fe13b1e4c01abf3aeb98ca4ad9c80b741c786"}, + {file = "jaraco_context-6.0.2.tar.gz", hash = "sha256:953ae8dddb57b1d791bf72ea1009b32088840a7dd19b9ba16443f62be919ee57"}, ] [package.dependencies] "backports.tarfile" = {version = "*", markers = "python_version < \"3.12\""} [package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -test = ["portend", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +enabler = ["pytest-enabler (>=3.4)"] +test = ["jaraco.test (>=5.6.0)", "portend", "pytest (>=6,!=8.1.*)"] +type = ["mypy (<1.19) ; platform_python_implementation == \"PyPy\"", "pytest-mypy (>=1.0.1)"] [[package]] name = "jaraco-functools" -version = "4.3.0" +version = "4.4.0" description = "Functools like those found in stdlib" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "jaraco_functools-4.3.0-py3-none-any.whl", hash = "sha256:227ff8ed6f7b8f62c56deff101545fa7543cf2c8e7b82a7c2116e672f29c26e8"}, - {file = "jaraco_functools-4.3.0.tar.gz", hash = "sha256:cfd13ad0dd2c47a3600b439ef72d8615d482cedcff1632930d6f28924d92f294"}, + {file = "jaraco_functools-4.4.0-py3-none-any.whl", hash = "sha256:9eec1e36f45c818d9bf307c8948eb03b2b56cd44087b3cdc989abca1f20b9176"}, + {file = "jaraco_functools-4.4.0.tar.gz", hash = "sha256:da21933b0417b89515562656547a77b4931f98176eb173644c0d35032a33d6bb"}, ] [package.dependencies] @@ -3028,9 +3155,9 @@ more_itertools = "*" check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -enabler = ["pytest-enabler (>=2.2)"] +enabler = ["pytest-enabler (>=3.4)"] test = ["jaraco.classes", "pytest (>=6,!=8.1.*)"] -type = ["pytest-mypy"] +type = ["mypy (<1.19) ; platform_python_implementation == \"PyPy\"", "pytest-mypy (>=1.0.1)"] [[package]] name = "jedi" @@ -3213,14 +3340,14 @@ files = [ [[package]] name = "joblib" -version = "1.5.2" +version = "1.5.3" description = "Lightweight pipelining with Python functions" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "joblib-1.5.2-py3-none-any.whl", hash = "sha256:4e1f0bdbb987e6d843c70cf43714cb276623def372df3c22fe5266b2670bc241"}, - {file = "joblib-1.5.2.tar.gz", hash = "sha256:3faa5c39054b2f03ca547da9b2f52fde67c06240c31853f306aea97f13647b55"}, + {file = "joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713"}, + {file = "joblib-1.5.3.tar.gz", hash = "sha256:8561a3269e6801106863fd0d6d84bb737be9e7631e33aaed3fb9ce5953688da3"}, ] [[package]] @@ -3241,14 +3368,14 @@ six = ">=1.13.0" [[package]] name = "json-repair" -version = "0.54.2" +version = "0.54.3" description = "A package to repair broken json strings" optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "json_repair-0.54.2-py3-none-any.whl", hash = "sha256:be51cce5dca97e0c24ebdf61a1ede2449a8a7666012de99467bb7b0afb35179b"}, - {file = "json_repair-0.54.2.tar.gz", hash = "sha256:4b6b62ce17f1a505b220fa4aadba1fc37dc9c221544f158471efe3775620bad6"}, + {file = "json_repair-0.54.3-py3-none-any.whl", hash = "sha256:4cdc132ee27d4780576f71bf27a113877046224a808bfc17392e079cb344fb81"}, + {file = "json_repair-0.54.3.tar.gz", hash = "sha256:e50feec9725e52ac91f12184609754684ac1656119dfbd31de09bdaf9a1d8bf6"}, ] [[package]] @@ -3491,18 +3618,18 @@ files = [ [[package]] name = "langchain" -version = "1.1.0" +version = "1.2.0" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0.0,>=3.10.0" groups = ["main"] files = [ - {file = "langchain-1.1.0-py3-none-any.whl", hash = "sha256:af080f3a4a779bfa5925de7aacb6dfab83249d4aab9a08f7aa7b9bec3766d8ea"}, - {file = "langchain-1.1.0.tar.gz", hash = "sha256:583c892f59873c0329dbe04169fb3234ac794c50780e7c6fb62a61c7b86a981b"}, + {file = "langchain-1.2.0-py3-none-any.whl", hash = "sha256:82f0d17aa4fbb11560b30e1e7d4aeb75e3ad71ce09b85c90ab208b181a24ffac"}, + {file = "langchain-1.2.0.tar.gz", hash = "sha256:a087d1e2b2969819e29a91a6d5f98302aafe31bd49ba377ecee3bf5a5dcfe14a"}, ] [package.dependencies] -langchain-core = ">=1.1.0,<2.0.0" +langchain-core = ">=1.2.1,<2.0.0" langgraph = ">=1.0.2,<1.1.0" pydantic = ">=2.7.4,<3.0.0" @@ -3526,19 +3653,19 @@ xai = ["langchain-xai"] [[package]] name = "langchain-classic" -version = "1.0.0" +version = "1.0.1" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0.0,>=3.10.0" groups = ["main"] files = [ - {file = "langchain_classic-1.0.0-py3-none-any.whl", hash = "sha256:97f71f150c10123f5511c08873f030e35ede52311d729a7688c721b4e1e01f33"}, - {file = "langchain_classic-1.0.0.tar.gz", hash = "sha256:a63655609254ebc36d660eb5ad7c06c778b2e6733c615ffdac3eac4fbe2b12c5"}, + {file = "langchain_classic-1.0.1-py3-none-any.whl", hash = "sha256:131d83a02bb80044c68fedc1ab4ae885d5b8f8c2c742d8ab9e7534ad9cda8e80"}, + {file = "langchain_classic-1.0.1.tar.gz", hash = "sha256:40a499684df36b005a1213735dc7f8dca8f5eb67978d6ec763e7a49780864fdc"}, ] [package.dependencies] -langchain-core = ">=1.0.0,<2.0.0" -langchain-text-splitters = ">=1.0.0,<2.0.0" +langchain-core = ">=1.2.5,<2.0.0" +langchain-text-splitters = ">=1.1.0,<2.0.0" langsmith = ">=0.1.17,<1.0.0" pydantic = ">=2.7.4,<3.0.0" pyyaml = ">=5.3.0,<7.0.0" @@ -3553,6 +3680,7 @@ 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"] @@ -3591,14 +3719,14 @@ tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<10.0.0" [[package]] name = "langchain-core" -version = "1.1.0" +version = "1.2.5" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0.0,>=3.10.0" groups = ["main"] files = [ - {file = "langchain_core-1.1.0-py3-none-any.whl", hash = "sha256:2c9f27dadc6d21ed4aa46506a37a56e6a7e2d2f9141922dc5c251ba921822ee6"}, - {file = "langchain_core-1.1.0.tar.gz", hash = "sha256:2b76a82d427922c8bc51c08404af4fc2a29e9f161dfe2297cb05091e810201e7"}, + {file = "langchain_core-1.2.5-py3-none-any.whl", hash = "sha256:3255944ef4e21b2551facb319bfc426057a40247c0a05de5bd6f2fc021fbfa34"}, + {file = "langchain_core-1.2.5.tar.gz", hash = "sha256:d674f6df42f07e846859b9d3afe547cad333d6bf9763e92c88eb4f8aaedcd3cc"}, ] [package.dependencies] @@ -3609,17 +3737,18 @@ pydantic = ">=2.7.4,<3.0.0" pyyaml = ">=5.3.0,<7.0.0" tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<10.0.0" typing-extensions = ">=4.7.0,<5.0.0" +uuid-utils = ">=0.12.0,<1.0" [[package]] name = "langchain-ollama" -version = "1.0.0" +version = "1.0.1" description = "An integration package connecting Ollama and LangChain" optional = false python-versions = "<4.0.0,>=3.10.0" groups = ["main"] files = [ - {file = "langchain_ollama-1.0.0-py3-none-any.whl", hash = "sha256:5828523fcbd137847490841110a6aedf96b68534e7fe2735715ecf3e835b2391"}, - {file = "langchain_ollama-1.0.0.tar.gz", hash = "sha256:2ea9ad1b0f0ab319d600b9193d1124a8925523a3b943d75a967718e24ec09a8a"}, + {file = "langchain_ollama-1.0.1-py3-none-any.whl", hash = "sha256:37eb939a4718a0255fe31e19fbb0def044746c717b01b97d397606ebc3e9b440"}, + {file = "langchain_ollama-1.0.1.tar.gz", hash = "sha256:e37880c2f41cdb0895e863b1cfd0c2c840a117868b3f32e44fef42569e367443"}, ] [package.dependencies] @@ -3628,35 +3757,35 @@ ollama = ">=0.6.0,<1.0.0" [[package]] name = "langchain-openai" -version = "1.1.0" +version = "1.1.6" description = "An integration package connecting OpenAI and LangChain" optional = false python-versions = "<4.0.0,>=3.10.0" groups = ["main"] files = [ - {file = "langchain_openai-1.1.0-py3-none-any.whl", hash = "sha256:243bb345d0260ea1326c2b6ac2237ec29f082ab457c59e9306bac349df4577e8"}, - {file = "langchain_openai-1.1.0.tar.gz", hash = "sha256:9a33280c2e8315d013d64e6b15e583be347beb0d0f281755c335ae504ad0c184"}, + {file = "langchain_openai-1.1.6-py3-none-any.whl", hash = "sha256:c42d04a67a85cee1d994afe400800d2b09ebf714721345f0b651eb06a02c3948"}, + {file = "langchain_openai-1.1.6.tar.gz", hash = "sha256:e306612654330ae36fb6bbe36db91c98534312afade19e140c3061fe4208dac8"}, ] [package.dependencies] -langchain-core = ">=1.1.0,<2.0.0" +langchain-core = ">=1.2.2,<2.0.0" openai = ">=1.109.1,<3.0.0" tiktoken = ">=0.7.0,<1.0.0" [[package]] name = "langchain-text-splitters" -version = "1.0.0" +version = "1.1.0" description = "LangChain text splitting utilities" optional = false python-versions = "<4.0.0,>=3.10.0" groups = ["main"] files = [ - {file = "langchain_text_splitters-1.0.0-py3-none-any.whl", hash = "sha256:f00c8219d3468f2c5bd951b708b6a7dd9bc3c62d0cfb83124c377f7170f33b2e"}, - {file = "langchain_text_splitters-1.0.0.tar.gz", hash = "sha256:d8580a20ad7ed10b432feb273e5758b2cc0902d094919629cec0e1ad691a6744"}, + {file = "langchain_text_splitters-1.1.0-py3-none-any.whl", hash = "sha256:f00341fe883358786104a5f881375ac830a4dd40253ecd42b4c10536c6e4693f"}, + {file = "langchain_text_splitters-1.1.0.tar.gz", hash = "sha256:75e58acb7585dc9508f3cd9d9809cb14751283226c2d6e21fb3a9ae57582ca22"}, ] [package.dependencies] -langchain-core = ">=1.0.0,<2.0.0" +langchain-core = ">=1.2.0,<2.0.0" [[package]] name = "langdetect" @@ -3675,21 +3804,21 @@ six = "*" [[package]] name = "langgraph" -version = "1.0.4" +version = "1.0.5" description = "Building stateful, multi-actor applications with LLMs" optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "langgraph-1.0.4-py3-none-any.whl", hash = "sha256:b1a835ceb0a8d69b9db48075e1939e28b1ad70ee23fa3fa8f90149904778bacf"}, - {file = "langgraph-1.0.4.tar.gz", hash = "sha256:86d08e25d7244340f59c5200fa69fdd11066aa999b3164b531e2a20036fac156"}, + {file = "langgraph-1.0.5-py3-none-any.whl", hash = "sha256:b4cfd173dca3c389735b47228ad8b295e6f7b3df779aba3a1e0c23871f81281e"}, + {file = "langgraph-1.0.5.tar.gz", hash = "sha256:7f6ae59622386b60fe9fa0ad4c53f42016b668455ed604329e7dc7904adbf3f8"}, ] [package.dependencies] langchain-core = ">=0.1" langgraph-checkpoint = ">=2.1.0,<4.0.0" langgraph-prebuilt = ">=1.0.2,<1.1.0" -langgraph-sdk = ">=0.2.2,<0.3.0" +langgraph-sdk = ">=0.3.0,<0.4.0" pydantic = ">=2.7.4" xxhash = ">=3.5.0" @@ -3711,14 +3840,14 @@ ormsgpack = ">=1.12.0" [[package]] name = "langgraph-cli" -version = "0.4.7" +version = "0.4.11" description = "CLI for interacting with LangGraph API" optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "langgraph_cli-0.4.7-py3-none-any.whl", hash = "sha256:c24e1593c2cdffb658841999eccf71d8bd73025105c727ebcad7fafe35c983ab"}, - {file = "langgraph_cli-0.4.7.tar.gz", hash = "sha256:51dc5c7bfd0ce957162facea5ef93ffe9778e8d9ec993354f19aec9dd0161470"}, + {file = "langgraph_cli-0.4.11-py3-none-any.whl", hash = "sha256:807cd6e8c5d4fd7160bd44be67f3b5621cb34ec309658072f75852b639b41ca0"}, + {file = "langgraph_cli-0.4.11.tar.gz", hash = "sha256:c38c531510ace1c2d90f8a15f4bb5b874ca9d07c0564cbda7590730da2b0dff3"}, ] [package.dependencies] @@ -3726,7 +3855,7 @@ click = ">=8.1.7" langgraph-sdk = {version = ">=0.1.0", markers = "python_version >= \"3.11\""} [package.extras] -inmem = ["langgraph-api (>=0.4,<0.6.0) ; python_version >= \"3.11\"", "langgraph-runtime-inmem (>=0.7) ; python_version >= \"3.11\"", "python-dotenv (>=0.8.0)"] +inmem = ["langgraph-api (>=0.5.35,<0.7.0) ; python_version >= \"3.11\"", "langgraph-runtime-inmem (>=0.7) ; python_version >= \"3.11\"", "python-dotenv (>=0.8.0)"] [[package]] name = "langgraph-prebuilt" @@ -3746,14 +3875,14 @@ langgraph-checkpoint = ">=2.1.0,<4.0.0" [[package]] name = "langgraph-sdk" -version = "0.2.10" +version = "0.3.1" description = "SDK for interacting with LangGraph API" optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "langgraph_sdk-0.2.10-py3-none-any.whl", hash = "sha256:9aef403663726085de6851e4e50459df9562069bd316dd0261eb359f776fd0ef"}, - {file = "langgraph_sdk-0.2.10.tar.gz", hash = "sha256:ab58331504fbea28e6322037aa362929799b4e9106663ac1dbd7c5ac44558933"}, + {file = "langgraph_sdk-0.3.1-py3-none-any.whl", hash = "sha256:0b856923bfd20bf3441ce9d03bef488aa333fb610e972618799a9d584436acad"}, + {file = "langgraph_sdk-0.3.1.tar.gz", hash = "sha256:f6dadfd2444eeff3e01405a9005c95fb3a028d4bd954ebec80ea6150084f92bb"}, ] [package.dependencies] @@ -3762,14 +3891,14 @@ orjson = ">=3.10.1" [[package]] name = "langsmith" -version = "0.4.49" +version = "0.5.1" description = "Client library to connect to the LangSmith Observability and Evaluation Platform." optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "langsmith-0.4.49-py3-none-any.whl", hash = "sha256:95f84edcd8e74ed658e4a3eb7355b530f35cb08a9a8865dbfde6740e4b18323c"}, - {file = "langsmith-0.4.49.tar.gz", hash = "sha256:4a16ef6f3a9b20c5471884991a12ff37d81f2c13a50660cfe27fa79a7ca2c1b0"}, + {file = "langsmith-0.5.1-py3-none-any.whl", hash = "sha256:70aa2a4c75add3f723c3bbac80dbb8adc575077834d3a733ee1ec133206ff351"}, + {file = "langsmith-0.5.1.tar.gz", hash = "sha256:6a10b38cb4ce58941b7f1dbdf41a461868605dd0162bf05d17690f2e4b6e50e7"}, ] [package.dependencies] @@ -3779,6 +3908,7 @@ packaging = ">=23.2" pydantic = ">=1,<3" requests = ">=2.0.0" requests-toolbelt = ">=1.0.0" +uuid-utils = ">=0.12.0,<1.0" zstandard = ">=0.23.0" [package.extras] @@ -3791,25 +3921,28 @@ vcr = ["vcrpy (>=7.0.0)"] [[package]] name = "litellm" -version = "1.80.7" +version = "1.80.11" description = "Library to easily interface with LLM API providers" optional = false python-versions = "<4.0,>=3.9" groups = ["main"] files = [ - {file = "litellm-1.80.7-py3-none-any.whl", hash = "sha256:f7d993f78c1e0e4e1202b2a925cc6540b55b6e5fb055dd342d88b145ab3102ed"}, - {file = "litellm-1.80.7.tar.gz", hash = "sha256:3977a8d195aef842d01c18bf9e22984829363c6a4b54daf9a43c9dd9f190b42c"}, + {file = "litellm-1.80.11-py3-none-any.whl", hash = "sha256:406283d66ead77dc7ff0e0b2559c80e9e497d8e7c2257efb1cb9210a20d09d54"}, + {file = "litellm-1.80.11.tar.gz", hash = "sha256:c9fc63e7acb6360363238fe291bcff1488c59ff66020416d8376c0ee56414a19"}, ] [package.dependencies] aiohttp = ">=3.10" click = "*" fastuuid = ">=0.13.0" -grpcio = ">=1.62.3,<1.68.0" +grpcio = [ + {version = ">=1.62.3,<1.68.0", markers = "python_version < \"3.14\""}, + {version = ">=1.75.0", markers = "python_version >= \"3.14\""}, +] httpx = ">=0.23.0" importlib-metadata = ">=6.8.0" jinja2 = ">=3.1.2,<4.0.0" -jsonschema = ">=4.22.0,<5.0.0" +jsonschema = ">=4.23.0,<5.0.0" openai = ">=2.8.0" pydantic = ">=2.5.0,<3.0.0" python-dotenv = ">=0.2.0" @@ -3820,7 +3953,7 @@ tokenizers = "*" caching = ["diskcache (>=5.6.1,<6.0.0)"] extra-proxy = ["azure-identity (>=1.15.0,<2.0.0) ; python_version >= \"3.9\"", "azure-keyvault-secrets (>=4.8.0,<5.0.0)", "google-cloud-iam (>=2.19.1,<3.0.0)", "google-cloud-kms (>=2.21.3,<3.0.0)", "prisma (==0.11.0)", "redisvl (>=0.4.1,<0.5.0) ; python_version >= \"3.9\" and python_version < \"3.14\"", "resend (>=0.8.0)"] mlflow = ["mlflow (>3.1.4) ; python_version >= \"3.10\""] -proxy = ["PyJWT (>=2.10.1,<3.0.0) ; python_version >= \"3.9\"", "apscheduler (>=3.10.4,<4.0.0)", "azure-identity (>=1.15.0,<2.0.0) ; python_version >= \"3.9\"", "azure-storage-blob (>=12.25.1,<13.0.0)", "backoff", "boto3 (==1.36.0)", "cryptography", "fastapi (>=0.120.1)", "fastapi-sso (>=0.16.0,<0.17.0)", "gunicorn (>=23.0.0,<24.0.0)", "litellm-enterprise (==0.1.22)", "litellm-proxy-extras (==0.4.9)", "mcp (>=1.21.2,<2.0.0) ; python_version >= \"3.10\"", "orjson (>=3.9.7,<4.0.0)", "polars (>=1.31.0,<2.0.0) ; python_version >= \"3.10\"", "pynacl (>=1.5.0,<2.0.0)", "python-multipart (>=0.0.18,<0.0.19)", "pyyaml (>=6.0.1,<7.0.0)", "rich (==13.7.1)", "rq", "soundfile (>=0.12.1,<0.13.0)", "uvicorn (>=0.31.1,<0.32.0)", "uvloop (>=0.21.0,<0.22.0) ; sys_platform != \"win32\"", "websockets (>=15.0.1,<16.0.0)"] +proxy = ["PyJWT (>=2.10.1,<3.0.0) ; python_version >= \"3.9\"", "apscheduler (>=3.10.4,<4.0.0)", "azure-identity (>=1.15.0,<2.0.0) ; python_version >= \"3.9\"", "azure-storage-blob (>=12.25.1,<13.0.0)", "backoff", "boto3 (==1.36.0)", "cryptography", "fastapi (>=0.120.1)", "fastapi-sso (>=0.16.0,<0.17.0)", "gunicorn (>=23.0.0,<24.0.0)", "litellm-enterprise (==0.1.27)", "litellm-proxy-extras (==0.4.16)", "mcp (>=1.21.2,<2.0.0) ; python_version >= \"3.10\"", "orjson (>=3.9.7,<4.0.0)", "polars (>=1.31.0,<2.0.0) ; python_version >= \"3.10\"", "pynacl (>=1.5.0,<2.0.0)", "python-multipart (>=0.0.18,<0.0.19)", "pyyaml (>=6.0.1,<7.0.0)", "rich (==13.7.1)", "rq", "soundfile (>=0.12.1,<0.13.0)", "uvicorn (>=0.31.1,<0.32.0)", "uvloop (>=0.21.0,<0.22.0) ; sys_platform != \"win32\"", "websockets (>=15.0.1,<16.0.0)"] semantic-router = ["semantic-router (>=0.1.12) ; python_version >= \"3.9\" and python_version < \"3.14\""] utils = ["numpydoc"] @@ -3872,14 +4005,14 @@ wsgi = ["opentelemetry-instrumentation-wsgi (>=0.42b0)"] [[package]] name = "logfire-api" -version = "4.15.1" +version = "4.16.0" description = "Shim for the Logfire SDK which does nothing unless Logfire is installed" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "logfire_api-4.15.1-py3-none-any.whl", hash = "sha256:a88b5c4b6e4acbf6f35a3e992a63f271cf2797aefd21e1cfc93d52b21ade65f6"}, - {file = "logfire_api-4.15.1.tar.gz", hash = "sha256:3fbafc5593f4a16a038a3d23c67a7a7ee9da8be9e3b148fa73069d32e1ed4e8e"}, + {file = "logfire_api-4.16.0-py3-none-any.whl", hash = "sha256:7351153c35cb61f0f89d2d4123ebf99b5469d70ef34c613a5ce56f85bf1b14fb"}, + {file = "logfire_api-4.16.0.tar.gz", hash = "sha256:0efa62f5e73abdea670b5e9384c841b544474207110a089536a0fa8704f9e386"}, ] [[package]] @@ -3901,6 +4034,104 @@ win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} [package.extras] dev = ["Sphinx (==8.1.3) ; python_version >= \"3.11\"", "build (==1.2.2) ; python_version >= \"3.11\"", "colorama (==0.4.5) ; python_version < \"3.8\"", "colorama (==0.4.6) ; python_version >= \"3.8\"", "exceptiongroup (==1.1.3) ; python_version >= \"3.7\" and python_version < \"3.11\"", "freezegun (==1.1.0) ; python_version < \"3.8\"", "freezegun (==1.5.0) ; python_version >= \"3.8\"", "mypy (==v0.910) ; python_version < \"3.6\"", "mypy (==v0.971) ; python_version == \"3.6\"", "mypy (==v1.13.0) ; python_version >= \"3.8\"", "mypy (==v1.4.1) ; python_version == \"3.7\"", "myst-parser (==4.0.0) ; python_version >= \"3.11\"", "pre-commit (==4.0.1) ; python_version >= \"3.9\"", "pytest (==6.1.2) ; python_version < \"3.8\"", "pytest (==8.3.2) ; python_version >= \"3.8\"", "pytest-cov (==2.12.1) ; python_version < \"3.8\"", "pytest-cov (==5.0.0) ; python_version == \"3.8\"", "pytest-cov (==6.0.0) ; python_version >= \"3.9\"", "pytest-mypy-plugins (==1.9.3) ; python_version >= \"3.6\" and python_version < \"3.8\"", "pytest-mypy-plugins (==3.1.0) ; python_version >= \"3.8\"", "sphinx-rtd-theme (==3.0.2) ; python_version >= \"3.11\"", "tox (==3.27.1) ; python_version < \"3.8\"", "tox (==4.23.2) ; python_version >= \"3.8\"", "twine (==6.0.1) ; python_version >= \"3.11\""] +[[package]] +name = "lupa" +version = "2.6" +description = "Python wrapper around Lua and LuaJIT" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "lupa-2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6b3dabda836317e63c5ad052826e156610f356a04b3003dfa0dbe66b5d54d671"}, + {file = "lupa-2.6-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:8726d1c123bbe9fbb974ce29825e94121824e66003038ff4532c14cc2ed0c51c"}, + {file = "lupa-2.6-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:f4e159e7d814171199b246f9235ca8961f6461ea8c1165ab428afa13c9289a94"}, + {file = "lupa-2.6-cp310-cp310-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:202160e80dbfddfb79316692a563d843b767e0f6787bbd1c455f9d54052efa6c"}, + {file = "lupa-2.6-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5deede7c5b36ab64f869dae4831720428b67955b0bb186c8349cf6ea121c852b"}, + {file = "lupa-2.6-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:86f04901f920bbf7c0cac56807dc9597e42347123e6f1f3ca920f15f54188ce5"}, + {file = "lupa-2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6deef8f851d6afb965c84849aa5b8c38856942df54597a811ce0369ced678610"}, + {file = "lupa-2.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:21f2b5549681c2a13b1170a26159d30875d367d28f0247b81ca347222c755038"}, + {file = "lupa-2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:66eea57630eab5e6f49fdc5d7811c0a2a41f2011be4ea56a087ea76112011eb7"}, + {file = "lupa-2.6-cp310-cp310-win32.whl", hash = "sha256:60a403de8cab262a4fe813085dd77010effa6e2eb1886db2181df803140533b1"}, + {file = "lupa-2.6-cp310-cp310-win_amd64.whl", hash = "sha256:e4656a39d93dfa947cf3db56dc16c7916cb0cc8024acd3a952071263f675df64"}, + {file = "lupa-2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6d988c0f9331b9f2a5a55186701a25444ab10a1432a1021ee58011499ecbbdd5"}, + {file = "lupa-2.6-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:ebe1bbf48259382c72a6fe363dea61a0fd6fe19eab95e2ae881e20f3654587bf"}, + {file = "lupa-2.6-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:a8fcee258487cf77cdd41560046843bb38c2e18989cd19671dd1e2596f798306"}, + {file = "lupa-2.6-cp311-cp311-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:561a8e3be800827884e767a694727ed8482d066e0d6edfcbf423b05e63b05535"}, + {file = "lupa-2.6-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:af880a62d47991cae78b8e9905c008cbfdc4a3a9723a66310c2634fc7644578c"}, + {file = "lupa-2.6-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:80b22923aa4023c86c0097b235615f89d469a0c4eee0489699c494d3367c4c85"}, + {file = "lupa-2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:153d2cc6b643f7efb9cfc0c6bb55ec784d5bac1a3660cfc5b958a7b8f38f4a75"}, + {file = "lupa-2.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3fa8777e16f3ded50b72967dc17e23f5a08e4f1e2c9456aff2ebdb57f5b2869f"}, + {file = "lupa-2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8dbdcbe818c02a2f56f5ab5ce2de374dab03e84b25266cfbaef237829bc09b3f"}, + {file = "lupa-2.6-cp311-cp311-win32.whl", hash = "sha256:defaf188fde8f7a1e5ce3a5e6d945e533b8b8d547c11e43b96c9b7fe527f56dc"}, + {file = "lupa-2.6-cp311-cp311-win_amd64.whl", hash = "sha256:9505ae600b5c14f3e17e70f87f88d333717f60411faca1ddc6f3e61dce85fa9e"}, + {file = "lupa-2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:47ce718817ef1cc0c40d87c3d5ae56a800d61af00fbc0fad1ca9be12df2f3b56"}, + {file = "lupa-2.6-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:7aba985b15b101495aa4b07112cdc08baa0c545390d560ad5cfde2e9e34f4d58"}, + {file = "lupa-2.6-cp312-cp312-macosx_11_0_x86_64.whl", hash = "sha256:b766f62f95b2739f2248977d29b0722e589dcf4f0ccfa827ccbd29f0148bd2e5"}, + {file = "lupa-2.6-cp312-cp312-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:00a934c23331f94cb51760097ebfab14b005d55a6b30a2b480e3c53dd2fa290d"}, + {file = "lupa-2.6-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21de9f38bd475303e34a042b7081aabdf50bd9bafd36ce4faea2f90fd9f15c31"}, + {file = "lupa-2.6-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf3bda96d3fc41237e964a69c23647d50d4e28421111360274d4799832c560e9"}, + {file = "lupa-2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a76ead245da54801a81053794aa3975f213221f6542d14ec4b859ee2e7e0323"}, + {file = "lupa-2.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8dd0861741caa20886ddbda0a121d8e52fb9b5bb153d82fa9bba796962bf30e8"}, + {file = "lupa-2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:239e63948b0b23023f81d9a19a395e768ed3da6a299f84e7963b8f813f6e3f9c"}, + {file = "lupa-2.6-cp312-cp312-win32.whl", hash = "sha256:325894e1099499e7a6f9c351147661a2011887603c71086d36fe0f964d52d1ce"}, + {file = "lupa-2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c735a1ce8ee60edb0fe71d665f1e6b7c55c6021f1d340eb8c865952c602cd36f"}, + {file = "lupa-2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:663a6e58a0f60e7d212017d6678639ac8df0119bc13c2145029dcba084391310"}, + {file = "lupa-2.6-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:d1f5afda5c20b1f3217a80e9bc1b77037f8a6eb11612fd3ada19065303c8f380"}, + {file = "lupa-2.6-cp313-cp313-macosx_11_0_x86_64.whl", hash = "sha256:26f2b3c085fe76e9119e48c1013c1cccdc1f51585d456858290475aa38e7089e"}, + {file = "lupa-2.6-cp313-cp313-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:60d2f902c7b96fb8ab98493dcff315e7bb4d0b44dc9dd76eb37de575025d5685"}, + {file = "lupa-2.6-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a02d25dee3a3250967c36590128d9220ae02f2eda166a24279da0b481519cbff"}, + {file = "lupa-2.6-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6eae1ee16b886b8914ff292dbefbf2f48abfbdee94b33a88d1d5475e02423203"}, + {file = "lupa-2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0edd5073a4ee74ab36f74fe61450148e6044f3952b8d21248581f3c5d1a58be"}, + {file = "lupa-2.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0c53ee9f22a8a17e7d4266ad48e86f43771951797042dd51d1494aaa4f5f3f0a"}, + {file = "lupa-2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:de7c0f157a9064a400d828789191a96da7f4ce889969a588b87ec80de9b14772"}, + {file = "lupa-2.6-cp313-cp313-win32.whl", hash = "sha256:ee9523941ae0a87b5b703417720c5d78f72d2f5bc23883a2ea80a949a3ed9e75"}, + {file = "lupa-2.6-cp313-cp313-win_amd64.whl", hash = "sha256:b1335a5835b0a25ebdbc75cf0bda195e54d133e4d994877ef025e218c2e59db9"}, + {file = "lupa-2.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:dcb6d0a3264873e1653bc188499f48c1fb4b41a779e315eba45256cfe7bc33c1"}, + {file = "lupa-2.6-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:a37e01f2128f8c36106726cb9d360bac087d58c54b4522b033cc5691c584db18"}, + {file = "lupa-2.6-cp314-cp314-macosx_11_0_x86_64.whl", hash = "sha256:458bd7e9ff3c150b245b0fcfbb9bd2593d1152ea7f0a7b91c1d185846da033fe"}, + {file = "lupa-2.6-cp314-cp314-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:052ee82cac5206a02df77119c325339acbc09f5ce66967f66a2e12a0f3211cad"}, + {file = "lupa-2.6-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96594eca3c87dd07938009e95e591e43d554c1dbd0385be03c100367141db5a8"}, + {file = "lupa-2.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8faddd9d198688c8884091173a088a8e920ecc96cda2ffed576a23574c4b3f6"}, + {file = "lupa-2.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:daebb3a6b58095c917e76ba727ab37b27477fb926957c825205fbda431552134"}, + {file = "lupa-2.6-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:f3154e68972befe0f81564e37d8142b5d5d79931a18309226a04ec92487d4ea3"}, + {file = "lupa-2.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e4dadf77b9fedc0bfa53417cc28dc2278a26d4cbd95c29f8927ad4d8fe0a7ef9"}, + {file = "lupa-2.6-cp314-cp314-win32.whl", hash = "sha256:cb34169c6fa3bab3e8ac58ca21b8a7102f6a94b6a5d08d3636312f3f02fafd8f"}, + {file = "lupa-2.6-cp314-cp314-win_amd64.whl", hash = "sha256:b74f944fe46c421e25d0f8692aef1e842192f6f7f68034201382ac440ef9ea67"}, + {file = "lupa-2.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0e21b716408a21ab65723f8841cf7f2f37a844b7a965eeabb785e27fca4099cf"}, + {file = "lupa-2.6-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:589db872a141bfff828340079bbdf3e9a31f2689f4ca0d88f97d9e8c2eae6142"}, + {file = "lupa-2.6-cp314-cp314t-macosx_11_0_x86_64.whl", hash = "sha256:cd852a91a4a9d4dcbb9a58100f820a75a425703ec3e3f049055f60b8533b7953"}, + {file = "lupa-2.6-cp314-cp314t-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:0334753be028358922415ca97a64a3048e4ed155413fc4eaf87dd0a7e2752983"}, + {file = "lupa-2.6-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:661d895cd38c87658a34780fac54a690ec036ead743e41b74c3fb81a9e65a6aa"}, + {file = "lupa-2.6-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6aa58454ccc13878cc177c62529a2056be734da16369e451987ff92784994ca7"}, + {file = "lupa-2.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1425017264e470c98022bba8cff5bd46d054a827f5df6b80274f9cc71dafd24f"}, + {file = "lupa-2.6-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:224af0532d216e3105f0a127410f12320f7c5f1aa0300bdf9646b8d9afb0048c"}, + {file = "lupa-2.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9abb98d5a8fd27c8285302e82199f0e56e463066f88f619d6594a450bf269d80"}, + {file = "lupa-2.6-cp314-cp314t-win32.whl", hash = "sha256:1849efeba7a8f6fb8aa2c13790bee988fd242ae404bd459509640eeea3d1e291"}, + {file = "lupa-2.6-cp314-cp314t-win_amd64.whl", hash = "sha256:fc1498d1a4fc028bc521c26d0fad4ca00ed63b952e32fb95949bda76a04bad52"}, + {file = "lupa-2.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9591700991e333b70dd92b48f152eb4731b8b24af671a9f6f721b74d68ed4499"}, + {file = "lupa-2.6-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:ef8dfa7fe08bc3f4591411b8945bbeb15af8512c3e7ad5e9b1e3a9036cdbbce7"}, + {file = "lupa-2.6-cp38-cp38-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:728c466e91174dad238f8a9c1cbdb8e69ffe559df85f87ee76edac3395300949"}, + {file = "lupa-2.6-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c781170bc7134704ae317a66204d30688b41d3e471e17e659987ea4947e11f20"}, + {file = "lupa-2.6-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:241f4ddab33b9a686fc76667241bebc39a06b74ec40d79ec222f5add9000fe57"}, + {file = "lupa-2.6-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:c17f6b6193ced33cc7ca0b2b08b319a1b3501b014a3a3f9999c01cafc04c40f5"}, + {file = "lupa-2.6-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:fa6c1379e83d4104065c151736250a09f3a99e368423c7a20f9c59b15945e9fc"}, + {file = "lupa-2.6-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aef1a8bc10c50695e1a33a07dbef803b93eb97fc150fdb19858d704a603a67dd"}, + {file = "lupa-2.6-cp38-cp38-win32.whl", hash = "sha256:10c191bc1d5565e4360d884bea58320975ddb33270cdf9a9f55d1a1efe79aa03"}, + {file = "lupa-2.6-cp38-cp38-win_amd64.whl", hash = "sha256:05681f8ffb41f0c7fbb9ca859cc3a7e4006e9c6350d25358b535c5295c6a9928"}, + {file = "lupa-2.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8897dc6c3249786b2cdf2f83324febb436193d4581b6a71dea49f77bf8b19bb0"}, + {file = "lupa-2.6-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:4446396ca3830be0c106c70db4b4f622c37b2d447874c07952cafb9c57949a4a"}, + {file = "lupa-2.6-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:5826e687c89995a6eaafeae242071ba16448eec1a9ee8e17ed48551b5d1e21c2"}, + {file = "lupa-2.6-cp39-cp39-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:5871935cb36d1d22f9c04ac0db75c06751bd95edcfa0d9309f732de908e297a9"}, + {file = "lupa-2.6-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:43eb6e43ea8512d0d65b995d36dd9d77aa02598035e25b84c23a1b58700c9fb2"}, + {file = "lupa-2.6-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:559714053018d9885cc8c36a33c5b7eb9aad30fb6357719cac3ce4dc6b39157e"}, + {file = "lupa-2.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:57ac88a00ce59bd9d4ddcd4fca8e02564765725f5068786b011c9d1be3de20c5"}, + {file = "lupa-2.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:b683fbd867c2e54c44a686361b75eee7e7a790da55afdbe89f1f23b106de0274"}, + {file = "lupa-2.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d2f656903a2ed2e074bf2b7d300968028dfa327a45b055be8e3b51ef0b82f9bf"}, + {file = "lupa-2.6-cp39-cp39-win32.whl", hash = "sha256:bf28f68ae231b72008523ab5ac23835ba0f76e0e99ec38b59766080a84eb596a"}, + {file = "lupa-2.6-cp39-cp39-win_amd64.whl", hash = "sha256:b4b2e9b3795a9897cf6cfcc58d08210fdc0d13ab47c9a0e13858c68932d8353c"}, + {file = "lupa-2.6.tar.gz", hash = "sha256:9a770a6e89576be3447668d7ced312cd6fd41d3c13c2462c9dc2c2ab570e45d9"}, +] + [[package]] name = "lxml" version = "6.0.2" @@ -4216,14 +4447,14 @@ files = [ [[package]] name = "marshmallow" -version = "3.26.1" +version = "3.26.2" 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.26.1-py3-none-any.whl", hash = "sha256:3350409f20a70a7e4e11a27661187b77cdcaeb20abca41c1454fe33636bea09c"}, - {file = "marshmallow-3.26.1.tar.gz", hash = "sha256:e6d8affb6cb61d39d26402096dc0aee12d5a26d490a121f118d2e81dc0719dc6"}, + {file = "marshmallow-3.26.2-py3-none-any.whl", hash = "sha256:013fa8a3c4c276c24d26d84ce934dc964e2aa794345a0f8c7e5a7191482c8a73"}, + {file = "marshmallow-3.26.2.tar.gz", hash = "sha256:bbe2adb5a03e6e3571b573f42527c6fe926e17467833660bebd11593ab8dfd57"}, ] [package.dependencies] @@ -4254,14 +4485,14 @@ test = ["flake8", "nbdime", "nbval", "notebook", "pytest"] [[package]] name = "mcp" -version = "1.22.0" +version = "1.25.0" description = "Model Context Protocol SDK" optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "mcp-1.22.0-py3-none-any.whl", hash = "sha256:bed758e24df1ed6846989c909ba4e3df339a27b4f30f1b8b627862a4bade4e98"}, - {file = "mcp-1.22.0.tar.gz", hash = "sha256:769b9ac90ed42134375b19e777a2858ca300f95f2e800982b3e2be62dfc0ba01"}, + {file = "mcp-1.25.0-py3-none-any.whl", hash = "sha256:b37c38144a666add0862614cc79ec276e97d72aa8ca26d622818d4e278b9721a"}, + {file = "mcp-1.25.0.tar.gz", hash = "sha256:56310361ebf0364e2d438e5b45f7668cbb124e158bb358333cd06e49e83a6802"}, ] [package.dependencies] @@ -4340,14 +4571,14 @@ gcp = ["google-auth (>=2.27.0)", "requests (>=2.32.3)"] [[package]] name = "mistune" -version = "3.1.4" +version = "3.2.0" description = "A sane and fast Markdown parser with useful plugins and renderers" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "mistune-3.1.4-py3-none-any.whl", hash = "sha256:93691da911e5d9d2e23bc54472892aff676df27a75274962ff9edc210364266d"}, - {file = "mistune-3.1.4.tar.gz", hash = "sha256:b5a7f801d389f724ec702840c11d8fc48f2b33519102fc7ee739e8177b672164"}, + {file = "mistune-3.2.0-py3-none-any.whl", hash = "sha256:febdc629a3c78616b94393c6580551e0e34cc289987ec6c35ed3f4be42d0eee1"}, + {file = "mistune-3.2.0.tar.gz", hash = "sha256:708487c8a8cdd99c9d90eb3ed4c3ed961246ff78ac82f03418f5183ab70e398a"}, ] [[package]] @@ -4585,14 +4816,14 @@ twitter = ["twython"] [[package]] name = "nodeenv" -version = "1.9.1" +version = "1.10.0" description = "Node.js virtual environment builder" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" groups = ["dev"] files = [ - {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, - {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, + {file = "nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827"}, + {file = "nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb"}, ] [[package]] @@ -4710,14 +4941,14 @@ pydantic = ">=2.9" [[package]] name = "openai" -version = "2.8.1" +version = "2.14.0" description = "The official Python library for the openai API" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "openai-2.8.1-py3-none-any.whl", hash = "sha256:c6c3b5a04994734386e8dad3c00a393f56d3b68a27cd2e8acae91a59e4122463"}, - {file = "openai-2.8.1.tar.gz", hash = "sha256:cb1b79eef6e809f6da326a7ef6038719e35aa944c42d081807bfa1be8060f15f"}, + {file = "openai-2.14.0-py3-none-any.whl", hash = "sha256:7ea40aca4ffc4c4a776e77679021b47eec1160e341f42ae086ba949c9dcc9183"}, + {file = "openai-2.14.0.tar.gz", hash = "sha256:419357bedde9402d23bf8f2ee372fca1985a73348debba94bddff06f19459952"}, ] [package.dependencies] @@ -4803,6 +5034,23 @@ opentelemetry-sdk = ">=1.35.0,<1.36.0" requests = ">=2.7,<3.0" typing-extensions = ">=4.5.0" +[[package]] +name = "opentelemetry-exporter-prometheus" +version = "0.56b0" +description = "Prometheus Metric Exporter for OpenTelemetry" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "opentelemetry_exporter_prometheus-0.56b0-py3-none-any.whl", hash = "sha256:0a7d8952e2938f830deb5000505eecf20416ef25fdb591753b9b0cb91d9560ea"}, + {file = "opentelemetry_exporter_prometheus-0.56b0.tar.gz", hash = "sha256:c783146b66400269783b773c5ccedf7d2ff140271478e2816202930a14c07c6b"}, +] + +[package.dependencies] +opentelemetry-api = ">=1.12,<2.0" +opentelemetry-sdk = ">=1.35.0,<1.36.0" +prometheus-client = ">=0.5.0,<1.0.0" + [[package]] name = "opentelemetry-instrumentation" version = "0.56b0" @@ -4905,157 +5153,157 @@ files = [ [[package]] name = "orjson" -version = "3.11.4" +version = "3.11.5" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "orjson-3.11.4-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e3aa2118a3ece0d25489cbe48498de8a5d580e42e8d9979f65bf47900a15aba1"}, - {file = "orjson-3.11.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a69ab657a4e6733133a3dca82768f2f8b884043714e8d2b9ba9f52b6efef5c44"}, - {file = "orjson-3.11.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3740bffd9816fc0326ddc406098a3a8f387e42223f5f455f2a02a9f834ead80c"}, - {file = "orjson-3.11.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65fd2f5730b1bf7f350c6dc896173d3460d235c4be007af73986d7cd9a2acd23"}, - {file = "orjson-3.11.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fdc3ae730541086158d549c97852e2eea6820665d4faf0f41bf99df41bc11ea"}, - {file = "orjson-3.11.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e10b4d65901da88845516ce9f7f9736f9638d19a1d483b3883dc0182e6e5edba"}, - {file = "orjson-3.11.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb6a03a678085f64b97f9d4a9ae69376ce91a3a9e9b56a82b1580d8e1d501aff"}, - {file = "orjson-3.11.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2c82e4f0b1c712477317434761fbc28b044c838b6b1240d895607441412371ac"}, - {file = "orjson-3.11.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d58c166a18f44cc9e2bad03a327dc2d1a3d2e85b847133cfbafd6bfc6719bd79"}, - {file = "orjson-3.11.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:94f206766bf1ea30e1382e4890f763bd1eefddc580e08fec1ccdc20ddd95c827"}, - {file = "orjson-3.11.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:41bf25fb39a34cf8edb4398818523277ee7096689db352036a9e8437f2f3ee6b"}, - {file = "orjson-3.11.4-cp310-cp310-win32.whl", hash = "sha256:fa9627eba4e82f99ca6d29bc967f09aba446ee2b5a1ea728949ede73d313f5d3"}, - {file = "orjson-3.11.4-cp310-cp310-win_amd64.whl", hash = "sha256:23ef7abc7fca96632d8174ac115e668c1e931b8fe4dde586e92a500bf1914dcc"}, - {file = "orjson-3.11.4-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5e59d23cd93ada23ec59a96f215139753fbfe3a4d989549bcb390f8c00370b39"}, - {file = "orjson-3.11.4-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:5c3aedecfc1beb988c27c79d52ebefab93b6c3921dbec361167e6559aba2d36d"}, - {file = "orjson-3.11.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da9e5301f1c2caa2a9a4a303480d79c9ad73560b2e7761de742ab39fe59d9175"}, - {file = "orjson-3.11.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8873812c164a90a79f65368f8f96817e59e35d0cc02786a5356f0e2abed78040"}, - {file = "orjson-3.11.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5d7feb0741ebb15204e748f26c9638e6665a5fa93c37a2c73d64f1669b0ddc63"}, - {file = "orjson-3.11.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01ee5487fefee21e6910da4c2ee9eef005bee568a0879834df86f888d2ffbdd9"}, - {file = "orjson-3.11.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d40d46f348c0321df01507f92b95a377240c4ec31985225a6668f10e2676f9a"}, - {file = "orjson-3.11.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95713e5fc8af84d8edc75b785d2386f653b63d62b16d681687746734b4dfc0be"}, - {file = "orjson-3.11.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ad73ede24f9083614d6c4ca9a85fe70e33be7bf047ec586ee2363bc7418fe4d7"}, - {file = "orjson-3.11.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:842289889de515421f3f224ef9c1f1efb199a32d76d8d2ca2706fa8afe749549"}, - {file = "orjson-3.11.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3b2427ed5791619851c52a1261b45c233930977e7de8cf36de05636c708fa905"}, - {file = "orjson-3.11.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c36e524af1d29982e9b190573677ea02781456b2e537d5840e4538a5ec41907"}, - {file = "orjson-3.11.4-cp311-cp311-win32.whl", hash = "sha256:87255b88756eab4a68ec61837ca754e5d10fa8bc47dc57f75cedfeaec358d54c"}, - {file = "orjson-3.11.4-cp311-cp311-win_amd64.whl", hash = "sha256:e2d5d5d798aba9a0e1fede8d853fa899ce2cb930ec0857365f700dffc2c7af6a"}, - {file = "orjson-3.11.4-cp311-cp311-win_arm64.whl", hash = "sha256:6bb6bb41b14c95d4f2702bce9975fda4516f1db48e500102fc4d8119032ff045"}, - {file = "orjson-3.11.4-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d4371de39319d05d3f482f372720b841c841b52f5385bd99c61ed69d55d9ab50"}, - {file = "orjson-3.11.4-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:e41fd3b3cac850eaae78232f37325ed7d7436e11c471246b87b2cd294ec94853"}, - {file = "orjson-3.11.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:600e0e9ca042878c7fdf189cf1b028fe2c1418cc9195f6cb9824eb6ed99cb938"}, - {file = "orjson-3.11.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7bbf9b333f1568ef5da42bc96e18bf30fd7f8d54e9ae066d711056add508e415"}, - {file = "orjson-3.11.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4806363144bb6e7297b8e95870e78d30a649fdc4e23fc84daa80c8ebd366ce44"}, - {file = "orjson-3.11.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad355e8308493f527d41154e9053b86a5be892b3b359a5c6d5d95cda23601cb2"}, - {file = "orjson-3.11.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c8a7517482667fb9f0ff1b2f16fe5829296ed7a655d04d68cd9711a4d8a4e708"}, - {file = "orjson-3.11.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97eb5942c7395a171cbfecc4ef6701fc3c403e762194683772df4c54cfbb2210"}, - {file = "orjson-3.11.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:149d95d5e018bdd822e3f38c103b1a7c91f88d38a88aada5c4e9b3a73a244241"}, - {file = "orjson-3.11.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:624f3951181eb46fc47dea3d221554e98784c823e7069edb5dbd0dc826ac909b"}, - {file = "orjson-3.11.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:03bfa548cf35e3f8b3a96c4e8e41f753c686ff3d8e182ce275b1751deddab58c"}, - {file = "orjson-3.11.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:525021896afef44a68148f6ed8a8bf8375553d6066c7f48537657f64823565b9"}, - {file = "orjson-3.11.4-cp312-cp312-win32.whl", hash = "sha256:b58430396687ce0f7d9eeb3dd47761ca7d8fda8e9eb92b3077a7a353a75efefa"}, - {file = "orjson-3.11.4-cp312-cp312-win_amd64.whl", hash = "sha256:c6dbf422894e1e3c80a177133c0dda260f81428f9de16d61041949f6a2e5c140"}, - {file = "orjson-3.11.4-cp312-cp312-win_arm64.whl", hash = "sha256:d38d2bc06d6415852224fcc9c0bfa834c25431e466dc319f0edd56cca81aa96e"}, - {file = "orjson-3.11.4-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:2d6737d0e616a6e053c8b4acc9eccea6b6cce078533666f32d140e4f85002534"}, - {file = "orjson-3.11.4-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:afb14052690aa328cc118a8e09f07c651d301a72e44920b887c519b313d892ff"}, - {file = "orjson-3.11.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38aa9e65c591febb1b0aed8da4d469eba239d434c218562df179885c94e1a3ad"}, - {file = "orjson-3.11.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f2cf4dfaf9163b0728d061bebc1e08631875c51cd30bf47cb9e3293bfbd7dcd5"}, - {file = "orjson-3.11.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89216ff3dfdde0e4070932e126320a1752c9d9a758d6a32ec54b3b9334991a6a"}, - {file = "orjson-3.11.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9daa26ca8e97fae0ce8aa5d80606ef8f7914e9b129b6b5df9104266f764ce436"}, - {file = "orjson-3.11.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c8b2769dc31883c44a9cd126560327767f848eb95f99c36c9932f51090bfce9"}, - {file = "orjson-3.11.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1469d254b9884f984026bd9b0fa5bbab477a4bfe558bba6848086f6d43eb5e73"}, - {file = "orjson-3.11.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:68e44722541983614e37117209a194e8c3ad07838ccb3127d96863c95ec7f1e0"}, - {file = "orjson-3.11.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:8e7805fda9672c12be2f22ae124dcd7b03928d6c197544fe12174b86553f3196"}, - {file = "orjson-3.11.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:04b69c14615fb4434ab867bf6f38b2d649f6f300af30a6705397e895f7aec67a"}, - {file = "orjson-3.11.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:639c3735b8ae7f970066930e58cf0ed39a852d417c24acd4a25fc0b3da3c39a6"}, - {file = "orjson-3.11.4-cp313-cp313-win32.whl", hash = "sha256:6c13879c0d2964335491463302a6ca5ad98105fc5db3565499dcb80b1b4bd839"}, - {file = "orjson-3.11.4-cp313-cp313-win_amd64.whl", hash = "sha256:09bf242a4af98732db9f9a1ec57ca2604848e16f132e3f72edfd3c5c96de009a"}, - {file = "orjson-3.11.4-cp313-cp313-win_arm64.whl", hash = "sha256:a85f0adf63319d6c1ba06fb0dbf997fced64a01179cf17939a6caca662bf92de"}, - {file = "orjson-3.11.4-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:42d43a1f552be1a112af0b21c10a5f553983c2a0938d2bbb8ecd8bc9fb572803"}, - {file = "orjson-3.11.4-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:26a20f3fbc6c7ff2cb8e89c4c5897762c9d88cf37330c6a117312365d6781d54"}, - {file = "orjson-3.11.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e3f20be9048941c7ffa8fc523ccbd17f82e24df1549d1d1fe9317712d19938e"}, - {file = "orjson-3.11.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aac364c758dc87a52e68e349924d7e4ded348dedff553889e4d9f22f74785316"}, - {file = "orjson-3.11.4-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d5c54a6d76e3d741dcc3f2707f8eeb9ba2a791d3adbf18f900219b62942803b1"}, - {file = "orjson-3.11.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f28485bdca8617b79d44627f5fb04336897041dfd9fa66d383a49d09d86798bc"}, - {file = "orjson-3.11.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bfc2a484cad3585e4ba61985a6062a4c2ed5c7925db6d39f1fa267c9d166487f"}, - {file = "orjson-3.11.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e34dbd508cb91c54f9c9788923daca129fe5b55c5b4eebe713bf5ed3791280cf"}, - {file = "orjson-3.11.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b13c478fa413d4b4ee606ec8e11c3b2e52683a640b006bb586b3041c2ca5f606"}, - {file = "orjson-3.11.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:724ca721ecc8a831b319dcd72cfa370cc380db0bf94537f08f7edd0a7d4e1780"}, - {file = "orjson-3.11.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:977c393f2e44845ce1b540e19a786e9643221b3323dae190668a98672d43fb23"}, - {file = "orjson-3.11.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1e539e382cf46edec157ad66b0b0872a90d829a6b71f17cb633d6c160a223155"}, - {file = "orjson-3.11.4-cp314-cp314-win32.whl", hash = "sha256:d63076d625babab9db5e7836118bdfa086e60f37d8a174194ae720161eb12394"}, - {file = "orjson-3.11.4-cp314-cp314-win_amd64.whl", hash = "sha256:0a54d6635fa3aaa438ae32e8570b9f0de36f3f6562c308d2a2a452e8b0592db1"}, - {file = "orjson-3.11.4-cp314-cp314-win_arm64.whl", hash = "sha256:78b999999039db3cf58f6d230f524f04f75f129ba3d1ca2ed121f8657e575d3d"}, - {file = "orjson-3.11.4-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:405261b0a8c62bcbd8e2931c26fdc08714faf7025f45531541e2b29e544b545b"}, - {file = "orjson-3.11.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af02ff34059ee9199a3546f123a6ab4c86caf1708c79042caf0820dc290a6d4f"}, - {file = "orjson-3.11.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b2eba969ea4203c177c7b38b36c69519e6067ee68c34dc37081fac74c796e10"}, - {file = "orjson-3.11.4-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0baa0ea43cfa5b008a28d3c07705cf3ada40e5d347f0f44994a64b1b7b4b5350"}, - {file = "orjson-3.11.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80fd082f5dcc0e94657c144f1b2a3a6479c44ad50be216cf0c244e567f5eae19"}, - {file = "orjson-3.11.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e3704d35e47d5bee811fb1cbd8599f0b4009b14d451c4c57be5a7e25eb89a13"}, - {file = "orjson-3.11.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:caa447f2b5356779d914658519c874cf3b7629e99e63391ed519c28c8aea4919"}, - {file = "orjson-3.11.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:bba5118143373a86f91dadb8df41d9457498226698ebdf8e11cbb54d5b0e802d"}, - {file = "orjson-3.11.4-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:622463ab81d19ef3e06868b576551587de8e4d518892d1afab71e0fbc1f9cffc"}, - {file = "orjson-3.11.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3e0a700c4b82144b72946b6629968df9762552ee1344bfdb767fecdd634fbd5a"}, - {file = "orjson-3.11.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6e18a5c15e764e5f3fc569b47872450b4bcea24f2a6354c0a0e95ad21045d5a9"}, - {file = "orjson-3.11.4-cp39-cp39-win32.whl", hash = "sha256:fb1c37c71cad991ef4d89c7a634b5ffb4447dbd7ae3ae13e8f5ee7f1775e7ab1"}, - {file = "orjson-3.11.4-cp39-cp39-win_amd64.whl", hash = "sha256:e2985ce8b8c42d00492d0ed79f2bd2b6460d00f2fa671dfde4bf2e02f49bf5c6"}, - {file = "orjson-3.11.4.tar.gz", hash = "sha256:39485f4ab4c9b30a3943cfe99e1a213c4776fb69e8abd68f66b83d5a0b0fdc6d"}, + {file = "orjson-3.11.5-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:df9eadb2a6386d5ea2bfd81309c505e125cfc9ba2b1b99a97e60985b0b3665d1"}, + {file = "orjson-3.11.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ccc70da619744467d8f1f49a8cadae5ec7bbe054e5232d95f92ed8737f8c5870"}, + {file = "orjson-3.11.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:073aab025294c2f6fc0807201c76fdaed86f8fc4be52c440fb78fbb759a1ac09"}, + {file = "orjson-3.11.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:835f26fa24ba0bb8c53ae2a9328d1706135b74ec653ed933869b74b6909e63fd"}, + {file = "orjson-3.11.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667c132f1f3651c14522a119e4dd631fad98761fa960c55e8e7430bb2a1ba4ac"}, + {file = "orjson-3.11.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42e8961196af655bb5e63ce6c60d25e8798cd4dfbc04f4203457fa3869322c2e"}, + {file = "orjson-3.11.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75412ca06e20904c19170f8a24486c4e6c7887dea591ba18a1ab572f1300ee9f"}, + {file = "orjson-3.11.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6af8680328c69e15324b5af3ae38abbfcf9cbec37b5346ebfd52339c3d7e8a18"}, + {file = "orjson-3.11.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a86fe4ff4ea523eac8f4b57fdac319faf037d3c1be12405e6a7e86b3fbc4756a"}, + {file = "orjson-3.11.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e607b49b1a106ee2086633167033afbd63f76f2999e9236f638b06b112b24ea7"}, + {file = "orjson-3.11.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7339f41c244d0eea251637727f016b3d20050636695bc78345cce9029b189401"}, + {file = "orjson-3.11.5-cp310-cp310-win32.whl", hash = "sha256:8be318da8413cdbbce77b8c5fac8d13f6eb0f0db41b30bb598631412619572e8"}, + {file = "orjson-3.11.5-cp310-cp310-win_amd64.whl", hash = "sha256:b9f86d69ae822cabc2a0f6c099b43e8733dda788405cba2665595b7e8dd8d167"}, + {file = "orjson-3.11.5-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9c8494625ad60a923af6b2b0bd74107146efe9b55099e20d7740d995f338fcd8"}, + {file = "orjson-3.11.5-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:7bb2ce0b82bc9fd1168a513ddae7a857994b780b2945a8c51db4ab1c4b751ebc"}, + {file = "orjson-3.11.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67394d3becd50b954c4ecd24ac90b5051ee7c903d167459f93e77fc6f5b4c968"}, + {file = "orjson-3.11.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:298d2451f375e5f17b897794bcc3e7b821c0f32b4788b9bcae47ada24d7f3cf7"}, + {file = "orjson-3.11.5-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa5e4244063db8e1d87e0f54c3f7522f14b2dc937e65d5241ef0076a096409fd"}, + {file = "orjson-3.11.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1db2088b490761976c1b2e956d5d4e6409f3732e9d79cfa69f876c5248d1baf9"}, + {file = "orjson-3.11.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c2ed66358f32c24e10ceea518e16eb3549e34f33a9d51f99ce23b0251776a1ef"}, + {file = "orjson-3.11.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2021afda46c1ed64d74b555065dbd4c2558d510d8cec5ea6a53001b3e5e82a9"}, + {file = "orjson-3.11.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b42ffbed9128e547a1647a3e50bc88ab28ae9daa61713962e0d3dd35e820c125"}, + {file = "orjson-3.11.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8d5f16195bb671a5dd3d1dbea758918bada8f6cc27de72bd64adfbd748770814"}, + {file = "orjson-3.11.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c0e5d9f7a0227df2927d343a6e3859bebf9208b427c79bd31949abcc2fa32fa5"}, + {file = "orjson-3.11.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:23d04c4543e78f724c4dfe656b3791b5f98e4c9253e13b2636f1af5d90e4a880"}, + {file = "orjson-3.11.5-cp311-cp311-win32.whl", hash = "sha256:c404603df4865f8e0afe981aa3c4b62b406e6d06049564d58934860b62b7f91d"}, + {file = "orjson-3.11.5-cp311-cp311-win_amd64.whl", hash = "sha256:9645ef655735a74da4990c24ffbd6894828fbfa117bc97c1edd98c282ecb52e1"}, + {file = "orjson-3.11.5-cp311-cp311-win_arm64.whl", hash = "sha256:1cbf2735722623fcdee8e712cbaaab9e372bbcb0c7924ad711b261c2eccf4a5c"}, + {file = "orjson-3.11.5-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:334e5b4bff9ad101237c2d799d9fd45737752929753bf4faf4b207335a416b7d"}, + {file = "orjson-3.11.5-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:ff770589960a86eae279f5d8aa536196ebda8273a2a07db2a54e82b93bc86626"}, + {file = "orjson-3.11.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed24250e55efbcb0b35bed7caaec8cedf858ab2f9f2201f17b8938c618c8ca6f"}, + {file = "orjson-3.11.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a66d7769e98a08a12a139049aac2f0ca3adae989817f8c43337455fbc7669b85"}, + {file = "orjson-3.11.5-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:86cfc555bfd5794d24c6a1903e558b50644e5e68e6471d66502ce5cb5fdef3f9"}, + {file = "orjson-3.11.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a230065027bc2a025e944f9d4714976a81e7ecfa940923283bca7bbc1f10f626"}, + {file = "orjson-3.11.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b29d36b60e606df01959c4b982729c8845c69d1963f88686608be9ced96dbfaa"}, + {file = "orjson-3.11.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c74099c6b230d4261fdc3169d50efc09abf38ace1a42ea2f9994b1d79153d477"}, + {file = "orjson-3.11.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e697d06ad57dd0c7a737771d470eedc18e68dfdefcdd3b7de7f33dfda5b6212e"}, + {file = "orjson-3.11.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e08ca8a6c851e95aaecc32bc44a5aa75d0ad26af8cdac7c77e4ed93acf3d5b69"}, + {file = "orjson-3.11.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e8b5f96c05fce7d0218df3fdfeb962d6b8cfff7e3e20264306b46dd8b217c0f3"}, + {file = "orjson-3.11.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ddbfdb5099b3e6ba6d6ea818f61997bb66de14b411357d24c4612cf1ebad08ca"}, + {file = "orjson-3.11.5-cp312-cp312-win32.whl", hash = "sha256:9172578c4eb09dbfcf1657d43198de59b6cef4054de385365060ed50c458ac98"}, + {file = "orjson-3.11.5-cp312-cp312-win_amd64.whl", hash = "sha256:2b91126e7b470ff2e75746f6f6ee32b9ab67b7a93c8ba1d15d3a0caaf16ec875"}, + {file = "orjson-3.11.5-cp312-cp312-win_arm64.whl", hash = "sha256:acbc5fac7e06777555b0722b8ad5f574739e99ffe99467ed63da98f97f9ca0fe"}, + {file = "orjson-3.11.5-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:3b01799262081a4c47c035dd77c1301d40f568f77cc7ec1bb7db5d63b0a01629"}, + {file = "orjson-3.11.5-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:61de247948108484779f57a9f406e4c84d636fa5a59e411e6352484985e8a7c3"}, + {file = "orjson-3.11.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:894aea2e63d4f24a7f04a1908307c738d0dce992e9249e744b8f4e8dd9197f39"}, + {file = "orjson-3.11.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ddc21521598dbe369d83d4d40338e23d4101dad21dae0e79fa20465dbace019f"}, + {file = "orjson-3.11.5-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7cce16ae2f5fb2c53c3eafdd1706cb7b6530a67cc1c17abe8ec747f5cd7c0c51"}, + {file = "orjson-3.11.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e46c762d9f0e1cfb4ccc8515de7f349abbc95b59cb5a2bd68df5973fdef913f8"}, + {file = "orjson-3.11.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7345c759276b798ccd6d77a87136029e71e66a8bbf2d2755cbdde1d82e78706"}, + {file = "orjson-3.11.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75bc2e59e6a2ac1dd28901d07115abdebc4563b5b07dd612bf64260a201b1c7f"}, + {file = "orjson-3.11.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:54aae9b654554c3b4edd61896b978568c6daa16af96fa4681c9b5babd469f863"}, + {file = "orjson-3.11.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4bdd8d164a871c4ec773f9de0f6fe8769c2d6727879c37a9666ba4183b7f8228"}, + {file = "orjson-3.11.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a261fef929bcf98a60713bf5e95ad067cea16ae345d9a35034e73c3990e927d2"}, + {file = "orjson-3.11.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c028a394c766693c5c9909dec76b24f37e6a1b91999e8d0c0d5feecbe93c3e05"}, + {file = "orjson-3.11.5-cp313-cp313-win32.whl", hash = "sha256:2cc79aaad1dfabe1bd2d50ee09814a1253164b3da4c00a78c458d82d04b3bdef"}, + {file = "orjson-3.11.5-cp313-cp313-win_amd64.whl", hash = "sha256:ff7877d376add4e16b274e35a3f58b7f37b362abf4aa31863dadacdd20e3a583"}, + {file = "orjson-3.11.5-cp313-cp313-win_arm64.whl", hash = "sha256:59ac72ea775c88b163ba8d21b0177628bd015c5dd060647bbab6e22da3aad287"}, + {file = "orjson-3.11.5-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e446a8ea0a4c366ceafc7d97067bfd55292969143b57e3c846d87fc701e797a0"}, + {file = "orjson-3.11.5-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:53deb5addae9c22bbe3739298f5f2196afa881ea75944e7720681c7080909a81"}, + {file = "orjson-3.11.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82cd00d49d6063d2b8791da5d4f9d20539c5951f965e45ccf4e96d33505ce68f"}, + {file = "orjson-3.11.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3fd15f9fc8c203aeceff4fda211157fad114dde66e92e24097b3647a08f4ee9e"}, + {file = "orjson-3.11.5-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9df95000fbe6777bf9820ae82ab7578e8662051bb5f83d71a28992f539d2cda7"}, + {file = "orjson-3.11.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92a8d676748fca47ade5bc3da7430ed7767afe51b2f8100e3cd65e151c0eaceb"}, + {file = "orjson-3.11.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa0f513be38b40234c77975e68805506cad5d57b3dfd8fe3baa7f4f4051e15b4"}, + {file = "orjson-3.11.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1863e75b92891f553b7922ce4ee10ed06db061e104f2b7815de80cdcb135ad"}, + {file = "orjson-3.11.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d4be86b58e9ea262617b8ca6251a2f0d63cc132a6da4b5fcc8e0a4128782c829"}, + {file = "orjson-3.11.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:b923c1c13fa02084eb38c9c065afd860a5cff58026813319a06949c3af5732ac"}, + {file = "orjson-3.11.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:1b6bd351202b2cd987f35a13b5e16471cf4d952b42a73c391cc537974c43ef6d"}, + {file = "orjson-3.11.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bb150d529637d541e6af06bbe3d02f5498d628b7f98267ff87647584293ab439"}, + {file = "orjson-3.11.5-cp314-cp314-win32.whl", hash = "sha256:9cc1e55c884921434a84a0c3dd2699eb9f92e7b441d7f53f3941079ec6ce7499"}, + {file = "orjson-3.11.5-cp314-cp314-win_amd64.whl", hash = "sha256:a4f3cb2d874e03bc7767c8f88adaa1a9a05cecea3712649c3b58589ec7317310"}, + {file = "orjson-3.11.5-cp314-cp314-win_arm64.whl", hash = "sha256:38b22f476c351f9a1c43e5b07d8b5a02eb24a6ab8e75f700f7d479d4568346a5"}, + {file = "orjson-3.11.5-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1b280e2d2d284a6713b0cfec7b08918ebe57df23e3f76b27586197afca3cb1e9"}, + {file = "orjson-3.11.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c8d8a112b274fae8c5f0f01954cb0480137072c271f3f4958127b010dfefaec"}, + {file = "orjson-3.11.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f0a2ae6f09ac7bd47d2d5a5305c1d9ed08ac057cda55bb0a49fa506f0d2da00"}, + {file = "orjson-3.11.5-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c0d87bd1896faac0d10b4f849016db81a63e4ec5df38757ffae84d45ab38aa71"}, + {file = "orjson-3.11.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:801a821e8e6099b8c459ac7540b3c32dba6013437c57fdcaec205b169754f38c"}, + {file = "orjson-3.11.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69a0f6ac618c98c74b7fbc8c0172ba86f9e01dbf9f62aa0b1776c2231a7bffe5"}, + {file = "orjson-3.11.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fea7339bdd22e6f1060c55ac31b6a755d86a5b2ad3657f2669ec243f8e3b2bdb"}, + {file = "orjson-3.11.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4dad582bc93cef8f26513e12771e76385a7e6187fd713157e971c784112aad56"}, + {file = "orjson-3.11.5-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:0522003e9f7fba91982e83a97fec0708f5a714c96c4209db7104e6b9d132f111"}, + {file = "orjson-3.11.5-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:7403851e430a478440ecc1258bcbacbfbd8175f9ac1e39031a7121dd0de05ff8"}, + {file = "orjson-3.11.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5f691263425d3177977c8d1dd896cde7b98d93cbf390b2544a090675e83a6a0a"}, + {file = "orjson-3.11.5-cp39-cp39-win32.whl", hash = "sha256:61026196a1c4b968e1b1e540563e277843082e9e97d78afa03eb89315af531f1"}, + {file = "orjson-3.11.5-cp39-cp39-win_amd64.whl", hash = "sha256:09b94b947ac08586af635ef922d69dc9bc63321527a3a04647f4986a73f4bd30"}, + {file = "orjson-3.11.5.tar.gz", hash = "sha256:82393ab47b4fe44ffd0a7659fa9cfaacc717eb617c93cde83795f14af5c2e9d5"}, ] [[package]] name = "ormsgpack" -version = "1.12.0" -description = "" +version = "1.12.1" +description = "Fast, correct Python msgpack library supporting dataclasses, datetimes, and numpy" optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "ormsgpack-1.12.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e08904c232358b94a682ccfbb680bc47d3fd5c424bb7dccb65974dd20c95e8e1"}, - {file = "ormsgpack-1.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9ed7a4b0037d69c8ba7e670e03ee65ae8d5c5114a409e73c5770d7fb5e4b895"}, - {file = "ormsgpack-1.12.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:db2928525b684f3f2af0367aef7ae8d20cde37fc5349c700017129d493a755aa"}, - {file = "ormsgpack-1.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45f911d9c5b23d11e49ff03fc8f9566745a2b1a7d9033733a1c0a2fa9301cd60"}, - {file = "ormsgpack-1.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:98c54ae6fd682b2aceb264505af9b2255f3df9d84e6e4369bc44d2110f1f311d"}, - {file = "ormsgpack-1.12.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:857ab987c3502de08258cc4baf0e87267cb2c80931601084e13df3c355b1ab9d"}, - {file = "ormsgpack-1.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:27579d45dc502ee736238e1024559cb0a01aa72a3b68827448b8edf6a2dcdc9c"}, - {file = "ormsgpack-1.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:c78379d054760875540cf2e81f28da1bb78d09fda3eabdbeb6c53b3e297158cb"}, - {file = "ormsgpack-1.12.0-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:c40d86d77391b18dd34de5295e3de2b8ad818bcab9c9def4121c8ec5c9714ae4"}, - {file = "ormsgpack-1.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:777b7fab364dc0f200bb382a98a385c8222ffa6a2333d627d763797326202c86"}, - {file = "ormsgpack-1.12.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b5089ad9dd5b3d3013b245a55e4abaea2f8ad70f4a78e1b002127b02340004"}, - {file = "ormsgpack-1.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:deaf0c87cace7bc08fbf68c5cc66605b593df6427e9f4de235b2da358787e008"}, - {file = "ormsgpack-1.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f62d476fe28bc5675d9aff30341bfa9f41d7de332c5b63fbbe9aaf6bb7ec74d4"}, - {file = "ormsgpack-1.12.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ded7810095b887e28434f32f5a345d354e88cf851bab3c5435aeb86a718618d2"}, - {file = "ormsgpack-1.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f72a1dea0c4ae7c4101dcfbe8133f274a9d769d0b87fe5188db4fab07ffabaee"}, - {file = "ormsgpack-1.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:8f479bfef847255d7d0b12c7a198f6a21490155da2da3062e082ba370893d4a1"}, - {file = "ormsgpack-1.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:3583ca410e4502144b2594170542e4bbef7b15643fd1208703ae820f11029036"}, - {file = "ormsgpack-1.12.0-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e0c1e08b64d99076fee155276097489b82cc56e8d5951c03c721a65a32f44494"}, - {file = "ormsgpack-1.12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3fd43bcb299131690b8e0677af172020b2ada8e625169034b42ac0c13adf84aa"}, - {file = "ormsgpack-1.12.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f0149d595341e22ead340bf281b2995c4cc7dc8d522a6b5f575fe17aa407604"}, - {file = "ormsgpack-1.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f19a1b27d169deb553c80fd10b589fc2be1fc14cee779fae79fcaf40db04de2b"}, - {file = "ormsgpack-1.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6f28896942d655064940dfe06118b7ce1e3468d051483148bf02c99ec157483a"}, - {file = "ormsgpack-1.12.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:9396efcfa48b4abbc06e44c5dbc3c4574a8381a80cb4cd01eea15d28b38c554e"}, - {file = "ormsgpack-1.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:96586ed537a5fb386a162c4f9f7d8e6f76e07b38a990d50c73f11131e00ff040"}, - {file = "ormsgpack-1.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:e70387112fb3870e4844de090014212cdcf1342f5022047aecca01ec7de05d7a"}, - {file = "ormsgpack-1.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:d71290a23de5d4829610c42665d816c661ecad8979883f3f06b2e3ab9639962e"}, - {file = "ormsgpack-1.12.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:766f2f3b512d85cd375b26a8b1329b99843560b50b93d3880718e634ad4a5de5"}, - {file = "ormsgpack-1.12.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84b285b1f3f185aad7da45641b873b30acfd13084cf829cf668c4c6480a81583"}, - {file = "ormsgpack-1.12.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e23604fc79fe110292cb365f4c8232e64e63a34f470538be320feae3921f271b"}, - {file = "ormsgpack-1.12.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc32b156c113a0fae2975051417d8d9a7a5247c34b2d7239410c46b75ce9348a"}, - {file = "ormsgpack-1.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:94ac500dd10c20fa8b8a23bc55606250bfe711bf9716828d9f3d44dfd1f25668"}, - {file = "ormsgpack-1.12.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:c5201ff7ec24f721f813a182885a17064cffdbe46b2412685a52e6374a872c8f"}, - {file = "ormsgpack-1.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a9740bb3839c9368aacae1cbcfc474ee6976458f41cc135372b7255d5206c953"}, - {file = "ormsgpack-1.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ed37f29772432048b58174e920a1d4c4cde0404a5d448d3d8bbcc95d86a6918"}, - {file = "ormsgpack-1.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:b03994bbec5d6d42e03d6604e327863f885bde67aa61e06107ce1fa5bdd3e71d"}, - {file = "ormsgpack-1.12.0-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0f3981ba3cba80656012090337e548e597799e14b41e3d0b595ab5ab05a23d7f"}, - {file = "ormsgpack-1.12.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:901f6f55184d6776dbd5183cbce14caf05bf7f467eef52faf9b094686980bf71"}, - {file = "ormsgpack-1.12.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e13b15412571422b711b40f45e3fe6d993ea3314b5e97d1a853fe99226c5effc"}, - {file = "ormsgpack-1.12.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91fa8a452553a62e5fb3fbab471e7faf7b3bec3c87a2f355ebf3d7aab290fe4f"}, - {file = "ormsgpack-1.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:74ec101f69624695eec4ce7c953192d97748254abe78fb01b591f06d529e1952"}, - {file = "ormsgpack-1.12.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:9bbf7896580848326c1f9bd7531f264e561f98db7e08e15aa75963d83832c717"}, - {file = "ormsgpack-1.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7567917da613b8f8d591c1674e411fd3404bea41ef2b9a0e0a1e049c0f9406d7"}, - {file = "ormsgpack-1.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:4e418256c5d8622b8bc92861936f7c6a0131355e7bcad88a42102ae8227f8a1c"}, - {file = "ormsgpack-1.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:433ace29aa02713554f714c62a4e4dcad0c9e32674ba4f66742c91a4c3b1b969"}, - {file = "ormsgpack-1.12.0-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e57164be4ca34b64e210ec515059193280ac84df4d6f31a6fcbfb2fc8436de55"}, - {file = "ormsgpack-1.12.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:904f96289deaa92fc6440b122edc27c5bdc28234edd63717f6d853d88c823a83"}, - {file = "ormsgpack-1.12.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b291d086e524a1062d57d1b7b5a8bcaaf29caebf0212fec12fd86240bd33633"}, - {file = "ormsgpack-1.12.0.tar.gz", hash = "sha256:94be818fdbb0285945839b88763b269987787cb2f7ef280cad5d6ec815b7e608"}, + {file = "ormsgpack-1.12.1-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:62e3614cab63fa5aa42f5f0ca3cd12899f0bfc5eb8a5a0ebab09d571c89d427d"}, + {file = "ormsgpack-1.12.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86d9fbf85c05c69c33c229d2eba7c8c3500a56596cd8348131c918acd040d6af"}, + {file = "ormsgpack-1.12.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8d246e66f09d8e0f96e770829149ee83206e90ed12f5987998bb7be84aec99fe"}, + {file = "ormsgpack-1.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cfc2c830a1ed2d00de713d08c9e62efa699e8fd29beafa626aaebe466f583ebb"}, + {file = "ormsgpack-1.12.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bc892757d8f9eea5208268a527cf93c98409802f6a9f7c8d71a7b8f9ba5cb944"}, + {file = "ormsgpack-1.12.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:0de1dbcf11ea739ac4a882b43d5c2055e6d99ce64e8d6502e25d6d881700c017"}, + {file = "ormsgpack-1.12.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d5065dfb9ec4db93241c60847624d9aeef4ccb449c26a018c216b55c69be83c0"}, + {file = "ormsgpack-1.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:7d17103c4726181d7000c61b751c881f1b6f401d146df12da028fc730227df19"}, + {file = "ormsgpack-1.12.1-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:4038f59ae0e19dac5e5d9aae4ec17ff84a79e046342ee73ccdecf3547ecf0d34"}, + {file = "ormsgpack-1.12.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16c63b0c5a3eec467e4bb33a14dabba076b7d934dff62898297b5c0b5f7c3cb3"}, + {file = "ormsgpack-1.12.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:74fd6a8e037eb310dda865298e8d122540af00fe5658ec18b97a1d34f4012e4d"}, + {file = "ormsgpack-1.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58ad60308e233dd824a1859eabb5fe092e123e885eafa4ad5789322329c80fb5"}, + {file = "ormsgpack-1.12.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:35127464c941c1219acbe1a220e48d55e7933373d12257202f4042f7044b4c90"}, + {file = "ormsgpack-1.12.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:c48d1c50794692d1e6e3f8c3bb65f5c3acfaae9347e506484a65d60b3d91fb50"}, + {file = "ormsgpack-1.12.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b512b2ad6feaaefdc26e05431ed2843e42483041e354e167c53401afaa83d919"}, + {file = "ormsgpack-1.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:93f30db95e101a9616323bfc50807ad00e7f6197cea2216d2d24af42afc77d88"}, + {file = "ormsgpack-1.12.1-cp311-cp311-win_arm64.whl", hash = "sha256:d75b5fa14f6abffce2c392ee03b4731199d8a964c81ee8645c4c79af0e80fd50"}, + {file = "ormsgpack-1.12.1-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:4d7fb0e1b6fbc701d75269f7405a4f79230a6ce0063fb1092e4f6577e312f86d"}, + {file = "ormsgpack-1.12.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43a9353e2db5b024c91a47d864ef15eaa62d81824cfc7740fed4cef7db738694"}, + {file = "ormsgpack-1.12.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fc8fe866b7706fc25af0adf1f600bc06ece5b15ca44e34641327198b821e5c3c"}, + {file = "ormsgpack-1.12.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:813755b5f598a78242042e05dfd1ada4e769e94b98c9ab82554550f97ff4d641"}, + {file = "ormsgpack-1.12.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8eea2a13536fae45d78f93f2cc846c9765c7160c85f19cfefecc20873c137cdd"}, + {file = "ormsgpack-1.12.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7a02ebda1a863cbc604740e76faca8eee1add322db2dcbe6cf32669fffdff65c"}, + {file = "ormsgpack-1.12.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3c0bd63897c439931cdf29348e5e6e8c330d529830e848d10767615c0f3d1b82"}, + {file = "ormsgpack-1.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:362f2e812f8d7035dc25a009171e09d7cc97cb30d3c9e75a16aeae00ca3c1dcf"}, + {file = "ormsgpack-1.12.1-cp312-cp312-win_arm64.whl", hash = "sha256:6190281e381db2ed0045052208f47a995ccf61eed48f1215ae3cce3fbccd59c5"}, + {file = "ormsgpack-1.12.1-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:9663d6b3ecc917c063d61a99169ce196a80f3852e541ae404206836749459279"}, + {file = "ormsgpack-1.12.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32e85cfbaf01a94a92520e7fe7851cfcfe21a5698299c28ab86194895f9b9233"}, + {file = "ormsgpack-1.12.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dabfd2c24b59c7c69870a5ecee480dfae914a42a0c2e7c9d971cf531e2ba471a"}, + {file = "ormsgpack-1.12.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51bbf2b64afeded34ccd8e25402e4bca038757913931fa0d693078d75563f6f9"}, + {file = "ormsgpack-1.12.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9959a71dde1bd0ced84af17facc06a8afada495a34e9cb1bad8e9b20d4c59cef"}, + {file = "ormsgpack-1.12.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:e9be0e3b62d758f21f5b20e0e06b3a240ec546c4a327bf771f5825462aa74714"}, + {file = "ormsgpack-1.12.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a29d49ab7fdd77ea787818e60cb4ef491708105b9c4c9b0f919201625eb036b5"}, + {file = "ormsgpack-1.12.1-cp313-cp313-win_amd64.whl", hash = "sha256:c418390b47a1d367e803f6c187f77e4d67c7ae07ba962e3a4a019001f4b0291a"}, + {file = "ormsgpack-1.12.1-cp313-cp313-win_arm64.whl", hash = "sha256:cfa22c91cffc10a7fbd43729baff2de7d9c28cef2509085a704168ae31f02568"}, + {file = "ormsgpack-1.12.1-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:b93c91efb1a70751a1902a5b43b27bd8fd38e0ca0365cf2cde2716423c15c3a6"}, + {file = "ormsgpack-1.12.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf0ea0389167b5fa8d2933dd3f33e887ec4ba68f89c25214d7eec4afd746d22"}, + {file = "ormsgpack-1.12.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f4c29af837f35af3375070689e781161e7cf019eb2f7cd641734ae45cd001c0d"}, + {file = "ormsgpack-1.12.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:336fc65aa0fe65896a3dabaae31e332a0a98b4a00ad7b0afde21a7505fd23ff3"}, + {file = "ormsgpack-1.12.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:940f60aabfefe71dd6b82cb33f4ff10b2e7f5fcfa5f103cdb0a23b6aae4c713c"}, + {file = "ormsgpack-1.12.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:596ad9e1b6d4c95595c54aaf49b1392609ca68f562ce06f4f74a5bc4053bcda4"}, + {file = "ormsgpack-1.12.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:575210e8fcbc7b0375026ba040a5eef223e9f66a4453d9623fc23282ae09c3c8"}, + {file = "ormsgpack-1.12.1-cp314-cp314-win_amd64.whl", hash = "sha256:647daa3718572280893456be44c60aea6690b7f2edc54c55648ee66e8f06550f"}, + {file = "ormsgpack-1.12.1-cp314-cp314-win_arm64.whl", hash = "sha256:a8b3ab762a6deaf1b6490ab46dda0c51528cf8037e0246c40875c6fe9e37b699"}, + {file = "ormsgpack-1.12.1-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:12087214e436c1f6c28491949571abea759a63111908c4f7266586d78144d7a8"}, + {file = "ormsgpack-1.12.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e6d54c14cf86ef13f10ccade94d1e7de146aa9b17d371e18b16e95f329393b7"}, + {file = "ormsgpack-1.12.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f3584d07882b7ea2a1a589f795a3af97fe4c2932b739408e6d1d9d286cad862"}, + {file = "ormsgpack-1.12.1.tar.gz", hash = "sha256:a3877fde1e4f27a39f92681a0aab6385af3a41d0c25375d33590ae20410ea2ac"}, ] [[package]] @@ -5145,14 +5393,14 @@ ptyprocess = ">=0.5" [[package]] name = "pgvector" -version = "0.4.1" +version = "0.4.2" description = "pgvector support for Python" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pgvector-0.4.1-py3-none-any.whl", hash = "sha256:34bb4e99e1b13d08a2fe82dda9f860f15ddcd0166fbb25bffe15821cbfeb7362"}, - {file = "pgvector-0.4.1.tar.gz", hash = "sha256:83d3a1c044ff0c2f1e95d13dfb625beb0b65506cfec0941bfe81fd0ad44f4003"}, + {file = "pgvector-0.4.2-py3-none-any.whl", hash = "sha256:549d45f7a18593783d5eec609ea1684a724ba8405c4cb182a0b2b08aeff04e08"}, + {file = "pgvector-0.4.2.tar.gz", hash = "sha256:322cac0c1dc5d41c9ecf782bd9991b7966685dee3a00bc873631391ed949513a"}, ] [package.dependencies] @@ -5269,14 +5517,14 @@ xmp = ["defusedxml"] [[package]] name = "platformdirs" -version = "4.5.0" +version = "4.5.1" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.10" groups = ["main", "dev"] files = [ - {file = "platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3"}, - {file = "platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312"}, + {file = "platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31"}, + {file = "platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda"}, ] [package.extras] @@ -5365,6 +5613,21 @@ files = [ [package.extras] dev = ["certifi", "mypy (>=1.14.1)", "pytest (>=8.1.1)", "pytest-asyncio (>=0.25.3)", "ruff (>=0.9.2)", "typing-extensions ; python_full_version < \"3.12.0\""] +[[package]] +name = "prometheus-client" +version = "0.23.1" +description = "Python client for the Prometheus monitoring system." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "prometheus_client-0.23.1-py3-none-any.whl", hash = "sha256:dd1913e6e76b59cfe44e7a4b83e01afc9873c1bdfd2ed8739f1e76aeca115f99"}, + {file = "prometheus_client-0.23.1.tar.gz", hash = "sha256:6ae8f9081eaaaf153a2e959d2e6c4f4fb57b12ef76c8c7980202f1e57b48b2ce"}, +] + +[package.extras] +twisted = ["twisted"] + [[package]] name = "prompt-toolkit" version = "3.0.52" @@ -5514,56 +5777,58 @@ files = [ [[package]] name = "protobuf" -version = "6.33.1" +version = "6.33.2" description = "" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "protobuf-6.33.1-cp310-abi3-win32.whl", hash = "sha256:f8d3fdbc966aaab1d05046d0240dd94d40f2a8c62856d41eaa141ff64a79de6b"}, - {file = "protobuf-6.33.1-cp310-abi3-win_amd64.whl", hash = "sha256:923aa6d27a92bf44394f6abf7ea0500f38769d4b07f4be41cb52bd8b1123b9ed"}, - {file = "protobuf-6.33.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:fe34575f2bdde76ac429ec7b570235bf0c788883e70aee90068e9981806f2490"}, - {file = "protobuf-6.33.1-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:f8adba2e44cde2d7618996b3fc02341f03f5bc3f2748be72dc7b063319276178"}, - {file = "protobuf-6.33.1-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:0f4cf01222c0d959c2b399142deb526de420be8236f22c71356e2a544e153c53"}, - {file = "protobuf-6.33.1-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:8fd7d5e0eb08cd5b87fd3df49bc193f5cfd778701f47e11d127d0afc6c39f1d1"}, - {file = "protobuf-6.33.1-cp39-cp39-win32.whl", hash = "sha256:023af8449482fa884d88b4563d85e83accab54138ae098924a985bcbb734a213"}, - {file = "protobuf-6.33.1-cp39-cp39-win_amd64.whl", hash = "sha256:df051de4fd7e5e4371334e234c62ba43763f15ab605579e04c7008c05735cd82"}, - {file = "protobuf-6.33.1-py3-none-any.whl", hash = "sha256:d595a9fd694fdeb061a62fbe10eb039cc1e444df81ec9bb70c7fc59ebcb1eafa"}, - {file = "protobuf-6.33.1.tar.gz", hash = "sha256:97f65757e8d09870de6fd973aeddb92f85435607235d20b2dfed93405d00c85b"}, + {file = "protobuf-6.33.2-cp310-abi3-win32.whl", hash = "sha256:87eb388bd2d0f78febd8f4c8779c79247b26a5befad525008e49a6955787ff3d"}, + {file = "protobuf-6.33.2-cp310-abi3-win_amd64.whl", hash = "sha256:fc2a0e8b05b180e5fc0dd1559fe8ebdae21a27e81ac77728fb6c42b12c7419b4"}, + {file = "protobuf-6.33.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d9b19771ca75935b3a4422957bc518b0cecb978b31d1dd12037b088f6bcc0e43"}, + {file = "protobuf-6.33.2-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:b5d3b5625192214066d99b2b605f5783483575656784de223f00a8d00754fc0e"}, + {file = "protobuf-6.33.2-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:8cd7640aee0b7828b6d03ae518b5b4806fdfc1afe8de82f79c3454f8aef29872"}, + {file = "protobuf-6.33.2-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:1f8017c48c07ec5859106533b682260ba3d7c5567b1ca1f24297ce03384d1b4f"}, + {file = "protobuf-6.33.2-cp39-cp39-win32.whl", hash = "sha256:7109dcc38a680d033ffb8bf896727423528db9163be1b6a02d6a49606dcadbfe"}, + {file = "protobuf-6.33.2-cp39-cp39-win_amd64.whl", hash = "sha256:2981c58f582f44b6b13173e12bb8656711189c2a70250845f264b877f00b1913"}, + {file = "protobuf-6.33.2-py3-none-any.whl", hash = "sha256:7636aad9bb01768870266de5dc009de2d1b936771b38a793f73cbbf279c91c5c"}, + {file = "protobuf-6.33.2.tar.gz", hash = "sha256:56dc370c91fbb8ac85bc13582c9e373569668a290aa2e66a590c2a0d35ddb9e4"}, ] [[package]] name = "psutil" -version = "7.1.3" +version = "7.2.0" description = "Cross-platform lib for process and system monitoring." optional = false python-versions = ">=3.6" groups = ["main"] files = [ - {file = "psutil-7.1.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0005da714eee687b4b8decd3d6cc7c6db36215c9e74e5ad2264b90c3df7d92dc"}, - {file = "psutil-7.1.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:19644c85dcb987e35eeeaefdc3915d059dac7bd1167cdcdbf27e0ce2df0c08c0"}, - {file = "psutil-7.1.3-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:95ef04cf2e5ba0ab9eaafc4a11eaae91b44f4ef5541acd2ee91d9108d00d59a7"}, - {file = "psutil-7.1.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1068c303be3a72f8e18e412c5b2a8f6d31750fb152f9cb106b54090296c9d251"}, - {file = "psutil-7.1.3-cp313-cp313t-win_amd64.whl", hash = "sha256:18349c5c24b06ac5612c0428ec2a0331c26443d259e2a0144a9b24b4395b58fa"}, - {file = "psutil-7.1.3-cp313-cp313t-win_arm64.whl", hash = "sha256:c525ffa774fe4496282fb0b1187725793de3e7c6b29e41562733cae9ada151ee"}, - {file = "psutil-7.1.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:b403da1df4d6d43973dc004d19cee3b848e998ae3154cc8097d139b77156c353"}, - {file = "psutil-7.1.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ad81425efc5e75da3f39b3e636293360ad8d0b49bed7df824c79764fb4ba9b8b"}, - {file = "psutil-7.1.3-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f33a3702e167783a9213db10ad29650ebf383946e91bc77f28a5eb083496bc9"}, - {file = "psutil-7.1.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fac9cd332c67f4422504297889da5ab7e05fd11e3c4392140f7370f4208ded1f"}, - {file = "psutil-7.1.3-cp314-cp314t-win_amd64.whl", hash = "sha256:3792983e23b69843aea49c8f5b8f115572c5ab64c153bada5270086a2123c7e7"}, - {file = "psutil-7.1.3-cp314-cp314t-win_arm64.whl", hash = "sha256:31d77fcedb7529f27bb3a0472bea9334349f9a04160e8e6e5020f22c59893264"}, - {file = "psutil-7.1.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2bdbcd0e58ca14996a42adf3621a6244f1bb2e2e528886959c72cf1e326677ab"}, - {file = "psutil-7.1.3-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:bc31fa00f1fbc3c3802141eede66f3a2d51d89716a194bf2cd6fc68310a19880"}, - {file = "psutil-7.1.3-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3bb428f9f05c1225a558f53e30ccbad9930b11c3fc206836242de1091d3e7dd3"}, - {file = "psutil-7.1.3-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56d974e02ca2c8eb4812c3f76c30e28836fffc311d55d979f1465c1feeb2b68b"}, - {file = "psutil-7.1.3-cp37-abi3-win_amd64.whl", hash = "sha256:f39c2c19fe824b47484b96f9692932248a54c43799a84282cfe58d05a6449efd"}, - {file = "psutil-7.1.3-cp37-abi3-win_arm64.whl", hash = "sha256:bd0d69cee829226a761e92f28140bec9a5ee9d5b4fb4b0cc589068dbfff559b1"}, - {file = "psutil-7.1.3.tar.gz", hash = "sha256:6c86281738d77335af7aec228328e944b30930899ea760ecf33a4dba66be5e74"}, + {file = "psutil-7.2.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:c31e927555539132a00380c971816ea43d089bf4bd5f3e918ed8c16776d68474"}, + {file = "psutil-7.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:db8e44e766cef86dea47d9a1fa535d38dc76449e5878a92f33683b7dba5bfcb2"}, + {file = "psutil-7.2.0-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85ef849ac92169dedc59a7ac2fb565f47b3468fbe1524bf748746bc21afb94c7"}, + {file = "psutil-7.2.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:26782bdbae2f5c14ce9ebe8ad2411dc2ca870495e0cd90f8910ede7fa5e27117"}, + {file = "psutil-7.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:b7665f612d3b38a583391b95969667a53aaf6c5706dc27a602c9a4874fbf09e4"}, + {file = "psutil-7.2.0-cp313-cp313t-win_arm64.whl", hash = "sha256:4413373c174520ae28a24a8974ad8ce6b21f060d27dde94e25f8c73a7effe57a"}, + {file = "psutil-7.2.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:2f2f53fd114e7946dfba3afb98c9b7c7f376009447360ca15bfb73f2066f84c7"}, + {file = "psutil-7.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e65c41d7e60068f60ce43b31a3a7fc90deb0dfd34ffc824a2574c2e5279b377e"}, + {file = "psutil-7.2.0-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cc66d21366850a4261412ce994ae9976bba9852dafb4f2fa60db68ed17ff5281"}, + {file = "psutil-7.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e025d67b42b8f22b096d5d20f5171de0e0fefb2f0ce983a13c5a1b5ed9872706"}, + {file = "psutil-7.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:45f6b91f7ad63414d6454fd609e5e3556d0e1038d5d9c75a1368513bdf763f57"}, + {file = "psutil-7.2.0-cp314-cp314t-win_arm64.whl", hash = "sha256:87b18a19574139d60a546e88b5f5b9cbad598e26cdc790d204ab95d7024f03ee"}, + {file = "psutil-7.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:977a2fcd132d15cb05b32b2d85b98d087cad039b0ce435731670ba74da9e6133"}, + {file = "psutil-7.2.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:24151011c21fadd94214d7139d7c6c54569290d7e553989bdf0eab73b13beb8c"}, + {file = "psutil-7.2.0-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:91f211ba9279e7c61d9d8f84b713cfc38fa161cb0597d5cb3f1ca742f6848254"}, + {file = "psutil-7.2.0-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f37415188b7ea98faf90fed51131181646c59098b077550246e2e092e127418b"}, + {file = "psutil-7.2.0-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0d12c7ce6ed1128cd81fd54606afa054ac7dbb9773469ebb58cf2f171c49f2ac"}, + {file = "psutil-7.2.0-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ca0faef7976530940dcd39bc5382d0d0d5eb023b186a4901ca341bd8d8684151"}, + {file = "psutil-7.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:abdb74137ca232d20250e9ad471f58d500e7743bc8253ba0bfbf26e570c0e437"}, + {file = "psutil-7.2.0-cp37-abi3-win_arm64.whl", hash = "sha256:284e71038b3139e7ab3834b63b3eb5aa5565fcd61a681ec746ef9a0a8c457fd2"}, + {file = "psutil-7.2.0.tar.gz", hash = "sha256:2e4f8e1552f77d14dc96fb0f6240c5b34a37081c0889f0853b3b29a496e5ef64"}, ] [package.extras] -dev = ["abi3audit", "black", "check-manifest", "colorama ; os_name == \"nt\"", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pyreadline ; os_name == \"nt\"", "pytest", "pytest-cov", "pytest-instafail", "pytest-subtests", "pytest-xdist", "pywin32 ; os_name == \"nt\" and platform_python_implementation != \"PyPy\"", "requests", "rstcheck", "ruff", "setuptools", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "validate-pyproject[all]", "virtualenv", "vulture", "wheel", "wheel ; os_name == \"nt\" and platform_python_implementation != \"PyPy\"", "wmi ; os_name == \"nt\" and platform_python_implementation != \"PyPy\""] -test = ["pytest", "pytest-instafail", "pytest-subtests", "pytest-xdist", "pywin32 ; os_name == \"nt\" and platform_python_implementation != \"PyPy\"", "setuptools", "wheel ; os_name == \"nt\" and platform_python_implementation != \"PyPy\"", "wmi ; os_name == \"nt\" and platform_python_implementation != \"PyPy\""] +dev = ["abi3audit", "black", "check-manifest", "coverage", "packaging", "psleak", "pylint", "pyperf", "pypinfo", "pytest", "pytest-cov", "pytest-instafail", "pytest-xdist", "requests", "rstcheck", "ruff", "setuptools", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "validate-pyproject[all]", "virtualenv", "vulture", "wheel"] +test = ["psleak", "pytest", "pytest-instafail", "pytest-xdist", "setuptools"] [[package]] name = "psycopg2" @@ -5612,54 +5877,57 @@ tests = ["pytest"] [[package]] name = "py-key-value-aio" -version = "0.2.8" +version = "0.3.0" description = "Async Key-Value" optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "py_key_value_aio-0.2.8-py3-none-any.whl", hash = "sha256:561565547ce8162128fd2bd0b9d70ce04a5f4586da8500cce79a54dfac78c46a"}, - {file = "py_key_value_aio-0.2.8.tar.gz", hash = "sha256:c0cfbb0bd4e962a3fa1a9fa6db9ba9df812899bd9312fa6368aaea7b26008b36"}, + {file = "py_key_value_aio-0.3.0-py3-none-any.whl", hash = "sha256:1c781915766078bfd608daa769fefb97e65d1d73746a3dfb640460e322071b64"}, + {file = "py_key_value_aio-0.3.0.tar.gz", hash = "sha256:858e852fcf6d696d231266da66042d3355a7f9871650415feef9fca7a6cd4155"}, ] [package.dependencies] -beartype = ">=0.22.2" -cachetools = {version = ">=6.0.0", optional = true, markers = "extra == \"memory\""} -diskcache = {version = ">=5.6.0", optional = true, markers = "extra == \"disk\""} +beartype = ">=0.20.0" +cachetools = {version = ">=5.0.0", optional = true, markers = "extra == \"memory\""} +diskcache = {version = ">=5.0.0", optional = true, markers = "extra == \"disk\""} keyring = {version = ">=25.6.0", optional = true, markers = "extra == \"keyring\""} pathvalidate = {version = ">=3.3.1", optional = true, markers = "extra == \"disk\""} -py-key-value-shared = "0.2.8" +py-key-value-shared = "0.3.0" +redis = {version = ">=4.3.0", optional = true, markers = "extra == \"redis\""} [package.extras] -disk = ["diskcache (>=5.6.0)", "pathvalidate (>=3.3.1)"] +disk = ["diskcache (>=5.0.0)", "pathvalidate (>=3.3.1)"] +duckdb = ["duckdb (>=1.1.1)", "pytz (>=2025.2)"] dynamodb = ["aioboto3 (>=13.3.0)", "types-aiobotocore-dynamodb (>=2.16.0)"] -elasticsearch = ["aiohttp (>=3.12)", "elasticsearch (>=9.0.0)"] +elasticsearch = ["aiohttp (>=3.12)", "elasticsearch (>=8.0.0)"] +filetree = ["aiofile (>=3.5.0)", "anyio (>=4.4.0)"] keyring = ["keyring (>=25.6.0)"] keyring-linux = ["dbus-python (>=1.4.0)", "keyring (>=25.6.0)"] memcached = ["aiomcache (>=0.8.0)"] -memory = ["cachetools (>=6.0.0)"] -mongodb = ["pymongo (>=4.15.0)"] +memory = ["cachetools (>=5.0.0)"] +mongodb = ["pymongo (>=4.0.0)"] pydantic = ["pydantic (>=2.11.9)"] redis = ["redis (>=4.3.0)"] -rocksdb = ["rocksdict (>=0.3.0)"] +rocksdb = ["rocksdict (>=0.3.2) ; python_full_version < \"3.12.0\"", "rocksdict (>=0.3.24) ; python_full_version >= \"3.12.0\""] valkey = ["valkey-glide (>=2.1.0)"] vault = ["hvac (>=2.3.0)", "types-hvac (>=2.3.0)"] wrappers-encryption = ["cryptography (>=45.0.0)"] [[package]] name = "py-key-value-shared" -version = "0.2.8" +version = "0.3.0" description = "Shared Key-Value" optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "py_key_value_shared-0.2.8-py3-none-any.whl", hash = "sha256:aff1bbfd46d065b2d67897d298642e80e5349eae588c6d11b48452b46b8d46ba"}, - {file = "py_key_value_shared-0.2.8.tar.gz", hash = "sha256:703b4d3c61af124f0d528ba85995c3c8d78f8bd3d2b217377bd3278598070cc1"}, + {file = "py_key_value_shared-0.3.0-py3-none-any.whl", hash = "sha256:5b0efba7ebca08bb158b1e93afc2f07d30b8f40c2fc12ce24a4c0d84f42f9298"}, + {file = "py_key_value_shared-0.3.0.tar.gz", hash = "sha256:8fdd786cf96c3e900102945f92aa1473138ebe960ef49da1c833790160c28a4b"}, ] [package.dependencies] -beartype = ">=0.22.2" +beartype = ">=0.20.0" typing-extensions = ">=4.15.0" [[package]] @@ -6023,20 +6291,45 @@ gcp-secret-manager = ["google-cloud-secret-manager (>=2.23.1)"] toml = ["tomli (>=2.0.1)"] yaml = ["pyyaml (>=6.0.1)"] +[[package]] +name = "pydocket" +version = "0.15.4" +description = "A distributed background task system for Python functions" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "pydocket-0.15.4-py3-none-any.whl", hash = "sha256:21a961f87cd995b40df3f559fb0bae75d925ec0916c10b9739b6c1638ffde436"}, + {file = "pydocket-0.15.4.tar.gz", hash = "sha256:31c79bca5eb11dfac8635d3e5b81ec7d7c8949c8c8cfc536ae76753949c147c8"}, +] + +[package.dependencies] +cloudpickle = ">=3.1.1" +fakeredis = {version = ">=2.32.1", extras = ["lua"]} +opentelemetry-api = ">=1.30.0" +opentelemetry-exporter-prometheus = ">=0.51b0" +prometheus-client = ">=0.21.1" +py-key-value-aio = {version = ">=0.3.0", extras = ["memory", "redis"]} +python-json-logger = ">=2.0.7" +redis = ">=5" +rich = ">=13.9.4" +typer = ">=0.15.1" +typing-extensions = ">=4.12.0" + [[package]] name = "pydyf" -version = "0.11.0" +version = "0.12.1" description = "A low-level PDF generator." optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" groups = ["main"] files = [ - {file = "pydyf-0.11.0-py3-none-any.whl", hash = "sha256:0aaf9e2ebbe786ec7a78ec3fbffa4cdcecde53fd6f563221d53c6bc1328848a3"}, - {file = "pydyf-0.11.0.tar.gz", hash = "sha256:394dddf619cca9d0c55715e3c55ea121a9bf9cbc780cdc1201a2427917b86b64"}, + {file = "pydyf-0.12.1-py3-none-any.whl", hash = "sha256:ea25b4e1fe7911195cb57067560daaa266639184e8335365cc3ee5214e7eaadc"}, + {file = "pydyf-0.12.1.tar.gz", hash = "sha256:fbd7e759541ac725c29c506612003de393249b94310ea78ae44cb1d04b220095"}, ] [package.extras] -doc = ["sphinx", "sphinx_rtd_theme"] +doc = ["furo", "sphinx"] test = ["pillow", "pytest", "ruff"] [[package]] @@ -6077,31 +6370,32 @@ tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] [[package]] name = "pymupdf" -version = "1.26.6" +version = "1.26.7" description = "A high performance Python library for data extraction, analysis, conversion & manipulation of PDF (and other) documents." optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "pymupdf-1.26.6-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e46f320a136ad55e5219e8f0f4061bdf3e4c12b126d2740d5a49f73fae7ea176"}, - {file = "pymupdf-1.26.6-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:6844cd2396553c0fa06de4869d5d5ecb1260e6fc3b9d85abe8fa35f14dd9d688"}, - {file = "pymupdf-1.26.6-cp310-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:617ba69e02c44f0da1c0e039ea4a26cf630849fd570e169c71daeb8ac52a81d6"}, - {file = "pymupdf-1.26.6-cp310-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:7777d0b7124c2ebc94849536b6a1fb85d158df3b9d873935e63036559391534c"}, - {file = "pymupdf-1.26.6-cp310-abi3-win32.whl", hash = "sha256:8f3ef05befc90ca6bb0f12983200a7048d5bff3e1c1edef1bb3de60b32cb5274"}, - {file = "pymupdf-1.26.6-cp310-abi3-win_amd64.whl", hash = "sha256:ce02ca96ed0d1acfd00331a4d41a34c98584d034155b06fd4ec0f051718de7ba"}, - {file = "pymupdf-1.26.6.tar.gz", hash = "sha256:a2b4531cd4ab36d6f1f794bb6d3c33b49bda22f36d58bb1f3e81cbc10183bd2b"}, + {file = "pymupdf-1.26.7-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:07085718dfdae5ab83b05eb5eb397f863bcc538fe05135318a01ea353e7a1353"}, + {file = "pymupdf-1.26.7-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:31aa9c8377ea1eea02934b92f4dcf79fb2abba0bf41f8a46d64c3e31546a3c02"}, + {file = "pymupdf-1.26.7-cp310-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e419b609996434a14a80fa060adec72c434a1cca6a511ec54db9841bc5d51b3c"}, + {file = "pymupdf-1.26.7-cp310-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:69dfc78f206a96e5b3ac22741263ebab945fdf51f0dbe7c5757c3511b23d9d72"}, + {file = "pymupdf-1.26.7-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1d5106f46e1ca0d64d46bd51892372a4f82076bdc14a9678d33d630702abca36"}, + {file = "pymupdf-1.26.7-cp310-abi3-win32.whl", hash = "sha256:7c9645b6f5452629c747690190350213d3e5bbdb6b2eca227d82702b327f6eee"}, + {file = "pymupdf-1.26.7-cp310-abi3-win_amd64.whl", hash = "sha256:425b1befe40d41b72eb0fe211711c7ae334db5eb60307e9dd09066ed060cceba"}, + {file = "pymupdf-1.26.7.tar.gz", hash = "sha256:71add8bdc8eb1aaa207c69a13400693f06ad9b927bea976f5d5ab9df0bb489c3"}, ] [[package]] name = "pypdf" -version = "6.4.0" +version = "6.5.0" description = "A pure-python PDF library capable of splitting, merging, cropping, and transforming PDF files" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pypdf-6.4.0-py3-none-any.whl", hash = "sha256:55ab9837ed97fd7fcc5c131d52fcc2223bc5c6b8a1488bbf7c0e27f1f0023a79"}, - {file = "pypdf-6.4.0.tar.gz", hash = "sha256:4769d471f8ddc3341193ecc5d6560fa44cf8cd0abfabf21af4e195cc0c224072"}, + {file = "pypdf-6.5.0-py3-none-any.whl", hash = "sha256:9cef8002aaedeecf648dfd9ff1ce38f20ae8d88e2534fced6630038906440b25"}, + {file = "pypdf-6.5.0.tar.gz", hash = "sha256:9e78950906380ae4f2ce1d9039e9008098ba6366a4d9c7423c4bdbd6e6683404"}, ] [package.extras] @@ -6276,6 +6570,21 @@ files = [ [package.extras] dev = ["black (==25.11.0)", "build (==1.3.0)", "flake8 (==7.3.0)", "mypy (==1.18.2)", "pytest (==9.0.0)", "requests (==2.32.5)", "twine (==6.2.0)"] +[[package]] +name = "python-json-logger" +version = "4.0.0" +description = "JSON Log Formatter for the Python Logging Package" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "python_json_logger-4.0.0-py3-none-any.whl", hash = "sha256:af09c9daf6a813aa4cc7180395f50f2a9e5fa056034c9953aec92e381c5ba1e2"}, + {file = "python_json_logger-4.0.0.tar.gz", hash = "sha256:f58e68eb46e1faed27e0f574a55a0455eecd7b8a5b88b85a784519ba3cff047f"}, +] + +[package.extras] +dev = ["backports.zoneinfo ; python_version < \"3.9\"", "black", "build", "freezegun", "mdx_truly_sane_lists", "mike", "mkdocs", "mkdocs-awesome-pages-plugin", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-material (>=8.5)", "mkdocstrings[python]", "msgspec ; implementation_name != \"pypy\"", "mypy", "orjson ; implementation_name != \"pypy\"", "pylint", "pytest", "tzdata", "validate-pyproject[all]"] + [[package]] name = "python-magic" version = "0.4.27" @@ -6290,14 +6599,14 @@ files = [ [[package]] name = "python-multipart" -version = "0.0.20" +version = "0.0.21" description = "A streaming multipart parser for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" groups = ["main"] files = [ - {file = "python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104"}, - {file = "python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13"}, + {file = "python_multipart-0.0.21-py3-none-any.whl", hash = "sha256:cf7a6713e01c87aa35387f4774e812c4361150938d20d232800f75ffcf266090"}, + {file = "python_multipart-0.0.21.tar.gz", hash = "sha256:7137ebd4d3bbf70ea1622998f902b97a29434a9e8dc40eb203bbcf7c2a2cba92"}, ] [[package]] @@ -6849,127 +7158,127 @@ docs = ["sphinx"] [[package]] name = "rpds-py" -version = "0.29.0" +version = "0.30.0" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "rpds_py-0.29.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:4ae4b88c6617e1b9e5038ab3fccd7bac0842fdda2b703117b2aa99bc85379113"}, - {file = "rpds_py-0.29.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7d9128ec9d8cecda6f044001fde4fb71ea7c24325336612ef8179091eb9596b9"}, - {file = "rpds_py-0.29.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d37812c3da8e06f2bb35b3cf10e4a7b68e776a706c13058997238762b4e07f4f"}, - {file = "rpds_py-0.29.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:66786c3fb1d8de416a7fa8e1cb1ec6ba0a745b2b0eee42f9b7daa26f1a495545"}, - {file = "rpds_py-0.29.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58f5c77f1af888b5fd1876c9a0d9858f6f88a39c9dd7c073a88e57e577da66d"}, - {file = "rpds_py-0.29.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:799156ef1f3529ed82c36eb012b5d7a4cf4b6ef556dd7cc192148991d07206ae"}, - {file = "rpds_py-0.29.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:453783477aa4f2d9104c4b59b08c871431647cb7af51b549bbf2d9eb9c827756"}, - {file = "rpds_py-0.29.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:24a7231493e3c4a4b30138b50cca089a598e52c34cf60b2f35cebf62f274fdea"}, - {file = "rpds_py-0.29.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7033c1010b1f57bb44d8067e8c25aa6fa2e944dbf46ccc8c92b25043839c3fd2"}, - {file = "rpds_py-0.29.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0248b19405422573621172ab8e3a1f29141362d13d9f72bafa2e28ea0cdca5a2"}, - {file = "rpds_py-0.29.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f9f436aee28d13b9ad2c764fc273e0457e37c2e61529a07b928346b219fcde3b"}, - {file = "rpds_py-0.29.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24a16cb7163933906c62c272de20ea3c228e4542c8c45c1d7dc2b9913e17369a"}, - {file = "rpds_py-0.29.0-cp310-cp310-win32.whl", hash = "sha256:1a409b0310a566bfd1be82119891fefbdce615ccc8aa558aff7835c27988cbef"}, - {file = "rpds_py-0.29.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5523b0009e7c3c1263471b69d8da1c7d41b3ecb4cb62ef72be206b92040a950"}, - {file = "rpds_py-0.29.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9b9c764a11fd637e0322a488560533112837f5334ffeb48b1be20f6d98a7b437"}, - {file = "rpds_py-0.29.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3fd2164d73812026ce970d44c3ebd51e019d2a26a4425a5dcbdfa93a34abc383"}, - {file = "rpds_py-0.29.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a097b7f7f7274164566ae90a221fd725363c0e9d243e2e9ed43d195ccc5495c"}, - {file = "rpds_py-0.29.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7cdc0490374e31cedefefaa1520d5fe38e82fde8748cbc926e7284574c714d6b"}, - {file = "rpds_py-0.29.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89ca2e673ddd5bde9b386da9a0aac0cab0e76f40c8f0aaf0d6311b6bbf2aa311"}, - {file = "rpds_py-0.29.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a5d9da3ff5af1ca1249b1adb8ef0573b94c76e6ae880ba1852f033bf429d4588"}, - {file = "rpds_py-0.29.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8238d1d310283e87376c12f658b61e1ee23a14c0e54c7c0ce953efdbdc72deed"}, - {file = "rpds_py-0.29.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:2d6fb2ad1c36f91c4646989811e84b1ea5e0c3cf9690b826b6e32b7965853a63"}, - {file = "rpds_py-0.29.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:534dc9df211387547267ccdb42253aa30527482acb38dd9b21c5c115d66a96d2"}, - {file = "rpds_py-0.29.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d456e64724a075441e4ed648d7f154dc62e9aabff29bcdf723d0c00e9e1d352f"}, - {file = "rpds_py-0.29.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a738f2da2f565989401bd6fd0b15990a4d1523c6d7fe83f300b7e7d17212feca"}, - {file = "rpds_py-0.29.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a110e14508fd26fd2e472bb541f37c209409876ba601cf57e739e87d8a53cf95"}, - {file = "rpds_py-0.29.0-cp311-cp311-win32.whl", hash = "sha256:923248a56dd8d158389a28934f6f69ebf89f218ef96a6b216a9be6861804d3f4"}, - {file = "rpds_py-0.29.0-cp311-cp311-win_amd64.whl", hash = "sha256:539eb77eb043afcc45314d1be09ea6d6cafb3addc73e0547c171c6d636957f60"}, - {file = "rpds_py-0.29.0-cp311-cp311-win_arm64.whl", hash = "sha256:bdb67151ea81fcf02d8f494703fb728d4d34d24556cbff5f417d74f6f5792e7c"}, - {file = "rpds_py-0.29.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a0891cfd8db43e085c0ab93ab7e9b0c8fee84780d436d3b266b113e51e79f954"}, - {file = "rpds_py-0.29.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3897924d3f9a0361472d884051f9a2460358f9a45b1d85a39a158d2f8f1ad71c"}, - {file = "rpds_py-0.29.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a21deb8e0d1571508c6491ce5ea5e25669b1dd4adf1c9d64b6314842f708b5d"}, - {file = "rpds_py-0.29.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9efe71687d6427737a0a2de9ca1c0a216510e6cd08925c44162be23ed7bed2d5"}, - {file = "rpds_py-0.29.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:40f65470919dc189c833e86b2c4bd21bd355f98436a2cef9e0a9a92aebc8e57e"}, - {file = "rpds_py-0.29.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:def48ff59f181130f1a2cb7c517d16328efac3ec03951cca40c1dc2049747e83"}, - {file = "rpds_py-0.29.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad7bd570be92695d89285a4b373006930715b78d96449f686af422debb4d3949"}, - {file = "rpds_py-0.29.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:5a572911cd053137bbff8e3a52d31c5d2dba51d3a67ad902629c70185f3f2181"}, - {file = "rpds_py-0.29.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d583d4403bcbf10cffc3ab5cee23d7643fcc960dff85973fd3c2d6c86e8dbb0c"}, - {file = "rpds_py-0.29.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:070befbb868f257d24c3bb350dbd6e2f645e83731f31264b19d7231dd5c396c7"}, - {file = "rpds_py-0.29.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:fc935f6b20b0c9f919a8ff024739174522abd331978f750a74bb68abd117bd19"}, - {file = "rpds_py-0.29.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8c5a8ecaa44ce2d8d9d20a68a2483a74c07f05d72e94a4dff88906c8807e77b0"}, - {file = "rpds_py-0.29.0-cp312-cp312-win32.whl", hash = "sha256:ba5e1aeaf8dd6d8f6caba1f5539cddda87d511331714b7b5fc908b6cfc3636b7"}, - {file = "rpds_py-0.29.0-cp312-cp312-win_amd64.whl", hash = "sha256:b5f6134faf54b3cb83375db0f113506f8b7770785be1f95a631e7e2892101977"}, - {file = "rpds_py-0.29.0-cp312-cp312-win_arm64.whl", hash = "sha256:b016eddf00dca7944721bf0cd85b6af7f6c4efaf83ee0b37c4133bd39757a8c7"}, - {file = "rpds_py-0.29.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1585648d0760b88292eecab5181f5651111a69d90eff35d6b78aa32998886a61"}, - {file = "rpds_py-0.29.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:521807963971a23996ddaf764c682b3e46459b3c58ccd79fefbe16718db43154"}, - {file = "rpds_py-0.29.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a8896986efaa243ab713c69e6491a4138410f0fe36f2f4c71e18bd5501e8014"}, - {file = "rpds_py-0.29.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1d24564a700ef41480a984c5ebed62b74e6ce5860429b98b1fede76049e953e6"}, - {file = "rpds_py-0.29.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6596b93c010d386ae46c9fba9bfc9fc5965fa8228edeac51576299182c2e31c"}, - {file = "rpds_py-0.29.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5cc58aac218826d054c7da7f95821eba94125d88be673ff44267bb89d12a5866"}, - {file = "rpds_py-0.29.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de73e40ebc04dd5d9556f50180395322193a78ec247e637e741c1b954810f295"}, - {file = "rpds_py-0.29.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:295ce5ac7f0cf69a651ea75c8f76d02a31f98e5698e82a50a5f4d4982fbbae3b"}, - {file = "rpds_py-0.29.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1ea59b23ea931d494459c8338056fe7d93458c0bf3ecc061cd03916505369d55"}, - {file = "rpds_py-0.29.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f49d41559cebd608042fdcf54ba597a4a7555b49ad5c1c0c03e0af82692661cd"}, - {file = "rpds_py-0.29.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:05a2bd42768ea988294ca328206efbcc66e220d2d9b7836ee5712c07ad6340ea"}, - {file = "rpds_py-0.29.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:33ca7bdfedd83339ca55da3a5e1527ee5870d4b8369456b5777b197756f3ca22"}, - {file = "rpds_py-0.29.0-cp313-cp313-win32.whl", hash = "sha256:20c51ae86a0bb9accc9ad4e6cdeec58d5ebb7f1b09dd4466331fc65e1766aae7"}, - {file = "rpds_py-0.29.0-cp313-cp313-win_amd64.whl", hash = "sha256:6410e66f02803600edb0b1889541f4b5cc298a5ccda0ad789cc50ef23b54813e"}, - {file = "rpds_py-0.29.0-cp313-cp313-win_arm64.whl", hash = "sha256:56838e1cd9174dc23c5691ee29f1d1be9eab357f27efef6bded1328b23e1ced2"}, - {file = "rpds_py-0.29.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:37d94eadf764d16b9a04307f2ab1d7af6dc28774bbe0535c9323101e14877b4c"}, - {file = "rpds_py-0.29.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d472cf73efe5726a067dce63eebe8215b14beabea7c12606fd9994267b3cfe2b"}, - {file = "rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:72fdfd5ff8992e4636621826371e3ac5f3e3b8323e9d0e48378e9c13c3dac9d0"}, - {file = "rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2549d833abdf8275c901313b9e8ff8fba57e50f6a495035a2a4e30621a2f7cc4"}, - {file = "rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4448dad428f28a6a767c3e3b80cde3446a22a0efbddaa2360f4bb4dc836d0688"}, - {file = "rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:115f48170fd4296a33938d8c11f697f5f26e0472e43d28f35624764173a60e4d"}, - {file = "rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e5bb73ffc029820f4348e9b66b3027493ae00bca6629129cd433fd7a76308ee"}, - {file = "rpds_py-0.29.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:b1581fcde18fcdf42ea2403a16a6b646f8eb1e58d7f90a0ce693da441f76942e"}, - {file = "rpds_py-0.29.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16e9da2bda9eb17ea318b4c335ec9ac1818e88922cbe03a5743ea0da9ecf74fb"}, - {file = "rpds_py-0.29.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:28fd300326dd21198f311534bdb6d7e989dd09b3418b3a91d54a0f384c700967"}, - {file = "rpds_py-0.29.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2aba991e041d031c7939e1358f583ae405a7bf04804ca806b97a5c0e0af1ea5e"}, - {file = "rpds_py-0.29.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:7f437026dbbc3f08c99cc41a5b2570c6e1a1ddbe48ab19a9b814254128d4ea7a"}, - {file = "rpds_py-0.29.0-cp313-cp313t-win32.whl", hash = "sha256:6e97846e9800a5d0fe7be4d008f0c93d0feeb2700da7b1f7528dabafb31dfadb"}, - {file = "rpds_py-0.29.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f49196aec7c4b406495f60e6f947ad71f317a765f956d74bbd83996b9edc0352"}, - {file = "rpds_py-0.29.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:394d27e4453d3b4d82bb85665dc1fcf4b0badc30fc84282defed71643b50e1a1"}, - {file = "rpds_py-0.29.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:55d827b2ae95425d3be9bc9a5838b6c29d664924f98146557f7715e331d06df8"}, - {file = "rpds_py-0.29.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc31a07ed352e5462d3ee1b22e89285f4ce97d5266f6d1169da1142e78045626"}, - {file = "rpds_py-0.29.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c4695dd224212f6105db7ea62197144230b808d6b2bba52238906a2762f1d1e7"}, - {file = "rpds_py-0.29.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcae1770b401167f8b9e1e3f566562e6966ffa9ce63639916248a9e25fa8a244"}, - {file = "rpds_py-0.29.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:90f30d15f45048448b8da21c41703b31c61119c06c216a1bf8c245812a0f0c17"}, - {file = "rpds_py-0.29.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44a91e0ab77bdc0004b43261a4b8cd6d6b451e8d443754cfda830002b5745b32"}, - {file = "rpds_py-0.29.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:4aa195e5804d32c682e453b34474f411ca108e4291c6a0f824ebdc30a91c973c"}, - {file = "rpds_py-0.29.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7971bdb7bf4ee0f7e6f67fa4c7fbc6019d9850cc977d126904392d363f6f8318"}, - {file = "rpds_py-0.29.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8ae33ad9ce580c7a47452c3b3f7d8a9095ef6208e0a0c7e4e2384f9fc5bf8212"}, - {file = "rpds_py-0.29.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:c661132ab2fb4eeede2ef69670fd60da5235209874d001a98f1542f31f2a8a94"}, - {file = "rpds_py-0.29.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bb78b3a0d31ac1bde132c67015a809948db751cb4e92cdb3f0b242e430b6ed0d"}, - {file = "rpds_py-0.29.0-cp314-cp314-win32.whl", hash = "sha256:f475f103488312e9bd4000bc890a95955a07b2d0b6e8884aef4be56132adbbf1"}, - {file = "rpds_py-0.29.0-cp314-cp314-win_amd64.whl", hash = "sha256:b9cf2359a4fca87cfb6801fae83a76aedf66ee1254a7a151f1341632acf67f1b"}, - {file = "rpds_py-0.29.0-cp314-cp314-win_arm64.whl", hash = "sha256:9ba8028597e824854f0f1733d8b964e914ae3003b22a10c2c664cb6927e0feb9"}, - {file = "rpds_py-0.29.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:e71136fd0612556b35c575dc2726ae04a1669e6a6c378f2240312cf5d1a2ab10"}, - {file = "rpds_py-0.29.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:76fe96632d53f3bf0ea31ede2f53bbe3540cc2736d4aec3b3801b0458499ef3a"}, - {file = "rpds_py-0.29.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9459a33f077130dbb2c7c3cea72ee9932271fb3126404ba2a2661e4fe9eb7b79"}, - {file = "rpds_py-0.29.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5c9546cfdd5d45e562cc0444b6dddc191e625c62e866bf567a2c69487c7ad28a"}, - {file = "rpds_py-0.29.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12597d11d97b8f7e376c88929a6e17acb980e234547c92992f9f7c058f1a7310"}, - {file = "rpds_py-0.29.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28de03cf48b8a9e6ec10318f2197b83946ed91e2891f651a109611be4106ac4b"}, - {file = "rpds_py-0.29.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd7951c964069039acc9d67a8ff1f0a7f34845ae180ca542b17dc1456b1f1808"}, - {file = "rpds_py-0.29.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:c07d107b7316088f1ac0177a7661ca0c6670d443f6fe72e836069025e6266761"}, - {file = "rpds_py-0.29.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1de2345af363d25696969befc0c1688a6cb5e8b1d32b515ef84fc245c6cddba3"}, - {file = "rpds_py-0.29.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:00e56b12d2199ca96068057e1ae7f9998ab6e99cda82431afafd32f3ec98cca9"}, - {file = "rpds_py-0.29.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:3919a3bbecee589300ed25000b6944174e07cd20db70552159207b3f4bbb45b8"}, - {file = "rpds_py-0.29.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e7fa2ccc312bbd91e43aa5e0869e46bc03278a3dddb8d58833150a18b0f0283a"}, - {file = "rpds_py-0.29.0-cp314-cp314t-win32.whl", hash = "sha256:97c817863ffc397f1e6a6e9d2d89fe5408c0a9922dac0329672fb0f35c867ea5"}, - {file = "rpds_py-0.29.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2023473f444752f0f82a58dfcbee040d0a1b3d1b3c2ec40e884bd25db6d117d2"}, - {file = "rpds_py-0.29.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:acd82a9e39082dc5f4492d15a6b6c8599aa21db5c35aaf7d6889aea16502c07d"}, - {file = "rpds_py-0.29.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:715b67eac317bf1c7657508170a3e011a1ea6ccb1c9d5f296e20ba14196be6b3"}, - {file = "rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3b1b87a237cb2dba4db18bcfaaa44ba4cd5936b91121b62292ff21df577fc43"}, - {file = "rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1c3c3e8101bb06e337c88eb0c0ede3187131f19d97d43ea0e1c5407ea74c0cbf"}, - {file = "rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b8e54d6e61f3ecd3abe032065ce83ea63417a24f437e4a3d73d2f85ce7b7cfe"}, - {file = "rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3fbd4e9aebf110473a420dea85a238b254cf8a15acb04b22a5a6b5ce8925b760"}, - {file = "rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80fdf53d36e6c72819993e35d1ebeeb8e8fc688d0c6c2b391b55e335b3afba5a"}, - {file = "rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:ea7173df5d86f625f8dde6d5929629ad811ed8decda3b60ae603903839ac9ac0"}, - {file = "rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:76054d540061eda273274f3d13a21a4abdde90e13eaefdc205db37c05230efce"}, - {file = "rpds_py-0.29.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:9f84c549746a5be3bc7415830747a3a0312573afc9f95785eb35228bb17742ec"}, - {file = "rpds_py-0.29.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:0ea962671af5cb9a260489e311fa22b2e97103e3f9f0caaea6f81390af96a9ed"}, - {file = "rpds_py-0.29.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:f7728653900035fb7b8d06e1e5900545d8088efc9d5d4545782da7df03ec803f"}, - {file = "rpds_py-0.29.0.tar.gz", hash = "sha256:fe55fe686908f50154d1dc599232016e50c243b438c3b7432f24e2895b0e5359"}, + {file = "rpds_py-0.30.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:679ae98e00c0e8d68a7fda324e16b90fd5260945b45d3b824c892cec9eea3288"}, + {file = "rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cc2206b76b4f576934f0ed374b10d7ca5f457858b157ca52064bdfc26b9fc00"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:389a2d49eded1896c3d48b0136ead37c48e221b391c052fba3f4055c367f60a6"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:32c8528634e1bf7121f3de08fa85b138f4e0dc47657866630611b03967f041d7"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f207f69853edd6f6700b86efb84999651baf3789e78a466431df1331608e5324"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67b02ec25ba7a9e8fa74c63b6ca44cf5707f2fbfadae3ee8e7494297d56aa9df"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0e95f6819a19965ff420f65578bacb0b00f251fefe2c8b23347c37174271f3"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:a452763cc5198f2f98898eb98f7569649fe5da666c2dc6b5ddb10fde5a574221"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0b65193a413ccc930671c55153a03ee57cecb49e6227204b04fae512eb657a7"}, + {file = "rpds_py-0.30.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:858738e9c32147f78b3ac24dc0edb6610000e56dc0f700fd5f651d0a0f0eb9ff"}, + {file = "rpds_py-0.30.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:da279aa314f00acbb803da1e76fa18666778e8a8f83484fba94526da5de2cba7"}, + {file = "rpds_py-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7c64d38fb49b6cdeda16ab49e35fe0da2e1e9b34bc38bd78386530f218b37139"}, + {file = "rpds_py-0.30.0-cp310-cp310-win32.whl", hash = "sha256:6de2a32a1665b93233cde140ff8b3467bdb9e2af2b91079f0333a0974d12d464"}, + {file = "rpds_py-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:1726859cd0de969f88dc8673bdd954185b9104e05806be64bcd87badbe313169"}, + {file = "rpds_py-0.30.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a2bffea6a4ca9f01b3f8e548302470306689684e61602aa3d141e34da06cf425"}, + {file = "rpds_py-0.30.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc4f992dfe1e2bc3ebc7444f6c7051b4bc13cd8e33e43511e8ffd13bf407010d"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:422c3cb9856d80b09d30d2eb255d0754b23e090034e1deb4083f8004bd0761e4"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07ae8a593e1c3c6b82ca3292efbe73c30b61332fd612e05abee07c79359f292f"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12f90dd7557b6bd57f40abe7747e81e0c0b119bef015ea7726e69fe550e394a4"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99b47d6ad9a6da00bec6aabe5a6279ecd3c06a329d4aa4771034a21e335c3a97"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33f559f3104504506a44bb666b93a33f5d33133765b0c216a5bf2f1e1503af89"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:946fe926af6e44f3697abbc305ea168c2c31d3e3ef1058cf68f379bf0335a78d"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:495aeca4b93d465efde585977365187149e75383ad2684f81519f504f5c13038"}, + {file = "rpds_py-0.30.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9a0ca5da0386dee0655b4ccdf46119df60e0f10da268d04fe7cc87886872ba7"}, + {file = "rpds_py-0.30.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8d6d1cc13664ec13c1b84241204ff3b12f9bb82464b8ad6e7a5d3486975c2eed"}, + {file = "rpds_py-0.30.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3896fa1be39912cf0757753826bc8bdc8ca331a28a7c4ae46b7a21280b06bb85"}, + {file = "rpds_py-0.30.0-cp311-cp311-win32.whl", hash = "sha256:55f66022632205940f1827effeff17c4fa7ae1953d2b74a8581baaefb7d16f8c"}, + {file = "rpds_py-0.30.0-cp311-cp311-win_amd64.whl", hash = "sha256:a51033ff701fca756439d641c0ad09a41d9242fa69121c7d8769604a0a629825"}, + {file = "rpds_py-0.30.0-cp311-cp311-win_arm64.whl", hash = "sha256:47b0ef6231c58f506ef0b74d44e330405caa8428e770fec25329ed2cb971a229"}, + {file = "rpds_py-0.30.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a161f20d9a43006833cd7068375a94d035714d73a172b681d8881820600abfad"}, + {file = "rpds_py-0.30.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6abc8880d9d036ecaafe709079969f56e876fcf107f7a8e9920ba6d5a3878d05"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca28829ae5f5d569bb62a79512c842a03a12576375d5ece7d2cadf8abe96ec28"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a1010ed9524c73b94d15919ca4d41d8780980e1765babf85f9a2f90d247153dd"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8d1736cfb49381ba528cd5baa46f82fdc65c06e843dab24dd70b63d09121b3f"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d948b135c4693daff7bc2dcfc4ec57237a29bd37e60c2fabf5aff2bbacf3e2f1"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47f236970bccb2233267d89173d3ad2703cd36a0e2a6e92d0560d333871a3d23"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:2e6ecb5a5bcacf59c3f912155044479af1d0b6681280048b338b28e364aca1f6"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a8fa71a2e078c527c3e9dc9fc5a98c9db40bcc8a92b4e8858e36d329f8684b51"}, + {file = "rpds_py-0.30.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:73c67f2db7bc334e518d097c6d1e6fed021bbc9b7d678d6cc433478365d1d5f5"}, + {file = "rpds_py-0.30.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5ba103fb455be00f3b1c2076c9d4264bfcb037c976167a6047ed82f23153f02e"}, + {file = "rpds_py-0.30.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7cee9c752c0364588353e627da8a7e808a66873672bcb5f52890c33fd965b394"}, + {file = "rpds_py-0.30.0-cp312-cp312-win32.whl", hash = "sha256:1ab5b83dbcf55acc8b08fc62b796ef672c457b17dbd7820a11d6c52c06839bdf"}, + {file = "rpds_py-0.30.0-cp312-cp312-win_amd64.whl", hash = "sha256:a090322ca841abd453d43456ac34db46e8b05fd9b3b4ac0c78bcde8b089f959b"}, + {file = "rpds_py-0.30.0-cp312-cp312-win_arm64.whl", hash = "sha256:669b1805bd639dd2989b281be2cfd951c6121b65e729d9b843e9639ef1fd555e"}, + {file = "rpds_py-0.30.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f83424d738204d9770830d35290ff3273fbb02b41f919870479fab14b9d303b2"}, + {file = "rpds_py-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7536cd91353c5273434b4e003cbda89034d67e7710eab8761fd918ec6c69cf8"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2771c6c15973347f50fece41fc447c054b7ac2ae0502388ce3b6738cd366e3d4"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a59119fc6e3f460315fe9d08149f8102aa322299deaa5cab5b40092345c2136"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76fec018282b4ead0364022e3c54b60bf368b9d926877957a8624b58419169b7"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:692bef75a5525db97318e8cd061542b5a79812d711ea03dbc1f6f8dbb0c5f0d2"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9027da1ce107104c50c81383cae773ef5c24d296dd11c99e2629dbd7967a20c6"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:9cf69cdda1f5968a30a359aba2f7f9aa648a9ce4b580d6826437f2b291cfc86e"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a4796a717bf12b9da9d3ad002519a86063dcac8988b030e405704ef7d74d2d9d"}, + {file = "rpds_py-0.30.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d4c2aa7c50ad4728a094ebd5eb46c452e9cb7edbfdb18f9e1221f597a73e1e7"}, + {file = "rpds_py-0.30.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba81a9203d07805435eb06f536d95a266c21e5b2dfbf6517748ca40c98d19e31"}, + {file = "rpds_py-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:945dccface01af02675628334f7cf49c2af4c1c904748efc5cf7bbdf0b579f95"}, + {file = "rpds_py-0.30.0-cp313-cp313-win32.whl", hash = "sha256:b40fb160a2db369a194cb27943582b38f79fc4887291417685f3ad693c5a1d5d"}, + {file = "rpds_py-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:806f36b1b605e2d6a72716f321f20036b9489d29c51c91f4dd29a3e3afb73b15"}, + {file = "rpds_py-0.30.0-cp313-cp313-win_arm64.whl", hash = "sha256:d96c2086587c7c30d44f31f42eae4eac89b60dabbac18c7669be3700f13c3ce1"}, + {file = "rpds_py-0.30.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:eb0b93f2e5c2189ee831ee43f156ed34e2a89a78a66b98cadad955972548be5a"}, + {file = "rpds_py-0.30.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:922e10f31f303c7c920da8981051ff6d8c1a56207dbdf330d9047f6d30b70e5e"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdc62c8286ba9bf7f47befdcea13ea0e26bf294bda99758fd90535cbaf408000"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47f9a91efc418b54fb8190a6b4aa7813a23fb79c51f4bb84e418f5476c38b8db"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f3587eb9b17f3789ad50824084fa6f81921bbf9a795826570bda82cb3ed91f2"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39c02563fc592411c2c61d26b6c5fe1e51eaa44a75aa2c8735ca88b0d9599daa"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51a1234d8febafdfd33a42d97da7a43f5dcb120c1060e352a3fbc0c6d36e2083"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:eb2c4071ab598733724c08221091e8d80e89064cd472819285a9ab0f24bcedb9"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bdfdb946967d816e6adf9a3d8201bfad269c67efe6cefd7093ef959683c8de0"}, + {file = "rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c77afbd5f5250bf27bf516c7c4a016813eb2d3e116139aed0096940c5982da94"}, + {file = "rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:61046904275472a76c8c90c9ccee9013d70a6d0f73eecefd38c1ae7c39045a08"}, + {file = "rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c5f36a861bc4b7da6516dbdf302c55313afa09b81931e8280361a4f6c9a2d27"}, + {file = "rpds_py-0.30.0-cp313-cp313t-win32.whl", hash = "sha256:3d4a69de7a3e50ffc214ae16d79d8fbb0922972da0356dcf4d0fdca2878559c6"}, + {file = "rpds_py-0.30.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f14fc5df50a716f7ece6a80b6c78bb35ea2ca47c499e422aa4463455dd96d56d"}, + {file = "rpds_py-0.30.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:68f19c879420aa08f61203801423f6cd5ac5f0ac4ac82a2368a9fcd6a9a075e0"}, + {file = "rpds_py-0.30.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ec7c4490c672c1a0389d319b3a9cfcd098dcdc4783991553c332a15acf7249be"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f251c812357a3fed308d684a5079ddfb9d933860fc6de89f2b7ab00da481e65f"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac98b175585ecf4c0348fd7b29c3864bda53b805c773cbf7bfdaffc8070c976f"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3e62880792319dbeb7eb866547f2e35973289e7d5696c6e295476448f5b63c87"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e7fc54e0900ab35d041b0601431b0a0eb495f0851a0639b6ef90f7741b39a18"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47e77dc9822d3ad616c3d5759ea5631a75e5809d5a28707744ef79d7a1bcfcad"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:b4dc1a6ff022ff85ecafef7979a2c6eb423430e05f1165d6688234e62ba99a07"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4559c972db3a360808309e06a74628b95eaccbf961c335c8fe0d590cf587456f"}, + {file = "rpds_py-0.30.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0ed177ed9bded28f8deb6ab40c183cd1192aa0de40c12f38be4d59cd33cb5c65"}, + {file = "rpds_py-0.30.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ad1fa8db769b76ea911cb4e10f049d80bf518c104f15b3edb2371cc65375c46f"}, + {file = "rpds_py-0.30.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:46e83c697b1f1c72b50e5ee5adb4353eef7406fb3f2043d64c33f20ad1c2fc53"}, + {file = "rpds_py-0.30.0-cp314-cp314-win32.whl", hash = "sha256:ee454b2a007d57363c2dfd5b6ca4a5d7e2c518938f8ed3b706e37e5d470801ed"}, + {file = "rpds_py-0.30.0-cp314-cp314-win_amd64.whl", hash = "sha256:95f0802447ac2d10bcc69f6dc28fe95fdf17940367b21d34e34c737870758950"}, + {file = "rpds_py-0.30.0-cp314-cp314-win_arm64.whl", hash = "sha256:613aa4771c99f03346e54c3f038e4cc574ac09a3ddfb0e8878487335e96dead6"}, + {file = "rpds_py-0.30.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:7e6ecfcb62edfd632e56983964e6884851786443739dbfe3582947e87274f7cb"}, + {file = "rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a1d0bc22a7cdc173fedebb73ef81e07faef93692b8c1ad3733b67e31e1b6e1b8"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d08f00679177226c4cb8c5265012eea897c8ca3b93f429e546600c971bcbae7"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5965af57d5848192c13534f90f9dd16464f3c37aaf166cc1da1cae1fd5a34898"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a4e86e34e9ab6b667c27f3211ca48f73dba7cd3d90f8d5b11be56e5dbc3fb4e"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5d3e6b26f2c785d65cc25ef1e5267ccbe1b069c5c21b8cc724efee290554419"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:626a7433c34566535b6e56a1b39a7b17ba961e97ce3b80ec62e6f1312c025551"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:acd7eb3f4471577b9b5a41baf02a978e8bdeb08b4b355273994f8b87032000a8"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fe5fa731a1fa8a0a56b0977413f8cacac1768dad38d16b3a296712709476fbd5"}, + {file = "rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:74a3243a411126362712ee1524dfc90c650a503502f135d54d1b352bd01f2404"}, + {file = "rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:3e8eeb0544f2eb0d2581774be4c3410356eba189529a6b3e36bbbf9696175856"}, + {file = "rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dbd936cde57abfee19ab3213cf9c26be06d60750e60a8e4dd85d1ab12c8b1f40"}, + {file = "rpds_py-0.30.0-cp314-cp314t-win32.whl", hash = "sha256:dc824125c72246d924f7f796b4f63c1e9dc810c7d9e2355864b3c3a73d59ade0"}, + {file = "rpds_py-0.30.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27f4b0e92de5bfbc6f86e43959e6edd1425c33b5e69aab0984a72047f2bcf1e3"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c2262bdba0ad4fc6fb5545660673925c2d2a5d9e2e0fb603aad545427be0fc58"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ee6af14263f25eedc3bb918a3c04245106a42dfd4f5c2285ea6f997b1fc3f89a"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3adbb8179ce342d235c31ab8ec511e66c73faa27a47e076ccc92421add53e2bb"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:250fa00e9543ac9b97ac258bd37367ff5256666122c2d0f2bc97577c60a1818c"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9854cf4f488b3d57b9aaeb105f06d78e5529d3145b1e4a41750167e8c213c6d3"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:993914b8e560023bc0a8bf742c5f303551992dcb85e247b1e5c7f4a7d145bda5"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58edca431fb9b29950807e301826586e5bbf24163677732429770a697ffe6738"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:dea5b552272a944763b34394d04577cf0f9bd013207bc32323b5a89a53cf9c2f"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ba3af48635eb83d03f6c9735dfb21785303e73d22ad03d489e88adae6eab8877"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:dff13836529b921e22f15cb099751209a60009731a68519630a24d61f0b1b30a"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:1b151685b23929ab7beec71080a8889d4d6d9fa9a983d213f07121205d48e2c4"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac37f9f516c51e5753f27dfdef11a88330f04de2d564be3991384b2f3535d02e"}, + {file = "rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84"}, ] [[package]] @@ -7018,14 +7327,14 @@ files = [ [[package]] name = "s3transfer" -version = "0.15.0" +version = "0.16.0" description = "An Amazon S3 Transfer Manager" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "s3transfer-0.15.0-py3-none-any.whl", hash = "sha256:6f8bf5caa31a0865c4081186689db1b2534cef721d104eb26101de4b9d6a5852"}, - {file = "s3transfer-0.15.0.tar.gz", hash = "sha256:d36fac8d0e3603eff9b5bfa4282c7ce6feb0301a633566153cbd0b93d11d8379"}, + {file = "s3transfer-0.16.0-py3-none-any.whl", hash = "sha256:18e25d66fed509e3868dc1572b3f427ff947dd2c56f844a5bf09481ad3f3b2fe"}, + {file = "s3transfer-0.16.0.tar.gz", hash = "sha256:8e990f13268025792229cd52fa10cb7163744bf56e719e0b9cb925ab79abf920"}, ] [package.dependencies] @@ -7053,14 +7362,14 @@ jeepney = ">=0.6" [[package]] name = "sentry-sdk" -version = "2.46.0" +version = "2.48.0" description = "Python client for Sentry (https://sentry.io)" optional = false python-versions = ">=3.6" groups = ["main"] files = [ - {file = "sentry_sdk-2.46.0-py2.py3-none-any.whl", hash = "sha256:4eeeb60198074dff8d066ea153fa6f241fef1668c10900ea53a4200abc8da9b1"}, - {file = "sentry_sdk-2.46.0.tar.gz", hash = "sha256:91821a23460725734b7741523021601593f35731808afc0bb2ba46c27b8acd91"}, + {file = "sentry_sdk-2.48.0-py2.py3-none-any.whl", hash = "sha256:6b12ac256769d41825d9b7518444e57fa35b5642df4c7c5e322af4d2c8721172"}, + {file = "sentry_sdk-2.48.0.tar.gz", hash = "sha256:5213190977ff7fdff8a58b722fb807f8d5524a80488626ebeda1b5676c0c1473"}, ] [package.dependencies] @@ -7162,83 +7471,90 @@ files = [ {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, ] +[[package]] +name = "sortedcontainers" +version = "2.4.0" +description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, + {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, +] + [[package]] name = "soupsieve" -version = "2.8" +version = "2.8.1" description = "A modern CSS selector implementation for Beautiful Soup." optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "soupsieve-2.8-py3-none-any.whl", hash = "sha256:0cc76456a30e20f5d7f2e14a98a4ae2ee4e5abdc7c5ea0aafe795f344bc7984c"}, - {file = "soupsieve-2.8.tar.gz", hash = "sha256:e2dd4a40a628cb5f28f6d4b0db8800b8f581b65bb380b97de22ba5ca8d72572f"}, + {file = "soupsieve-2.8.1-py3-none-any.whl", hash = "sha256:a11fe2a6f3d76ab3cf2de04eb339c1be5b506a8a47f2ceb6d139803177f85434"}, + {file = "soupsieve-2.8.1.tar.gz", hash = "sha256:4cf733bc50fa805f5df4b8ef4740fc0e0fa6218cf3006269afd3f9d6d80fd350"}, ] [[package]] name = "sqlalchemy" -version = "2.0.44" +version = "2.0.45" description = "Database Abstraction Library" optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "SQLAlchemy-2.0.44-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:471733aabb2e4848d609141a9e9d56a427c0a038f4abf65dd19d7a21fd563632"}, - {file = "SQLAlchemy-2.0.44-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48bf7d383a35e668b984c805470518b635d48b95a3c57cb03f37eaa3551b5f9f"}, - {file = "SQLAlchemy-2.0.44-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bf4bb6b3d6228fcf3a71b50231199fb94d2dd2611b66d33be0578ea3e6c2726"}, - {file = "SQLAlchemy-2.0.44-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:e998cf7c29473bd077704cea3577d23123094311f59bdc4af551923b168332b1"}, - {file = "SQLAlchemy-2.0.44-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:ebac3f0b5732014a126b43c2b7567f2f0e0afea7d9119a3378bde46d3dcad88e"}, - {file = "SQLAlchemy-2.0.44-cp37-cp37m-win32.whl", hash = "sha256:3255d821ee91bdf824795e936642bbf43a4c7cedf5d1aed8d24524e66843aa74"}, - {file = "SQLAlchemy-2.0.44-cp37-cp37m-win_amd64.whl", hash = "sha256:78e6c137ba35476adb5432103ae1534f2f5295605201d946a4198a0dea4b38e7"}, - {file = "sqlalchemy-2.0.44-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c77f3080674fc529b1bd99489378c7f63fcb4ba7f8322b79732e0258f0ea3ce"}, - {file = "sqlalchemy-2.0.44-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4c26ef74ba842d61635b0152763d057c8d48215d5be9bb8b7604116a059e9985"}, - {file = "sqlalchemy-2.0.44-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4a172b31785e2f00780eccab00bc240ccdbfdb8345f1e6063175b3ff12ad1b0"}, - {file = "sqlalchemy-2.0.44-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9480c0740aabd8cb29c329b422fb65358049840b34aba0adf63162371d2a96e"}, - {file = "sqlalchemy-2.0.44-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:17835885016b9e4d0135720160db3095dc78c583e7b902b6be799fb21035e749"}, - {file = "sqlalchemy-2.0.44-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cbe4f85f50c656d753890f39468fcd8190c5f08282caf19219f684225bfd5fd2"}, - {file = "sqlalchemy-2.0.44-cp310-cp310-win32.whl", hash = "sha256:2fcc4901a86ed81dc76703f3b93ff881e08761c63263c46991081fd7f034b165"}, - {file = "sqlalchemy-2.0.44-cp310-cp310-win_amd64.whl", hash = "sha256:9919e77403a483ab81e3423151e8ffc9dd992c20d2603bf17e4a8161111e55f5"}, - {file = "sqlalchemy-2.0.44-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0fe3917059c7ab2ee3f35e77757062b1bea10a0b6ca633c58391e3f3c6c488dd"}, - {file = "sqlalchemy-2.0.44-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:de4387a354ff230bc979b46b2207af841dc8bf29847b6c7dbe60af186d97aefa"}, - {file = "sqlalchemy-2.0.44-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3678a0fb72c8a6a29422b2732fe423db3ce119c34421b5f9955873eb9b62c1e"}, - {file = "sqlalchemy-2.0.44-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cf6872a23601672d61a68f390e44703442639a12ee9dd5a88bbce52a695e46e"}, - {file = "sqlalchemy-2.0.44-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:329aa42d1be9929603f406186630135be1e7a42569540577ba2c69952b7cf399"}, - {file = "sqlalchemy-2.0.44-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:70e03833faca7166e6a9927fbee7c27e6ecde436774cd0b24bbcc96353bce06b"}, - {file = "sqlalchemy-2.0.44-cp311-cp311-win32.whl", hash = "sha256:253e2f29843fb303eca6b2fc645aca91fa7aa0aa70b38b6950da92d44ff267f3"}, - {file = "sqlalchemy-2.0.44-cp311-cp311-win_amd64.whl", hash = "sha256:7a8694107eb4308a13b425ca8c0e67112f8134c846b6e1f722698708741215d5"}, - {file = "sqlalchemy-2.0.44-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:72fea91746b5890f9e5e0997f16cbf3d53550580d76355ba2d998311b17b2250"}, - {file = "sqlalchemy-2.0.44-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:585c0c852a891450edbb1eaca8648408a3cc125f18cf433941fa6babcc359e29"}, - {file = "sqlalchemy-2.0.44-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b94843a102efa9ac68a7a30cd46df3ff1ed9c658100d30a725d10d9c60a2f44"}, - {file = "sqlalchemy-2.0.44-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:119dc41e7a7defcefc57189cfa0e61b1bf9c228211aba432b53fb71ef367fda1"}, - {file = "sqlalchemy-2.0.44-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0765e318ee9179b3718c4fd7ba35c434f4dd20332fbc6857a5e8df17719c24d7"}, - {file = "sqlalchemy-2.0.44-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2e7b5b079055e02d06a4308d0481658e4f06bc7ef211567edc8f7d5dce52018d"}, - {file = "sqlalchemy-2.0.44-cp312-cp312-win32.whl", hash = "sha256:846541e58b9a81cce7dee8329f352c318de25aa2f2bbe1e31587eb1f057448b4"}, - {file = "sqlalchemy-2.0.44-cp312-cp312-win_amd64.whl", hash = "sha256:7cbcb47fd66ab294703e1644f78971f6f2f1126424d2b300678f419aa73c7b6e"}, - {file = "sqlalchemy-2.0.44-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ff486e183d151e51b1d694c7aa1695747599bb00b9f5f604092b54b74c64a8e1"}, - {file = "sqlalchemy-2.0.44-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0b1af8392eb27b372ddb783b317dea0f650241cea5bd29199b22235299ca2e45"}, - {file = "sqlalchemy-2.0.44-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b61188657e3a2b9ac4e8f04d6cf8e51046e28175f79464c67f2fd35bceb0976"}, - {file = "sqlalchemy-2.0.44-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b87e7b91a5d5973dda5f00cd61ef72ad75a1db73a386b62877d4875a8840959c"}, - {file = "sqlalchemy-2.0.44-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:15f3326f7f0b2bfe406ee562e17f43f36e16167af99c4c0df61db668de20002d"}, - {file = "sqlalchemy-2.0.44-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1e77faf6ff919aa8cd63f1c4e561cac1d9a454a191bb864d5dd5e545935e5a40"}, - {file = "sqlalchemy-2.0.44-cp313-cp313-win32.whl", hash = "sha256:ee51625c2d51f8baadf2829fae817ad0b66b140573939dd69284d2ba3553ae73"}, - {file = "sqlalchemy-2.0.44-cp313-cp313-win_amd64.whl", hash = "sha256:c1c80faaee1a6c3428cecf40d16a2365bcf56c424c92c2b6f0f9ad204b899e9e"}, - {file = "sqlalchemy-2.0.44-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2fc44e5965ea46909a416fff0af48a219faefd5773ab79e5f8a5fcd5d62b2667"}, - {file = "sqlalchemy-2.0.44-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:dc8b3850d2a601ca2320d081874033684e246d28e1c5e89db0864077cfc8f5a9"}, - {file = "sqlalchemy-2.0.44-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d733dec0614bb8f4bcb7c8af88172b974f685a31dc3a65cca0527e3120de5606"}, - {file = "sqlalchemy-2.0.44-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22be14009339b8bc16d6b9dc8780bacaba3402aa7581658e246114abbd2236e3"}, - {file = "sqlalchemy-2.0.44-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:357bade0e46064f88f2c3a99808233e67b0051cdddf82992379559322dfeb183"}, - {file = "sqlalchemy-2.0.44-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:4848395d932e93c1595e59a8672aa7400e8922c39bb9b0668ed99ac6fa867822"}, - {file = "sqlalchemy-2.0.44-cp38-cp38-win32.whl", hash = "sha256:2f19644f27c76f07e10603580a47278abb2a70311136a7f8fd27dc2e096b9013"}, - {file = "sqlalchemy-2.0.44-cp38-cp38-win_amd64.whl", hash = "sha256:1df4763760d1de0dfc8192cc96d8aa293eb1a44f8f7a5fbe74caf1b551905c5e"}, - {file = "sqlalchemy-2.0.44-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f7027414f2b88992877573ab780c19ecb54d3a536bef3397933573d6b5068be4"}, - {file = "sqlalchemy-2.0.44-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3fe166c7d00912e8c10d3a9a0ce105569a31a3d0db1a6e82c4e0f4bf16d5eca9"}, - {file = "sqlalchemy-2.0.44-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3caef1ff89b1caefc28f0368b3bde21a7e3e630c2eddac16abd9e47bd27cc36a"}, - {file = "sqlalchemy-2.0.44-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc2856d24afa44295735e72f3c75d6ee7fdd4336d8d3a8f3d44de7aa6b766df2"}, - {file = "sqlalchemy-2.0.44-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:11bac86b0deada30b6b5f93382712ff0e911fe8d31cb9bf46e6b149ae175eff0"}, - {file = "sqlalchemy-2.0.44-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:4d18cd0e9a0f37c9f4088e50e3839fcb69a380a0ec957408e0b57cff08ee0a26"}, - {file = "sqlalchemy-2.0.44-cp39-cp39-win32.whl", hash = "sha256:9e9018544ab07614d591a26c1bd4293ddf40752cc435caf69196740516af7100"}, - {file = "sqlalchemy-2.0.44-cp39-cp39-win_amd64.whl", hash = "sha256:8e0e4e66fd80f277a8c3de016a81a554e76ccf6b8d881ee0b53200305a8433f6"}, - {file = "sqlalchemy-2.0.44-py3-none-any.whl", hash = "sha256:19de7ca1246fbef9f9d1bff8f1ab25641569df226364a0e40457dc5457c54b05"}, - {file = "sqlalchemy-2.0.44.tar.gz", hash = "sha256:0ae7454e1ab1d780aee69fd2aae7d6b8670a581d8847f2d1e0f7ddfbf47e5a22"}, + {file = "sqlalchemy-2.0.45-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c64772786d9eee72d4d3784c28f0a636af5b0a29f3fe26ff11f55efe90c0bd85"}, + {file = "sqlalchemy-2.0.45-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7ae64ebf7657395824a19bca98ab10eb9a3ecb026bf09524014f1bb81cb598d4"}, + {file = "sqlalchemy-2.0.45-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f02325709d1b1a1489f23a39b318e175a171497374149eae74d612634b234c0"}, + {file = "sqlalchemy-2.0.45-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d2c3684fca8a05f0ac1d9a21c1f4a266983a7ea9180efb80ffeb03861ecd01a0"}, + {file = "sqlalchemy-2.0.45-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:040f6f0545b3b7da6b9317fc3e922c9a98fc7243b2a1b39f78390fc0942f7826"}, + {file = "sqlalchemy-2.0.45-cp310-cp310-win32.whl", hash = "sha256:830d434d609fe7bfa47c425c445a8b37929f140a7a44cdaf77f6d34df3a7296a"}, + {file = "sqlalchemy-2.0.45-cp310-cp310-win_amd64.whl", hash = "sha256:0209d9753671b0da74da2cfbb9ecf9c02f72a759e4b018b3ab35f244c91842c7"}, + {file = "sqlalchemy-2.0.45-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e90a344c644a4fa871eb01809c32096487928bd2038bf10f3e4515cb688cc56"}, + {file = "sqlalchemy-2.0.45-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8c8b41b97fba5f62349aa285654230296829672fc9939cd7f35aab246d1c08b"}, + {file = "sqlalchemy-2.0.45-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:12c694ed6468333a090d2f60950e4250b928f457e4962389553d6ba5fe9951ac"}, + {file = "sqlalchemy-2.0.45-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f7d27a1d977a1cfef38a0e2e1ca86f09c4212666ce34e6ae542f3ed0a33bc606"}, + {file = "sqlalchemy-2.0.45-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d62e47f5d8a50099b17e2bfc1b0c7d7ecd8ba6b46b1507b58cc4f05eefc3bb1c"}, + {file = "sqlalchemy-2.0.45-cp311-cp311-win32.whl", hash = "sha256:3c5f76216e7b85770d5bb5130ddd11ee89f4d52b11783674a662c7dd57018177"}, + {file = "sqlalchemy-2.0.45-cp311-cp311-win_amd64.whl", hash = "sha256:a15b98adb7f277316f2c276c090259129ee4afca783495e212048daf846654b2"}, + {file = "sqlalchemy-2.0.45-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b3ee2aac15169fb0d45822983631466d60b762085bc4535cd39e66bea362df5f"}, + {file = "sqlalchemy-2.0.45-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba547ac0b361ab4f1608afbc8432db669bd0819b3e12e29fb5fa9529a8bba81d"}, + {file = "sqlalchemy-2.0.45-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:215f0528b914e5c75ef2559f69dca86878a3beeb0c1be7279d77f18e8d180ed4"}, + {file = "sqlalchemy-2.0.45-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:107029bf4f43d076d4011f1afb74f7c3e2ea029ec82eb23d8527d5e909e97aa6"}, + {file = "sqlalchemy-2.0.45-cp312-cp312-win32.whl", hash = "sha256:0c9f6ada57b58420a2c0277ff853abe40b9e9449f8d7d231763c6bc30f5c4953"}, + {file = "sqlalchemy-2.0.45-cp312-cp312-win_amd64.whl", hash = "sha256:8defe5737c6d2179c7997242d6473587c3beb52e557f5ef0187277009f73e5e1"}, + {file = "sqlalchemy-2.0.45-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fe187fc31a54d7fd90352f34e8c008cf3ad5d064d08fedd3de2e8df83eb4a1cf"}, + {file = "sqlalchemy-2.0.45-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:672c45cae53ba88e0dad74b9027dddd09ef6f441e927786b05bec75d949fbb2e"}, + {file = "sqlalchemy-2.0.45-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:470daea2c1ce73910f08caf10575676a37159a6d16c4da33d0033546bddebc9b"}, + {file = "sqlalchemy-2.0.45-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9c6378449e0940476577047150fd09e242529b761dc887c9808a9a937fe990c8"}, + {file = "sqlalchemy-2.0.45-cp313-cp313-win32.whl", hash = "sha256:4b6bec67ca45bc166c8729910bd2a87f1c0407ee955df110d78948f5b5827e8a"}, + {file = "sqlalchemy-2.0.45-cp313-cp313-win_amd64.whl", hash = "sha256:afbf47dc4de31fa38fd491f3705cac5307d21d4bb828a4f020ee59af412744ee"}, + {file = "sqlalchemy-2.0.45-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:83d7009f40ce619d483d26ac1b757dfe3167b39921379a8bd1b596cf02dab4a6"}, + {file = "sqlalchemy-2.0.45-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d8a2ca754e5415cde2b656c27900b19d50ba076aa05ce66e2207623d3fe41f5a"}, + {file = "sqlalchemy-2.0.45-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7f46ec744e7f51275582e6a24326e10c49fbdd3fc99103e01376841213028774"}, + {file = "sqlalchemy-2.0.45-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:883c600c345123c033c2f6caca18def08f1f7f4c3ebeb591a63b6fceffc95cce"}, + {file = "sqlalchemy-2.0.45-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2c0b74aa79e2deade948fe8593654c8ef4228c44ba862bb7c9585c8e0db90f33"}, + {file = "sqlalchemy-2.0.45-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8a420169cef179d4c9064365f42d779f1e5895ad26ca0c8b4c0233920973db74"}, + {file = "sqlalchemy-2.0.45-cp314-cp314-win32.whl", hash = "sha256:e50dcb81a5dfe4b7b4a4aa8f338116d127cb209559124f3694c70d6cd072b68f"}, + {file = "sqlalchemy-2.0.45-cp314-cp314-win_amd64.whl", hash = "sha256:4748601c8ea959e37e03d13dcda4a44837afcd1b21338e637f7c935b8da06177"}, + {file = "sqlalchemy-2.0.45-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd337d3526ec5298f67d6a30bbbe4ed7e5e68862f0bf6dd21d289f8d37b7d60b"}, + {file = "sqlalchemy-2.0.45-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9a62b446b7d86a3909abbcd1cd3cc550a832f99c2bc37c5b22e1925438b9367b"}, + {file = "sqlalchemy-2.0.45-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5964f832431b7cdfaaa22a660b4c7eb1dfcd6ed41375f67fd3e3440fd95cb3cc"}, + {file = "sqlalchemy-2.0.45-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee580ab50e748208754ae8980cec79ec205983d8cf8b3f7c39067f3d9f2c8e22"}, + {file = "sqlalchemy-2.0.45-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13e27397a7810163440c6bfed6b3fe46f1bfb2486eb540315a819abd2c004128"}, + {file = "sqlalchemy-2.0.45-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ed3635353e55d28e7f4a95c8eda98a5cdc0a0b40b528433fbd41a9ae88f55b3d"}, + {file = "sqlalchemy-2.0.45-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:db6834900338fb13a9123307f0c2cbb1f890a8656fcd5e5448ae3ad5bbe8d312"}, + {file = "sqlalchemy-2.0.45-cp38-cp38-win32.whl", hash = "sha256:1d8b4a7a8c9b537509d56d5cd10ecdcfbb95912d72480c8861524efecc6a3fff"}, + {file = "sqlalchemy-2.0.45-cp38-cp38-win_amd64.whl", hash = "sha256:ebd300afd2b62679203435f596b2601adafe546cb7282d5a0cd3ed99e423720f"}, + {file = "sqlalchemy-2.0.45-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d29b2b99d527dbc66dd87c3c3248a5dd789d974a507f4653c969999fc7c1191b"}, + {file = "sqlalchemy-2.0.45-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:59a8b8bd9c6bedf81ad07c8bd5543eedca55fe9b8780b2b628d495ba55f8db1e"}, + {file = "sqlalchemy-2.0.45-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd93c6f5d65f254ceabe97548c709e073d6da9883343adaa51bf1a913ce93f8e"}, + {file = "sqlalchemy-2.0.45-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6d0beadc2535157070c9c17ecf25ecec31e13c229a8f69196d7590bde8082bf1"}, + {file = "sqlalchemy-2.0.45-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e057f928ffe9c9b246a55b469c133b98a426297e1772ad24ce9f0c47d123bd5b"}, + {file = "sqlalchemy-2.0.45-cp39-cp39-win32.whl", hash = "sha256:c1c2091b1489435ff85728fafeb990f073e64f6f5e81d5cd53059773e8521eb6"}, + {file = "sqlalchemy-2.0.45-cp39-cp39-win_amd64.whl", hash = "sha256:56ead1f8dfb91a54a28cd1d072c74b3d635bcffbd25e50786533b822d4f2cde2"}, + {file = "sqlalchemy-2.0.45-py3-none-any.whl", hash = "sha256:5225a288e4c8cc2308dbdd874edad6e7d0fd38eac1e9e5f23503425c8eee20d0"}, + {file = "sqlalchemy-2.0.45.tar.gz", hash = "sha256:1632a4bda8d2d25703fdad6363058d882541bdaaee0e5e3ddfa0cd3229efce88"}, ] [package.dependencies] @@ -7272,38 +7588,39 @@ sqlcipher = ["sqlcipher3_binary"] [[package]] name = "sqlparse" -version = "0.5.3" +version = "0.5.5" description = "A non-validating SQL parser." optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "sqlparse-0.5.3-py3-none-any.whl", hash = "sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca"}, - {file = "sqlparse-0.5.3.tar.gz", hash = "sha256:09f67787f56a0b16ecdbde1bfc7f5d9c3371ca683cfeaa8e6ff60b4807ec9272"}, + {file = "sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba"}, + {file = "sqlparse-0.5.5.tar.gz", hash = "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e"}, ] [package.extras] -dev = ["build", "hatch"] +dev = ["build"] doc = ["sphinx"] [[package]] name = "sse-starlette" -version = "3.0.3" +version = "3.1.1" description = "SSE plugin for Starlette" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "sse_starlette-3.0.3-py3-none-any.whl", hash = "sha256:af5bf5a6f3933df1d9c7f8539633dc8444ca6a97ab2e2a7cd3b6e431ac03a431"}, - {file = "sse_starlette-3.0.3.tar.gz", hash = "sha256:88cfb08747e16200ea990c8ca876b03910a23b547ab3bd764c0d8eb81019b971"}, + {file = "sse_starlette-3.1.1-py3-none-any.whl", hash = "sha256:bb38f71ae74cfd86b529907a9fda5632195dfa6ae120f214ea4c890c7ee9d436"}, + {file = "sse_starlette-3.1.1.tar.gz", hash = "sha256:bffa531420c1793ab224f63648c059bcadc412bf9fdb1301ac8de1cf9a67b7fb"}, ] [package.dependencies] anyio = ">=4.7.0" +starlette = ">=0.49.1" [package.extras] daphne = ["daphne (>=4.2.0)"] -examples = ["aiosqlite (>=0.21.0)", "fastapi (>=0.115.12)", "sqlalchemy[asyncio] (>=2.0.41)", "starlette (>=0.49.1)", "uvicorn (>=0.34.0)"] +examples = ["aiosqlite (>=0.21.0)", "fastapi (>=0.115.12)", "sqlalchemy[asyncio] (>=2.0.41)", "uvicorn (>=0.34.0)"] granian = ["granian (>=2.3.1)"] uvicorn = ["uvicorn (>=0.34.0)"] @@ -7636,42 +7953,60 @@ test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0, [[package]] name = "ty" -version = "0.0.1a28" +version = "0.0.1a35" description = "An extremely fast Python type checker, written in Rust." optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "ty-0.0.1a28-py3-none-linux_armv6l.whl", hash = "sha256:0ea28aaaf35176a75ce85da7a4b7f577f3a3319a1eb4d13c0105629e239a7d95"}, - {file = "ty-0.0.1a28-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:463f8b6bee5c3d338a535c40764a4f209f5465caecbc9f7358ee2a7f8b2d321e"}, - {file = "ty-0.0.1a28-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7d037ea9f896e6e9b96ca066959e2a7600db0da9e4038f1247c9337af253cc8c"}, - {file = "ty-0.0.1a28-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad5099ffaa891391733d6fd85bcdd00ad68042a2da4f80a114b9e7044e6f7460"}, - {file = "ty-0.0.1a28-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:587652aecb8d238adcb45ae7cd12efd27b9778f74b636cbbe5dcc2e938f9af4e"}, - {file = "ty-0.0.1a28-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d9556c87419264ffc3071a249f89d890a29df5d09abd8d216bac850ad2d7ba9"}, - {file = "ty-0.0.1a28-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7481abc03a0aabf966c9e1cccb18c9edbb7cf01ec011568cd24feb1ab45faef7"}, - {file = "ty-0.0.1a28-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76fd4926f668b733aeadd09f7d16e63af30cba5438bbba1274f950a1059c8d64"}, - {file = "ty-0.0.1a28-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8fb119d7db1a064dd74ccedf78bdc5caae30cf5de421dff972a849bcff411269"}, - {file = "ty-0.0.1a28-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd7f7d744920af9ceaf7fe6db290366abefbcffd7cce54f15e8cef6a86e2df31"}, - {file = "ty-0.0.1a28-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c20c6cf7e786ecf6c8f34892240b4b1ae8b1adce52243868aa400c80b7a9bc1d"}, - {file = "ty-0.0.1a28-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:54c94a06c0236dfd249217e28816b6aedfc40e71d5b5131924efa3b095dfcf1a"}, - {file = "ty-0.0.1a28-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1a15eb2535229ab65aaafbe3fb22c3d289c4e34cda92fb748815573b6d52fe3a"}, - {file = "ty-0.0.1a28-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:6c2ebd5314707cd26aabe77b1d664e597b7b29a8d07fed5091f986ebdaa261a9"}, - {file = "ty-0.0.1a28-py3-none-win32.whl", hash = "sha256:ae10abd8575d28744d905979632040222581ba364281abf75baf8f269a10ffc3"}, - {file = "ty-0.0.1a28-py3-none-win_amd64.whl", hash = "sha256:44ef82c1169c050ad9e91b2d76251be097ddd163719735cf7e5a978065f6b87c"}, - {file = "ty-0.0.1a28-py3-none-win_arm64.whl", hash = "sha256:051c1d43df50366fb8e795ae52af8f2015b79d176dbb82cdd45668074847ddf3"}, - {file = "ty-0.0.1a28.tar.gz", hash = "sha256:6454f2bc0d5b716aeaba3e32c4585a14a0d6bfc7e90d5aba64539fa33df824c4"}, + {file = "ty-0.0.1a35-py3-none-linux_armv6l.whl", hash = "sha256:70dde7bcf9ccf56be0708d1a399c5b796c38f38726dddbc61d5d64d84f83af6b"}, + {file = "ty-0.0.1a35-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:56a4f81fa980565abe692af82266c1c348bd4eaf4205bff4fcb5bb6ec0a211f4"}, + {file = "ty-0.0.1a35-py3-none-macosx_11_0_arm64.whl", hash = "sha256:144ab0ca5d0552b4248ae31a7ca89f434d5f16df29bcc95100bef1fdec892b95"}, + {file = "ty-0.0.1a35-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6db9a9e252ca73b4bae063ae3bac9e0723557aff6298f96ad1696a985b3e623f"}, + {file = "ty-0.0.1a35-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:081955635f12233433f74eff51acb2f5380ed23091c9c72d09d02494073c9d4f"}, + {file = "ty-0.0.1a35-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4f59fa2dc7dc4e8f0c9135738670c6691072de0b5b11582c9ca55895f8b92c9"}, + {file = "ty-0.0.1a35-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:48e466329c16f0dc4d60b54539bb3e50983516f7024e7e260d50f4b4bbbd4c3e"}, + {file = "ty-0.0.1a35-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:87ca20fe7f05dd7335f863cfcff4d51d611816b413be6d14e20c146e4e522471"}, + {file = "ty-0.0.1a35-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:188c8e2d7f3767d20dcd44b38cc585a0ab4fcee2ebcdb1d4442ca588dbc8c688"}, + {file = "ty-0.0.1a35-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5dba3072078486e4e5ffebe83ac2e2199053fabddecbf5b8b9736021a8258556"}, + {file = "ty-0.0.1a35-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b9bdef2a44fc1e8e40531bd714f9ec4f208dd13474f307547c0a93055dbaeccc"}, + {file = "ty-0.0.1a35-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:c4d1ed3b9c954ddb258ece43c84bb2dafd569bad3f437467b594de535caf3bde"}, + {file = "ty-0.0.1a35-py3-none-musllinux_1_2_i686.whl", hash = "sha256:ae9e28d2d549faac040b6b8acd9338b7acebbd7185e89af30b01bb115d68ddd4"}, + {file = "ty-0.0.1a35-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:0cb5f1084023d5bef5afa510db3a5052d4d18160e1708d3c5bf5a23f1d59a792"}, + {file = "ty-0.0.1a35-py3-none-win32.whl", hash = "sha256:11e3ee5df2a26fd6d0764cf425ac538a225fc077a694ba2c0f4a0fa78b760c07"}, + {file = "ty-0.0.1a35-py3-none-win_amd64.whl", hash = "sha256:9448a12b34f377eb841141908bfd74861404d25c21d8c934e67415a3655c952b"}, + {file = "ty-0.0.1a35-py3-none-win_arm64.whl", hash = "sha256:78fbb25e4a516568c993a2e12024285248ac091ad24a5b2f41cc815b8c65935e"}, + {file = "ty-0.0.1a35.tar.gz", hash = "sha256:b122986b36a7e7482943312026948e67670f8f252bdf1afa5378b1a59372c25e"}, +] + +[[package]] +name = "typer" +version = "0.21.0" +description = "Typer, build great CLIs. Easy to code. Based on Python type hints." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "typer-0.21.0-py3-none-any.whl", hash = "sha256:c79c01ca6b30af9fd48284058a7056ba0d3bf5cf10d0ff3d0c5b11b68c258ac6"}, + {file = "typer-0.21.0.tar.gz", hash = "sha256:c87c0d2b6eee3b49c5c64649ec92425492c14488096dfbc8a0c2799b2f6f9c53"}, ] +[package.dependencies] +click = ">=8.0.0" +rich = ">=10.11.0" +shellingham = ">=1.3.0" +typing-extensions = ">=3.7.4.3" + [[package]] name = "typer-slim" -version = "0.20.0" +version = "0.21.0" description = "Typer, build great CLIs. Easy to code. Based on Python type hints." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "typer_slim-0.20.0-py3-none-any.whl", hash = "sha256:f42a9b7571a12b97dddf364745d29f12221865acef7a2680065f9bb29c7dc89d"}, - {file = "typer_slim-0.20.0.tar.gz", hash = "sha256:9fc6607b3c6c20f5c33ea9590cbeb17848667c51feee27d9e314a579ab07d1a3"}, + {file = "typer_slim-0.21.0-py3-none-any.whl", hash = "sha256:92aee2188ac6fc2b2924bd75bb61a340b78bd8cd51fd9735533ce5a856812c8e"}, + {file = "typer_slim-0.21.0.tar.gz", hash = "sha256:f2dbd150cfa0fead2242e21fa9f654dfc64773763ddf07c6be9a49ad34f79557"}, ] [package.dependencies] @@ -7683,14 +8018,14 @@ standard = ["rich (>=10.11.0)", "shellingham (>=1.3.0)"] [[package]] name = "types-protobuf" -version = "6.32.1.20251105" +version = "6.32.1.20251210" description = "Typing stubs for protobuf" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "types_protobuf-6.32.1.20251105-py3-none-any.whl", hash = "sha256:a15109d38f7cfefd2539ef86d3f93a6a41c7cad53924f8aa1a51eaddbb72a660"}, - {file = "types_protobuf-6.32.1.20251105.tar.gz", hash = "sha256:641002611ff87dd9fedc38a39a29cacb9907ae5ce61489b53e99ca2074bef764"}, + {file = "types_protobuf-6.32.1.20251210-py3-none-any.whl", hash = "sha256:2641f78f3696822a048cfb8d0ff42ccd85c25f12f871fbebe86da63793692140"}, + {file = "types_protobuf-6.32.1.20251210.tar.gz", hash = "sha256:c698bb3f020274b1a2798ae09dc773728ce3f75209a35187bd11916ebfde6763"}, ] [[package]] @@ -7754,14 +8089,14 @@ typing-extensions = ">=4.12.0" [[package]] name = "tzdata" -version = "2025.2" +version = "2025.3" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" groups = ["main"] files = [ - {file = "tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8"}, - {file = "tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9"}, + {file = "tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1"}, + {file = "tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7"}, ] [[package]] @@ -7822,14 +8157,14 @@ xlsx = ["msoffcrypto-tool", "networkx", "openpyxl", "pandas", "xlrd"] [[package]] name = "unstructured-client" -version = "0.42.4" +version = "0.42.6" description = "Python Client SDK for Unstructured API" optional = false python-versions = ">=3.9.2" groups = ["main"] files = [ - {file = "unstructured_client-0.42.4-py3-none-any.whl", hash = "sha256:fc6341344dd2f2e2aed793636b5f4e6204cad741ff2253d5a48ff2f2bccb8e9a"}, - {file = "unstructured_client-0.42.4.tar.gz", hash = "sha256:144ecd231a11d091cdc76acf50e79e57889269b8c9d8b9df60e74cf32ac1ba5e"}, + {file = "unstructured_client-0.42.6-py3-none-any.whl", hash = "sha256:c93b1d9d1b9f63a8e961729d00224b3659ef9ef3e14996ea4e53ddc95df671a9"}, + {file = "unstructured_client-0.42.6.tar.gz", hash = "sha256:ea54f2c4ca3e7a1330f9e77cbc96f88f829518beeec5e1b797b5352f4d76a73a"}, ] [package.dependencies] @@ -7843,32 +8178,64 @@ requests-toolbelt = ">=1.0.0" [[package]] name = "urllib3" -version = "2.5.0" +version = "2.6.2" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"}, - {file = "urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760"}, + {file = "urllib3-2.6.2-py3-none-any.whl", hash = "sha256:ec21cddfe7724fc7cb4ba4bea7aa8e2ef36f607a4bab81aa6ce42a13dc3f03dd"}, + {file = "urllib3-2.6.2.tar.gz", hash = "sha256:016f9c98bb7e98085cb2b4b17b87d2c702975664e4f060c6532e64d1c1a5e797"}, ] [package.extras] -brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] +brotli = ["brotli (>=1.2.0) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=1.2.0.0) ; platform_python_implementation != \"CPython\""] h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["zstandard (>=0.18.0)"] +zstd = ["backports-zstd (>=1.0.0) ; python_version < \"3.14\""] + +[[package]] +name = "uuid-utils" +version = "0.12.0" +description = "Drop-in replacement for Python UUID with bindings in Rust" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "uuid_utils-0.12.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:3b9b30707659292f207b98f294b0e081f6d77e1fbc760ba5b41331a39045f514"}, + {file = "uuid_utils-0.12.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:add3d820c7ec14ed37317375bea30249699c5d08ff4ae4dbee9fc9bce3bfbf65"}, + {file = "uuid_utils-0.12.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b8fce83ecb3b16af29c7809669056c4b6e7cc912cab8c6d07361645de12dd79"}, + {file = "uuid_utils-0.12.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ec921769afcb905035d785582b0791d02304a7850fbd6ce924c1a8976380dfc6"}, + {file = "uuid_utils-0.12.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f3b060330f5899a92d5c723547dc6a95adef42433e9748f14c66859a7396664"}, + {file = "uuid_utils-0.12.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:908dfef7f0bfcf98d406e5dc570c25d2f2473e49b376de41792b6e96c1d5d291"}, + {file = "uuid_utils-0.12.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4c6a24148926bd0ca63e8a2dabf4cc9dc329a62325b3ad6578ecd60fbf926506"}, + {file = "uuid_utils-0.12.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:64a91e632669f059ef605f1771d28490b1d310c26198e46f754e8846dddf12f4"}, + {file = "uuid_utils-0.12.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:93c082212470bb4603ca3975916c205a9d7ef1443c0acde8fbd1e0f5b36673c7"}, + {file = "uuid_utils-0.12.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:431b1fb7283ba974811b22abd365f2726f8f821ab33f0f715be389640e18d039"}, + {file = "uuid_utils-0.12.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2ffd7838c40149100299fa37cbd8bab5ee382372e8e65a148002a37d380df7c8"}, + {file = "uuid_utils-0.12.0-cp39-abi3-win32.whl", hash = "sha256:487f17c0fee6cbc1d8b90fe811874174a9b1b5683bf2251549e302906a50fed3"}, + {file = "uuid_utils-0.12.0-cp39-abi3-win_amd64.whl", hash = "sha256:9598e7c9da40357ae8fffc5d6938b1a7017f09a1acbcc95e14af8c65d48c655a"}, + {file = "uuid_utils-0.12.0-cp39-abi3-win_arm64.whl", hash = "sha256:c9bea7c5b2aa6f57937ebebeee4d4ef2baad10f86f1b97b58a3f6f34c14b4e84"}, + {file = "uuid_utils-0.12.0-pp311-pypy311_pp73-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e2209d361f2996966ab7114f49919eb6aaeabc6041672abbbbf4fdbb8ec1acc0"}, + {file = "uuid_utils-0.12.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d9636bcdbd6cfcad2b549c352b669412d0d1eb09be72044a2f13e498974863cd"}, + {file = "uuid_utils-0.12.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8cd8543a3419251fb78e703ce3b15fdfafe1b7c542cf40caf0775e01db7e7674"}, + {file = "uuid_utils-0.12.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e98db2d8977c052cb307ae1cb5cc37a21715e8d415dbc65863b039397495a013"}, + {file = "uuid_utils-0.12.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8f2bdf5e4ffeb259ef6d15edae92aed60a1d6f07cbfab465d836f6b12b48da8"}, + {file = "uuid_utils-0.12.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c3ec53c0cb15e1835870c139317cc5ec06e35aa22843e3ed7d9c74f23f23898"}, + {file = "uuid_utils-0.12.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:84e5c0eba209356f7f389946a3a47b2cc2effd711b3fc7c7f155ad9f7d45e8a3"}, + {file = "uuid_utils-0.12.0.tar.gz", hash = "sha256:252bd3d311b5d6b7f5dfce7a5857e27bb4458f222586bb439463231e5a9cbd64"}, +] [[package]] name = "uvicorn" -version = "0.38.0" +version = "0.40.0" description = "The lightning-fast ASGI server." optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["main"] files = [ - {file = "uvicorn-0.38.0-py3-none-any.whl", hash = "sha256:48c0afd214ceb59340075b4a052ea1ee91c16fbc2a9b1469cca0e54566977b02"}, - {file = "uvicorn-0.38.0.tar.gz", hash = "sha256:fd97093bdd120a2609fc0d3afe931d4d4ad688b6e75f0f929fde1bc36fe0e91d"}, + {file = "uvicorn-0.40.0-py3-none-any.whl", hash = "sha256:c6c8f55bc8bf13eb6fa9ff87ad62308bbbc33d0b67f84293151efe87e0d5f2ee"}, + {file = "uvicorn-0.40.0.tar.gz", hash = "sha256:839676675e87e73694518b5574fd0f24c9d97b46bea16df7b8c05ea1a51071ea"}, ] [package.dependencies] @@ -8604,4 +8971,4 @@ cffi = ["cffi (>=1.17,<2.0) ; platform_python_implementation != \"PyPy\" and pyt [metadata] lock-version = "2.1" python-versions = "^3.11" -content-hash = "a53642bd3db034d6eb6f352814ce931b199e7912e418fbc8a5e1016a2b4c998c" +content-hash = "0d56df14efce74c0a81cde9325cf08237e7aea2c1e17ae89ab2027e4fc04e537" diff --git a/pyproject.toml b/pyproject.toml index 6bea657..5d93703 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,6 +42,7 @@ replicate = "^1.0.7" pgvector = "^0.4.1" gpt-researcher = "^0.14.5" pillow = "^12.0.0" +exa-py = "^2.0.2" [tool.poetry.group.dev.dependencies] pre-commit = "^3.2.1" diff --git a/requirements.txt b/requirements.txt index 3ba9987..2e6aeb7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ aiosignal==1.4.0 ; python_version >= "3.11" and python_version < "4.0" annotated-doc==0.0.4 ; python_version >= "3.11" and python_version < "4.0" annotated-types==0.7.0 ; python_version >= "3.11" and python_version < "4.0" anthropic==0.75.0 ; python_version >= "3.11" and python_version < "4.0" -anyio==4.11.0 ; python_version >= "3.11" and python_version < "4.0" +anyio==4.12.0 ; python_version >= "3.11" and python_version < "4.0" argcomplete==3.6.3 ; python_version >= "3.11" and python_version < "4.0" arrow==1.4.0 ; python_version >= "3.11" and python_version < "4.0" arxiv==2.3.1 ; python_version >= "3.11" and python_version < "4.0" @@ -14,28 +14,29 @@ asgiref==3.11.0 ; python_version >= "3.11" and python_version < "4.0" asttokens==3.0.1 ; python_version >= "3.11" and python_version < "4.0" async-timeout==5.0.1 ; python_version >= "3.11" and python_full_version < "3.11.3" attrs==25.4.0 ; python_version >= "3.11" and python_version < "4.0" -authlib==1.6.5 ; python_version >= "3.11" and python_version < "4.0" +authlib==1.6.6 ; python_version >= "3.11" and python_version < "4.0" backoff==2.2.1 ; python_version >= "3.11" and python_version < "4.0" backports-tarfile==1.2.0 ; python_version == "3.11" -beartype==0.22.6 ; python_version >= "3.11" and python_version < "4.0" -beautifulsoup4==4.14.2 ; python_version >= "3.11" and python_version < "4.0" +beartype==0.22.9 ; python_version >= "3.11" and python_version < "4.0" +beautifulsoup4==4.14.3 ; python_version >= "3.11" and python_version < "4.0" binaryornot==0.4.4 ; python_version >= "3.11" and python_version < "4.0" -boto3==1.41.5 ; python_version >= "3.11" and python_version < "4.0" -botocore==1.41.5 ; python_version >= "3.11" and python_version < "4.0" +boto3==1.42.16 ; python_version >= "3.11" and python_version < "4.0" +botocore==1.42.16 ; python_version >= "3.11" and python_version < "4.0" brotli==1.2.0 ; python_version >= "3.11" and python_version < "4.0" brotlicffi==1.2.0.0 ; python_version >= "3.11" and python_version < "4.0" and platform_python_implementation != "CPython" -cachetools==6.2.2 ; python_version >= "3.11" and python_version < "4.0" +cachetools==6.2.4 ; python_version >= "3.11" and python_version < "4.0" certifi==2025.11.12 ; python_version >= "3.11" and python_version < "4.0" cffi==2.0.0 ; python_version >= "3.11" and python_version < "4.0" chardet==5.2.0 ; python_version >= "3.11" and python_version < "4.0" charset-normalizer==3.4.4 ; python_version >= "3.11" and python_version < "4.0" click==8.3.1 ; python_version >= "3.11" and python_version < "4.0" -cohere==5.20.0 ; python_version >= "3.11" and python_version < "4.0" and platform_system != "Emscripten" +cloudpickle==3.1.2 ; python_version >= "3.11" and python_version < "4.0" +cohere==5.20.1 ; python_version >= "3.11" and python_version < "4.0" and platform_system != "Emscripten" colorama==0.4.6 ; python_version >= "3.11" and python_version < "4.0" cookiecutter==2.6.0 ; python_version >= "3.11" and python_version < "4.0" cryptography==46.0.3 ; python_version >= "3.11" and python_version < "4.0" cssselect2==0.8.0 ; python_version >= "3.11" and python_version < "4.0" -cyclopts==4.3.0 ; python_version >= "3.11" and python_version < "4.0" +cyclopts==4.4.1 ; python_version >= "3.11" and python_version < "4.0" dataclasses-json==0.6.7 ; python_version >= "3.11" and python_version < "4.0" decorator==5.2.1 ; python_version >= "3.11" and python_version < "4.0" diskcache==5.6.3 ; python_version >= "3.11" and python_version < "4.0" @@ -46,69 +47,72 @@ django-anymail==12.0 ; python_version >= "3.11" and python_version < "4.0" django-environ==0.11.2 ; python_version >= "3.11" and python_version < "4.0" django-extensions==3.2.3 ; python_version >= "3.11" and python_version < "4.0" django-ipware==7.0.1 ; python_version >= "3.11" and python_version < "4.0" -django-mjml==1.4 ; python_version >= "3.11" and python_version < "4.0" -django-ninja==1.5.0 ; python_version >= "3.11" and python_version < "4.0" +django-mjml==1.5 ; python_version >= "3.11" and python_version < "4.0" +django-ninja==1.5.1 ; python_version >= "3.11" and python_version < "4.0" django-picklefield==3.4.0 ; python_version >= "3.11" and python_version < "4.0" django-q-sentry==0.1.6 ; python_version >= "3.11" and python_version < "4.0" -django-q2==1.8.0 ; python_version >= "3.11" and python_version < "4.0" +django-q2==1.9.0 ; python_version >= "3.11" and python_version < "4.0" django-storages==1.14.6 ; python_version >= "3.11" and python_version < "4.0" django-structlog==8.1.0 ; python_version >= "3.11" and python_version < "4.0" django-widget-tweaks==1.5.0 ; python_version >= "3.11" and python_version < "4.0" -django==5.2.8 ; python_version >= "3.11" and python_version < "4.0" +django==5.2.9 ; python_version >= "3.11" and python_version < "4.0" dnspython==2.8.0 ; python_version >= "3.11" and python_version < "4.0" docopt==0.6.2 ; python_version >= "3.11" and python_version < "4.0" docstring-parser==0.17.0 ; python_version >= "3.11" and python_version < "4.0" -docutils==0.22.3 ; python_version >= "3.11" and python_version < "4.0" +docutils==0.22.4 ; python_version >= "3.11" and python_version < "4.0" duckduckgo-search==8.1.1 ; python_version >= "3.11" and python_version < "4.0" email-validator==2.3.0 ; python_version >= "3.11" and python_version < "4.0" emoji==2.15.0 ; python_version >= "3.11" and python_version < "4.0" -eval-type-backport==0.3.0 ; python_version >= "3.11" and python_version < "4.0" +eval-type-backport==0.3.1 ; python_version >= "3.11" and python_version < "4.0" +exa-py==2.0.2 ; python_version >= "3.11" and python_version < "4.0" exceptiongroup==1.3.1 ; python_version >= "3.11" and python_version < "4.0" executing==2.2.1 ; python_version >= "3.11" and python_version < "4.0" -fastapi==0.122.0 ; python_version >= "3.11" and python_version < "4.0" +fakeredis==2.33.0 ; python_version >= "3.11" and python_version < "4.0" +fastapi==0.127.1 ; python_version >= "3.11" and python_version < "4.0" fastavro==1.12.1 ; python_version >= "3.11" and python_version < "4.0" and platform_system != "Emscripten" -fastmcp==2.13.1 ; python_version >= "3.11" and python_version < "4.0" +fastmcp==2.14.0 ; python_version >= "3.11" and python_version < "4.0" fastuuid==0.14.0 ; python_version >= "3.11" and python_version < "4.0" feedparser==6.0.12 ; python_version >= "3.11" and python_version < "4.0" -filelock==3.20.0 ; python_version >= "3.11" and python_version < "4.0" +filelock==3.20.1 ; python_version >= "3.11" and python_version < "4.0" filetype==1.2.0 ; python_version >= "3.11" and python_version < "4.0" -fonttools==4.60.1 ; python_version >= "3.11" and python_version < "4.0" +fonttools==4.61.1 ; python_version >= "3.11" and python_version < "4.0" frozenlist==1.8.0 ; python_version >= "3.11" and python_version < "4.0" -fsspec==2025.10.0 ; python_version >= "3.11" and python_version < "4.0" -genai-prices==0.0.47 ; python_version >= "3.11" and python_version < "4.0" -google-auth==2.43.0 ; python_version >= "3.11" and python_version < "4.0" -google-genai==1.52.0 ; python_version >= "3.11" and python_version < "4.0" +fsspec==2025.12.0 ; python_version >= "3.11" and python_version < "4.0" +genai-prices==0.0.49 ; python_version >= "3.11" and python_version < "4.0" +google-auth==2.45.0 ; python_version >= "3.11" and python_version < "4.0" +google-genai==1.56.0 ; python_version >= "3.11" and python_version < "4.0" googleapis-common-protos==1.72.0 ; python_version >= "3.11" and python_version < "4.0" gpt-researcher==0.14.5 ; python_version >= "3.11" and python_version < "4.0" -greenlet==3.2.4 ; python_version >= "3.11" and python_version < "4.0" +greenlet==3.3.0 ; python_version >= "3.11" and python_version < "4.0" griffe==1.15.0 ; python_version >= "3.11" and python_version < "4.0" -groq==0.36.0 ; python_version >= "3.11" and python_version < "4.0" -grpcio==1.67.1 ; python_version >= "3.11" and python_version < "4.0" +groq==1.0.0 ; python_version >= "3.11" and python_version < "4.0" +grpcio==1.67.1 ; python_version >= "3.11" and python_version <= "3.13" +grpcio==1.76.0 ; python_version >= "3.14" and python_version < "4.0" gunicorn==23.0.0 ; python_version >= "3.11" and python_version < "4.0" h11==0.16.0 ; python_version >= "3.11" and python_version < "4.0" hf-xet==1.2.0 ; python_version >= "3.11" and python_version < "4.0" and (platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "arm64" or platform_machine == "aarch64") html5lib==1.1 ; python_version >= "3.11" and python_version < "4.0" htmldocx==0.0.6 ; python_version >= "3.11" and python_version < "4.0" httpcore==1.0.9 ; python_version >= "3.11" and python_version < "4.0" -httpx-aiohttp==0.1.9 ; python_version >= "3.11" and python_version < "4.0" -httpx-sse==0.4.0 ; python_version >= "3.11" and python_version < "4.0" +httpx-aiohttp==0.1.12 ; python_version >= "3.11" and python_version < "4.0" +httpx-sse==0.4.3 ; python_version >= "3.11" and python_version < "4.0" httpx==0.28.1 ; python_version >= "3.11" and python_version < "4.0" -huggingface-hub==1.1.5 ; python_version >= "3.11" and python_version < "4.0" +huggingface-hub==1.2.3 ; python_version >= "3.11" and python_version < "4.0" idna==3.11 ; python_version >= "3.11" and python_version < "4.0" -importlib-metadata==8.7.0 ; python_version >= "3.11" and python_version < "4.0" +importlib-metadata==8.7.1 ; python_version >= "3.11" and python_version < "4.0" iniconfig==2.3.0 ; python_version >= "3.11" and python_version < "4.0" invoke==2.2.1 ; python_version >= "3.11" and python_version < "4.0" ipython==8.37.0 ; python_version >= "3.11" and python_version < "4.0" jaraco-classes==3.4.0 ; python_version >= "3.11" and python_version < "4.0" -jaraco-context==6.0.1 ; python_version >= "3.11" and python_version < "4.0" -jaraco-functools==4.3.0 ; python_version >= "3.11" and python_version < "4.0" +jaraco-context==6.0.2 ; python_version >= "3.11" and python_version < "4.0" +jaraco-functools==4.4.0 ; python_version >= "3.11" and python_version < "4.0" jedi==0.19.2 ; python_version >= "3.11" and python_version < "4.0" jeepney==0.9.0 ; python_version >= "3.11" and python_version < "4.0" and sys_platform == "linux" jinja2==3.1.6 ; python_version >= "3.11" and python_version < "4.0" jiter==0.12.0 ; python_version >= "3.11" and python_version < "4.0" jmespath==1.0.1 ; python_version >= "3.11" and python_version < "4.0" -joblib==1.5.2 ; python_version >= "3.11" and python_version < "4.0" -json-repair==0.54.2 ; python_version >= "3.11" and python_version < "4.0" +joblib==1.5.3 ; python_version >= "3.11" and python_version < "4.0" +json-repair==0.54.3 ; python_version >= "3.11" and python_version < "4.0" json5==0.12.1 ; python_version >= "3.11" and python_version < "4.0" jsonpatch==1.33 ; python_version >= "3.11" and python_version < "4.0" jsonpointer==3.0.0 ; python_version >= "3.11" and python_version < "4.0" @@ -117,36 +121,37 @@ jsonschema-specifications==2025.9.1 ; python_version >= "3.11" and python_versio jsonschema==4.25.1 ; python_version >= "3.11" and python_version < "4.0" keyring==25.7.0 ; python_version >= "3.11" and python_version < "4.0" kiwisolver==1.4.9 ; python_version >= "3.11" and python_version < "4.0" -langchain-classic==1.0.0 ; python_version >= "3.11" and python_version < "4.0" +langchain-classic==1.0.1 ; python_version >= "3.11" and python_version < "4.0" langchain-community==0.4.1 ; python_version >= "3.11" and python_version < "4.0" -langchain-core==1.1.0 ; python_version >= "3.11" and python_version < "4.0" -langchain-ollama==1.0.0 ; python_version >= "3.11" and python_version < "4.0" -langchain-openai==1.1.0 ; python_version >= "3.11" and python_version < "4.0" -langchain-text-splitters==1.0.0 ; python_version >= "3.11" and python_version < "4.0" -langchain==1.1.0 ; python_version >= "3.11" and python_version < "4.0" +langchain-core==1.2.5 ; python_version >= "3.11" and python_version < "4.0" +langchain-ollama==1.0.1 ; python_version >= "3.11" and python_version < "4.0" +langchain-openai==1.1.6 ; python_version >= "3.11" and python_version < "4.0" +langchain-text-splitters==1.1.0 ; python_version >= "3.11" and python_version < "4.0" +langchain==1.2.0 ; python_version >= "3.11" and python_version < "4.0" langdetect==1.0.9 ; python_version >= "3.11" and python_version < "4.0" langgraph-checkpoint==3.0.1 ; python_version >= "3.11" and python_version < "4.0" -langgraph-cli==0.4.7 ; python_version >= "3.11" and python_version < "4.0" +langgraph-cli==0.4.11 ; python_version >= "3.11" and python_version < "4.0" langgraph-prebuilt==1.0.5 ; python_version >= "3.11" and python_version < "4.0" -langgraph-sdk==0.2.10 ; python_version >= "3.11" and python_version < "4.0" -langgraph==1.0.4 ; python_version >= "3.11" and python_version < "4.0" -langsmith==0.4.49 ; python_version >= "3.11" and python_version < "4.0" -litellm==1.80.7 ; python_version >= "3.11" and python_version < "4.0" -logfire-api==4.15.1 ; python_version >= "3.11" and python_version < "4.0" +langgraph-sdk==0.3.1 ; python_version >= "3.11" and python_version < "4.0" +langgraph==1.0.5 ; python_version >= "3.11" and python_version < "4.0" +langsmith==0.5.1 ; python_version >= "3.11" and python_version < "4.0" +litellm==1.80.11 ; python_version >= "3.11" and python_version < "4.0" +logfire-api==4.16.0 ; python_version >= "3.11" and python_version < "4.0" logfire==3.25.0 ; python_version >= "3.11" and python_version < "4.0" loguru==0.7.3 ; python_version >= "3.11" and python_version < "4.0" +lupa==2.6 ; python_version >= "3.11" and python_version < "4.0" lxml==6.0.2 ; python_version >= "3.11" and python_version < "4.0" markdown-it-py==4.0.0 ; python_version >= "3.11" and python_version < "4.0" markdown2==2.5.4 ; python_version >= "3.11" and python_version < "4.0" markdown==3.10 ; python_version >= "3.11" and python_version < "4.0" markupsafe==3.0.3 ; python_version >= "3.11" and python_version < "4.0" -marshmallow==3.26.1 ; python_version >= "3.11" and python_version < "4.0" +marshmallow==3.26.2 ; python_version >= "3.11" and python_version < "4.0" matplotlib-inline==0.2.1 ; python_version >= "3.11" and python_version < "4.0" -mcp==1.22.0 ; python_version >= "3.11" and python_version < "4.0" +mcp==1.25.0 ; python_version >= "3.11" and python_version < "4.0" md2pdf==1.0.1 ; python_version >= "3.11" and python_version < "4.0" mdurl==0.1.2 ; python_version >= "3.11" and python_version < "4.0" mistralai==1.9.11 ; python_version >= "3.11" and python_version < "4.0" -mistune==3.1.4 ; python_version >= "3.11" and python_version < "4.0" +mistune==3.2.0 ; python_version >= "3.11" and python_version < "4.0" more-itertools==10.8.0 ; python_version >= "3.11" and python_version < "4.0" multidict==6.7.0 ; python_version >= "3.11" and python_version < "4.0" mypy-extensions==1.1.0 ; python_version >= "3.11" and python_version < "4.0" @@ -157,39 +162,41 @@ numpy==2.2.6 ; python_version >= "3.11" and python_version < "4.0" oauthlib==3.3.1 ; python_version >= "3.11" and python_version < "4.0" olefile==0.47 ; python_version >= "3.11" and python_version < "4.0" ollama==0.6.1 ; python_version >= "3.11" and python_version < "4.0" -openai==2.8.1 ; python_version >= "3.11" and python_version < "4.0" +openai==2.14.0 ; python_version >= "3.11" and python_version < "4.0" openapi-pydantic==0.5.1 ; python_version >= "3.11" and python_version < "4.0" opentelemetry-api==1.35.0 ; python_version >= "3.11" and python_version < "4.0" opentelemetry-exporter-otlp-proto-common==1.35.0 ; python_version >= "3.11" and python_version < "4.0" opentelemetry-exporter-otlp-proto-http==1.35.0 ; python_version >= "3.11" and python_version < "4.0" +opentelemetry-exporter-prometheus==0.56b0 ; python_version >= "3.11" and python_version < "4.0" opentelemetry-instrumentation-httpx==0.56b0 ; python_version >= "3.11" and python_version < "4.0" opentelemetry-instrumentation==0.56b0 ; python_version >= "3.11" and python_version < "4.0" opentelemetry-proto==1.35.0 ; python_version >= "3.11" and python_version < "4.0" opentelemetry-sdk==1.35.0 ; python_version >= "3.11" and python_version < "4.0" opentelemetry-semantic-conventions==0.56b0 ; python_version >= "3.11" and python_version < "4.0" opentelemetry-util-http==0.56b0 ; python_version >= "3.11" and python_version < "4.0" -orjson==3.11.4 ; python_version >= "3.11" and python_version < "4.0" -ormsgpack==1.12.0 ; python_version >= "3.11" and python_version < "4.0" +orjson==3.11.5 ; python_version >= "3.11" and python_version < "4.0" +ormsgpack==1.12.1 ; python_version >= "3.11" and python_version < "4.0" packaging==25.0 ; python_version >= "3.11" and python_version < "4.0" parso==0.8.5 ; python_version >= "3.11" and python_version < "4.0" pathable==0.4.4 ; python_version >= "3.11" and python_version < "4.0" pathvalidate==3.3.1 ; python_version >= "3.11" and python_version < "4.0" pexpect==4.9.0 ; python_version >= "3.11" and python_version < "4.0" and sys_platform != "win32" and sys_platform != "emscripten" -pgvector==0.4.1 ; python_version >= "3.11" and python_version < "4.0" +pgvector==0.4.2 ; python_version >= "3.11" and python_version < "4.0" pillow==12.0.0 ; python_version >= "3.11" and python_version < "4.0" -platformdirs==4.5.0 ; python_version >= "3.11" and python_version < "4.0" +platformdirs==4.5.1 ; python_version >= "3.11" and python_version < "4.0" pluggy==1.6.0 ; python_version >= "3.11" and python_version < "4.0" posthog==5.4.0 ; python_version >= "3.11" and python_version < "4.0" primp==0.15.0 ; python_version >= "3.11" and python_version < "4.0" +prometheus-client==0.23.1 ; python_version >= "3.11" and python_version < "4.0" prompt-toolkit==3.0.52 ; python_version >= "3.11" and python_version < "4.0" propcache==0.4.1 ; python_version >= "3.11" and python_version < "4.0" -protobuf==6.33.1 ; python_version >= "3.11" and python_version < "4.0" -psutil==7.1.3 ; python_version >= "3.11" and python_version < "4.0" +protobuf==6.33.2 ; python_version >= "3.11" and python_version < "4.0" +psutil==7.2.0 ; python_version >= "3.11" and python_version < "4.0" psycopg2==2.9.11 ; python_version >= "3.11" and python_version < "4.0" ptyprocess==0.7.0 ; python_version >= "3.11" and python_version < "4.0" and sys_platform != "win32" and sys_platform != "emscripten" pure-eval==0.2.3 ; python_version >= "3.11" and python_version < "4.0" -py-key-value-aio==0.2.8 ; python_version >= "3.11" and python_version < "4.0" -py-key-value-shared==0.2.8 ; python_version >= "3.11" and python_version < "4.0" +py-key-value-aio==0.3.0 ; python_version >= "3.11" and python_version < "4.0" +py-key-value-shared==0.3.0 ; python_version >= "3.11" and python_version < "4.0" pyasn1-modules==0.4.2 ; python_version >= "3.11" and python_version < "4.0" pyasn1==0.6.1 ; python_version >= "3.11" and python_version < "4.0" pycparser==2.23 ; python_version >= "3.11" and python_version < "4.0" @@ -200,11 +207,12 @@ pydantic-evals==1.22.0 ; python_version >= "3.11" and python_version < "4.0" pydantic-graph==1.22.0 ; python_version >= "3.11" and python_version < "4.0" pydantic-settings==2.12.0 ; python_version >= "3.11" and python_version < "4.0" pydantic==2.12.5 ; python_version >= "3.11" and python_version < "4.0" -pydyf==0.11.0 ; python_version >= "3.11" and python_version < "4.0" +pydocket==0.15.4 ; python_version >= "3.11" and python_version < "4.0" +pydyf==0.12.1 ; python_version >= "3.11" and python_version < "4.0" pygments==2.19.2 ; python_version >= "3.11" and python_version < "4.0" pyjwt==2.10.1 ; python_version >= "3.11" and python_version < "4.0" -pymupdf==1.26.6 ; python_version >= "3.11" and python_version < "4.0" -pypdf==6.4.0 ; python_version >= "3.11" and python_version < "4.0" +pymupdf==1.26.7 ; python_version >= "3.11" and python_version < "4.0" +pypdf==6.5.0 ; python_version >= "3.11" and python_version < "4.0" pyperclip==1.11.0 ; python_version >= "3.11" and python_version < "4.0" pyphen==0.17.2 ; python_version >= "3.11" and python_version < "4.0" pytest-django==4.11.1 ; python_version >= "3.11" and python_version < "4.0" @@ -215,8 +223,9 @@ python-dotenv==1.2.1 ; python_version >= "3.11" and python_version < "4.0" python-frontmatter==1.1.0 ; python_version >= "3.11" and python_version < "4.0" python-ipware==3.0.0 ; python_version >= "3.11" and python_version < "4.0" python-iso639==2025.11.16 ; python_version >= "3.11" and python_version < "4.0" +python-json-logger==4.0.0 ; python_version >= "3.11" and python_version < "4.0" python-magic==0.4.27 ; python_version >= "3.11" and python_version < "4.0" -python-multipart==0.0.20 ; python_version >= "3.11" and python_version < "4.0" +python-multipart==0.0.21 ; python_version >= "3.11" and python_version < "4.0" python-oxmsg==0.0.2 ; python_version >= "3.11" and python_version < "4.0" python-slugify==8.0.4 ; python_version >= "3.11" and python_version < "4.0" python-webpack-boilerplate==1.0.4 ; python_version >= "3.11" and python_version < "4.0" @@ -233,19 +242,20 @@ requests-toolbelt==1.0.0 ; python_version >= "3.11" and python_version < "4.0" requests==2.32.5 ; python_version >= "3.11" and python_version < "4.0" rich-rst==1.3.2 ; python_version >= "3.11" and python_version < "4.0" rich==14.2.0 ; python_version >= "3.11" and python_version < "4.0" -rpds-py==0.29.0 ; python_version >= "3.11" and python_version < "4.0" +rpds-py==0.30.0 ; python_version >= "3.11" and python_version < "4.0" rsa==4.9.1 ; python_version >= "3.11" and python_version < "4.0" -s3transfer==0.15.0 ; python_version >= "3.11" and python_version < "4.0" +s3transfer==0.16.0 ; python_version >= "3.11" and python_version < "4.0" secretstorage==3.5.0 ; python_version >= "3.11" and python_version < "4.0" and sys_platform == "linux" -sentry-sdk==2.46.0 ; python_version >= "3.11" and python_version < "4.0" +sentry-sdk==2.48.0 ; python_version >= "3.11" and python_version < "4.0" sgmllib3k==1.0.0 ; python_version >= "3.11" and python_version < "4.0" shellingham==1.5.4 ; python_version >= "3.11" and python_version < "4.0" six==1.17.0 ; python_version >= "3.11" and python_version < "4.0" sniffio==1.3.1 ; python_version >= "3.11" and python_version < "4.0" -soupsieve==2.8 ; python_version >= "3.11" and python_version < "4.0" -sqlalchemy==2.0.44 ; python_version >= "3.11" and python_version < "4.0" -sqlparse==0.5.3 ; python_version >= "3.11" and python_version < "4.0" -sse-starlette==3.0.3 ; python_version >= "3.11" and python_version < "4.0" +sortedcontainers==2.4.0 ; python_version >= "3.11" and python_version < "4.0" +soupsieve==2.8.1 ; python_version >= "3.11" and python_version < "4.0" +sqlalchemy==2.0.45 ; python_version >= "3.11" and python_version < "4.0" +sqlparse==0.5.5 ; python_version >= "3.11" and python_version < "4.0" +sse-starlette==3.1.1 ; python_version >= "3.11" and python_version < "4.0" stack-data==0.6.3 ; python_version >= "3.11" and python_version < "4.0" starlette==0.50.0 ; python_version >= "3.11" and python_version < "4.0" stripe==11.6.0 ; python_version >= "3.11" and python_version < "4.0" @@ -260,17 +270,19 @@ tinyhtml5==2.0.0 ; python_version >= "3.11" and python_version < "4.0" tokenizers==0.22.1 ; python_version >= "3.11" and python_version < "4.0" tqdm==4.67.1 ; python_version >= "3.11" and python_version < "4.0" traitlets==5.14.3 ; python_version >= "3.11" and python_version < "4.0" -typer-slim==0.20.0 ; python_version >= "3.11" and python_version < "4.0" -types-protobuf==6.32.1.20251105 ; python_version >= "3.11" and python_version < "4.0" +typer-slim==0.21.0 ; python_version >= "3.11" and python_version < "4.0" +typer==0.21.0 ; python_version >= "3.11" and python_version < "4.0" +types-protobuf==6.32.1.20251210 ; python_version >= "3.11" and python_version < "4.0" types-requests==2.32.4.20250913 ; python_version >= "3.11" and python_version < "4.0" and platform_system != "Emscripten" typing-extensions==4.15.0 ; python_version >= "3.11" and python_version < "4.0" typing-inspect==0.9.0 ; python_version >= "3.11" and python_version < "4.0" typing-inspection==0.4.2 ; python_version >= "3.11" and python_version < "4.0" -tzdata==2025.2 ; python_version >= "3.11" and python_version < "4.0" -unstructured-client==0.42.4 ; python_version >= "3.11" and python_version < "4.0" +tzdata==2025.3 ; python_version >= "3.11" and python_version < "4.0" +unstructured-client==0.42.6 ; python_version >= "3.11" and python_version < "4.0" unstructured==0.18.21 ; python_version >= "3.11" and python_version < "4.0" -urllib3==2.5.0 ; python_version >= "3.11" and python_version < "4.0" -uvicorn==0.38.0 ; python_version >= "3.11" and python_version < "4.0" +urllib3==2.6.2 ; python_version >= "3.11" and python_version < "4.0" +uuid-utils==0.12.0 ; python_version >= "3.11" and python_version < "4.0" +uvicorn==0.40.0 ; python_version >= "3.11" and python_version < "4.0" wcwidth==0.2.14 ; python_version >= "3.11" and python_version < "4.0" weasyprint==66.0 ; python_version >= "3.11" and python_version < "4.0" webencodings==0.5.1 ; python_version >= "3.11" and python_version < "4.0" diff --git a/snippets/inspect_blog_post_title_suggestion.py b/snippets/inspect_blog_post_title_suggestion.py new file mode 100644 index 0000000..d907aef --- /dev/null +++ b/snippets/inspect_blog_post_title_suggestion.py @@ -0,0 +1,168 @@ +from core.models import ( + BlogPostTitleSuggestion, + GeneratedBlogPost, + GeneratedBlogPostResearchLink, + GeneratedBlogPostResearchQuestion, + GeneratedBlogPostSection, +) +from core.utils import get_relevant_external_pages_for_blog_post + + +def format_heading(text: str) -> str: + return f"\n{'=' * 16} {text} {'=' * 16}\n" + + +def format_subheading(text: str) -> str: + return f"\n{'-' * 10} {text} {'-' * 10}\n" + + +blog_post_title_suggestion_id_raw = input("BlogPostTitleSuggestion id: ").strip() +blog_post_title_suggestion_id = int(blog_post_title_suggestion_id_raw) + +title_suggestion = ( + BlogPostTitleSuggestion.objects.select_related("project") + .filter(id=blog_post_title_suggestion_id) + .first() +) + +if not title_suggestion: + raise ValueError(f"BlogPostTitleSuggestion not found: {blog_post_title_suggestion_id}") + +project = title_suggestion.project + +print(format_heading("TITLE SUGGESTION")) +print(f"id: {title_suggestion.id}") +print(f"project_id: {title_suggestion.project_id}") +print(f"title: {title_suggestion.title}") +print(f"content_type: {title_suggestion.content_type}") +print(f"category: {title_suggestion.category}") +print(f"description: {title_suggestion.description}") +print(f"prompt: {title_suggestion.prompt}") +print(f"target_keywords: {title_suggestion.target_keywords or []}") +print(f"suggested_meta_description: {title_suggestion.suggested_meta_description}") +print(f"user_score: {title_suggestion.user_score}") +print(f"archived: {title_suggestion.archived}") + +print(format_heading("PROJECT")) +if not project: + print("No project associated") +else: + print(f"id: {project.id}") + print(f"name: {project.name}") + print(f"type: {project.type}") + print(f"language: {project.language}") + print(f"location: {project.location}") + print(f"summary: {project.summary}") + print(f"blog_theme: {project.blog_theme}") + print(f"founders: {project.founders}") + print(f"key_features: {project.key_features}") + print(f"target_audience_summary: {project.target_audience_summary}") + print(f"pain_points: {project.pain_points}") + print(f"product_usage: {project.product_usage}") + print(f"proposed_keywords: {project.proposed_keywords}") + print(f"links: {project.links}") + +print(format_heading("DERIVED INPUTS")) +keywords_to_use = title_suggestion.get_blog_post_keywords() +print(f"keywords_to_use ({len(keywords_to_use)}): {keywords_to_use}") + +try: + internal_links = title_suggestion.get_internal_links(max_pages=2) +except Exception as error: + internal_links = [] + print(f"get_internal_links error: {error}") + +print(f"internal_links ({len(internal_links)}):") +for project_page in internal_links: + print( + f"- [{project_page.id}] {project_page.title} | {project_page.url} | always_use={project_page.always_use}" # noqa: E501 + ) + +try: + external_links = list( + get_relevant_external_pages_for_blog_post( + meta_description=title_suggestion.suggested_meta_description or "", + exclude_project=title_suggestion.project, + max_pages=3, + ) + ) +except Exception as error: + external_links = [] + print(f"get_relevant_external_pages_for_blog_post error: {error}") + +print(f"external_links ({len(external_links)}):") +for project_page in external_links: + print( + f"- [{project_page.id}] {project_page.title} | {project_page.url} | " + f"project_id={project_page.project_id} always_use={project_page.always_use}" + ) + +generated_blog_posts = ( + GeneratedBlogPost.objects.filter(title_suggestion=title_suggestion) + .select_related("project", "title_suggestion") + .order_by("-id") +) + +print(format_heading("GENERATED BLOG POSTS")) +print(f"count: {generated_blog_posts.count()}") + +for blog_post in generated_blog_posts: + print(format_subheading(f"GeneratedBlogPost {blog_post.id}")) + print(f"id: {blog_post.id}") + print(f"project_id: {blog_post.project_id}") + print(f"title_suggestion_id: {blog_post.title_suggestion_id}") + print(f"title: {blog_post.title}") + print(f"description: {blog_post.description}") + print(f"slug: {blog_post.slug}") + print(f"tags: {blog_post.tags}") + print(f"posted: {blog_post.posted}") + print(f"date_posted: {blog_post.date_posted}") + print(f"content_length: {len(blog_post.content or '')}") + + sections = GeneratedBlogPostSection.objects.filter(blog_post=blog_post).order_by("order", "id") + print(format_subheading(f"Sections ({sections.count()})")) + + for section in sections: + print( + f"[{section.order}] section_id={section.id} title={section.title} content_length={len(section.content or '')}" # noqa: E501 + ) + + section_questions = GeneratedBlogPostResearchQuestion.objects.filter( + section=section + ).order_by("id") + print(f" research_questions ({section_questions.count()}):") + for research_question in section_questions: + print(f" - [{research_question.id}] {research_question.question}") + + question_links = ( + GeneratedBlogPostResearchLink.objects.filter(research_question=research_question) + .order_by("id") + .values( + "id", + "url", + "title", + "author", + "published_date", + "date_scraped", + "date_analyzed", + ) + ) + question_links_list = list(question_links) + print(f" links ({len(question_links_list)}):") + for research_link in question_links_list: + print( + f" - [{research_link['id']}] {research_link['title']} | {research_link['url']} | " # noqa: E501 + f"author={research_link['author']} published_date={research_link['published_date']} " # noqa: E501 + f"date_scraped={research_link['date_scraped']} date_analyzed={research_link['date_analyzed']}" # noqa: E501 + ) + + blog_post_questions = GeneratedBlogPostResearchQuestion.objects.filter( + blog_post=blog_post, + section__isnull=True, + ).order_by("id") + if blog_post_questions.exists(): + print(format_subheading(f"Blog-level research questions ({blog_post_questions.count()})")) + for research_question in blog_post_questions: + print(f"- [{research_question.id}] {research_question.question}") + +print(format_heading("DONE")) diff --git a/tuxseo/settings.py b/tuxseo/settings.py index accc865..f77a45a 100644 --- a/tuxseo/settings.py +++ b/tuxseo/settings.py @@ -549,4 +549,7 @@ def extract_from_record(logger, name, event_dict): "from django_q.tasks import async_task", "from core.scheduled_tasks import *", "from core.tasks import *", + "from exa_py import Exa", ] + +EXA_API_KEY = env("EXA_API_KEY", default="") From 01efb03030b0bb95b21ad0cfdca0c3a8b2ce35ec Mon Sep 17 00:00:00 2001 From: Rasul Kireev Date: Sat, 27 Dec 2025 23:51:27 +0300 Subject: [PATCH 2/3] task --- core/tasks.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/core/tasks.py b/core/tasks.py index 9a56118..a5e3a70 100644 --- a/core/tasks.py +++ b/core/tasks.py @@ -1780,15 +1780,3 @@ def generate_blog_post_content(suggestion_id: int, send_email: bool = True): project_id=suggestion.project.id if suggestion.project else None, ) return f"Unexpected error: {str(error)}" - - -def generate_research_questions_for_section_task(section_id: int): - """ - Generate research questions for one blog post section, then queue Exa research link tasks for - each created question. - """ - from core.content_generator.tasks import ( - generate_research_questions_for_section_task as delegated_task, - ) - - return delegated_task(section_id=section_id) From d01bb1ce7babbf433912b01fe3b99c99d86fa391 Mon Sep 17 00:00:00 2001 From: Rasul Kireev Date: Sun, 28 Dec 2025 14:29:04 +0300 Subject: [PATCH 3/3] dump --- README.md | 35 + content_generation/__init__.py | 0 content_generation/admin.py | 1 + content_generation/apps.py | 6 + content_generation/migrations/__init__.py | 0 content_generation/models.py | 369 +++++++++ content_generation/tests.py | 1 + content_generation/views.py | 1 + ...nerate_blog_post_intro_conclusion_agent.py | 100 +++ ...enerate_blog_post_section_content_agent.py | 123 +++ core/agents/research_link_summary_agent.py | 33 + core/agents/schemas.py | 98 +++ core/content_generator/pipeline.py | 749 +++++++++++++++++- core/content_generator/tasks.py | 74 +- ...eratedblogpostresearchquestion_and_more.py | 95 --- ...edblogpostresearchlink_content_and_more.py | 44 - core/models.py | 3 +- core/urls.py | 5 + core/views.py | 210 +++++ .../blog/blog_post_research_process.html | 336 ++++++++ .../blog/generated_blog_post_detail.html | 14 + .../components/blog_post_suggestion_card.html | 14 +- tuxseo/settings.py | 1 + 23 files changed, 2120 insertions(+), 192 deletions(-) create mode 100644 content_generation/__init__.py create mode 100644 content_generation/admin.py create mode 100644 content_generation/apps.py create mode 100644 content_generation/migrations/__init__.py create mode 100644 content_generation/models.py create mode 100644 content_generation/tests.py create mode 100644 content_generation/views.py create mode 100644 core/agents/generate_blog_post_intro_conclusion_agent.py create mode 100644 core/agents/generate_blog_post_section_content_agent.py delete mode 100644 core/migrations/0050_backlink_generatedblogpostresearchquestion_and_more.py delete mode 100644 core/migrations/0051_rename_markdown_content_generatedblogpostresearchlink_content_and_more.py create mode 100644 frontend/templates/blog/blog_post_research_process.html diff --git a/README.md b/README.md index 3c8fae6..08fcb51 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,44 @@ *** +## Technical Details + +### Content Generation Pipeline + +```mermaid +flowchart TD + A["BlogPostTitleSuggestion.generate_content()"] --> B["init_blog_post_content_generation()"] + B --> C["AI: generate outline section titles
(Introduction + middle sections + Conclusion)"] + C --> D["DB: create GeneratedBlogPost + GeneratedBlogPostSection rows"] + + D --> E{"For each middle section"} + E --> F["Task: generate research questions for section
(local: 1 question)"] + + F --> G{"For each research question"} + G --> H["Task: Exa search for links
(local: 2 links)"] + + H --> I{"For each research link"} + I --> J["Task: scrape link with Jina Reader"] + J --> K["Task: analyze link (AI)
summary + contextual summary + answer"] + + K --> L{"All links attempted/analyzed?"} + L -- no --> K + L -- yes --> M["Task: synthesize middle section contents (AI)"] + + M --> N{"All middle sections have content?"} + N -- yes --> O["Task: generate Introduction + Conclusion (AI)"] + N -- no --> M + + O --> P{"All sections (incl. intro/conclusion) have content?"} + P -- yes --> Q["Task: populate GeneratedBlogPost.content
(code: combine sections into final markdown)"] + P -- no --> O +``` + ## TOC - [Overview](#overview) +- [Technical Details](#technical-details) + - [Content Generation Pipeline](#content-generation-pipeline) - [TOC](#toc) - [Deployment](#deployment) - [Render](#render) diff --git a/content_generation/__init__.py b/content_generation/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/content_generation/admin.py b/content_generation/admin.py new file mode 100644 index 0000000..846f6b4 --- /dev/null +++ b/content_generation/admin.py @@ -0,0 +1 @@ +# Register your models here. diff --git a/content_generation/apps.py b/content_generation/apps.py new file mode 100644 index 0000000..f88ddd6 --- /dev/null +++ b/content_generation/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ContentGenerationConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "content_generation" diff --git a/content_generation/migrations/__init__.py b/content_generation/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/content_generation/models.py b/content_generation/models.py new file mode 100644 index 0000000..4875573 --- /dev/null +++ b/content_generation/models.py @@ -0,0 +1,369 @@ +from urllib.request import urlopen + +import replicate +import requests +from django.conf import settings +from django.core.files.base import ContentFile +from django.db import models + +from core.agents import ( + create_insert_links_agent, +) +from core.agents.schemas import ( + GeneratedBlogPostSchema, + LinkInsertionContext, + ProjectPageContext, +) +from core.base_models import BaseModel +from core.choices import ( + OGImageStyle, +) +from core.models import AutoSubmissionSetting, BlogPostTitleSuggestion, Project +from core.utils import ( + get_og_image_prompt, + get_relevant_external_pages_for_blog_post, +) +from tuxseo.utils import get_tuxseo_logger + +logger = get_tuxseo_logger(__name__) + + +class GeneratedBlogPost(BaseModel): + project = models.ForeignKey( + Project, + null=True, + blank=True, + on_delete=models.CASCADE, + related_name="generated_blog_posts", + ) + title_suggestion = models.ForeignKey( + BlogPostTitleSuggestion, + null=True, + blank=True, + on_delete=models.CASCADE, + related_name="generated_blog_posts", + ) + + # Final Output Items + title = models.CharField(max_length=250) + description = models.TextField(blank=True) + slug = models.SlugField(max_length=250) + tags = models.TextField() + content = models.TextField() + icon = models.ImageField(upload_to="generated_blog_post_icons/", blank=True) + image = models.ImageField(upload_to="generated_blog_post_images/", blank=True) + + # Preparation + # GeneratedBlogPostSection model + + # Other + posted = models.BooleanField(default=False) + date_posted = models.DateTimeField(null=True, blank=True) + + def __str__(self): + return f"{self.project.name}: {self.title}" + + @classmethod + def blog_post_structure_rules(cls): + return """ + - Use markdown. + - Start with the title as h1 (#). Do no include any other metadata (description, slug, etc.) + - Then do and intro, starting with `## Introduction`, then a paragraph of text. + - Continue with h2 (##) topics as you see fit. + - Do not go deeper than h2 (##) for post structure. + - Never inlcude placeholder items (insert image here, link suggestions, etc.) + - Do not have `References` section, insert all the links into the post directly, organically. + - Do not include a call to action paragraph at the end of the post. + - Finish the post with a conclusion. + - Instead of using links as a reference, try to insert them into the post directly, organically. + """ # noqa: E501 + + @property + def generated_blog_post_schema(self): + return GeneratedBlogPostSchema( + description=self.description, + slug=self.slug, + tags=self.tags, + content=self.content, + ) + + def submit_blog_post_to_endpoint(self): + from core.utils import replace_placeholders + + project = self.project + submission_settings = ( + AutoSubmissionSetting.objects.filter(project=project).order_by("-id").first() + ) + + if not submission_settings or not submission_settings.endpoint_url: + logger.warning( + "No AutoSubmissionSetting or endpoint_url found for project", project_id=project.id + ) + return False + + url = submission_settings.endpoint_url + headers = replace_placeholders(submission_settings.header, self) + body = replace_placeholders(submission_settings.body, self) + + logger.info( + "[Submit Blog Post] Submitting blog post to endpoint", + project_id=project.id, + profile_id=project.profile.id, + endpoint_url=url, + headers_configured=bool(headers), + body_configured=bool(body), + ) + + try: + session = requests.Session() + session.cookies.clear() + + if headers is None: + headers = {} + + if "content-type" not in headers and "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + response = session.post(url, json=body, headers=headers, timeout=15) + response.raise_for_status() + return True + + except requests.RequestException as e: + logger.error( + "[Submit Blog Post to Endpoint] Request error", + error=str(e), + url=url, + headers=headers, + exc_info=True, + ) + return False + + def generate_og_image(self) -> tuple[bool, str]: + """ + Generate an Open Graph image for a blog post using Replicate flux-schnell model. + + Args: + generated_post: The GeneratedBlogPost instance to generate an image for + replicate_api_token: Replicate API token for authentication + + Returns: + A tuple of (success: bool, message: str) + """ + + if not settings.REPLICATE_API_TOKEN: + logger.error( + "[GenerateOGImage] Replicate API token not configured", + blog_post_id=self.id, + project_id=self.project_id, + ) + return False, "Replicate API token not configured" + + if self.image: + logger.info( + "[GenerateOGImage] Image already exists for blog post", + blog_post_id=self.id, + project_id=self.project_id, + ) + return True, f"Image already exists for blog post {self.id}" + + try: + blog_post_category = ( + self.title_suggestion.category if self.title_suggestion.category else "technology" + ) + + project_og_style = self.project.og_image_style or OGImageStyle.MODERN_GRADIENT + prompt = get_og_image_prompt(project_og_style, blog_post_category) + + logger.info( + "[GenerateOGImage] Starting image generation", + blog_post_id=self.id, + project_id=self.project_id, + category=blog_post_category, + og_style=project_og_style, + prompt=prompt, + ) + + replicate_client = replicate.Client(api_token=settings.REPLICATE_API_TOKEN) + + output = replicate_client.run( + "black-forest-labs/flux-schnell", + input={ + "prompt": prompt, + "aspect_ratio": "16:9", + "output_format": "png", + "output_quality": 90, + }, + ) + + if not output: + logger.error( + "[GenerateOGImage] No output from Replicate", + blog_post_id=self.id, + project_id=self.project_id, + ) + return False, f"Failed to generate image for blog post {self.id}" + + file_output = output[0] if isinstance(output, list) else output + image_url = str(file_output) + + logger.info( + "[GenerateOGImage] Image generated successfully", + blog_post_id=self.id, + project_id=self.project_id, + image_url=image_url, + ) + + image_response = urlopen(image_url) + image_content = ContentFile(image_response.read()) + + filename = f"og-image-{self.id}.png" + self.image.save(filename, image_content, save=True) + + logger.info( + "[GenerateOGImage] Image saved to blog post", + blog_post_id=self.id, + project_id=self.project_id, + saved_url=self.image.url, + ) + + return True, f"Successfully generated and saved OG image for blog post {self.id}" + + except replicate.exceptions.ReplicateError as replicate_error: + logger.error( + "[GenerateOGImage] Replicate API error", + error=str(replicate_error), + exc_info=True, + blog_post_id=self.id, + project_id=self.project_id, + ) + return False, f"Replicate API error: {str(replicate_error)}" + except Exception as error: + logger.error( + "[GenerateOGImage] Unexpected error during image generation", + error=str(error), + exc_info=True, + blog_post_id=self.id, + project_id=self.project_id, + ) + return False, f"Unexpected error: {str(error)}" + + def insert_links_into_post(self, max_pages=4, max_external_pages=3): + """ + Insert links from project pages into the blog post content organically. + Uses PydanticAI to intelligently place links without modifying the content. + + Args: + max_pages: Maximum number of internal project pages to use for linking (default: 4) + max_external_pages: Maximum number of external project pages to use for linking (default: 3) + + Returns: + str: The blog post content with links inserted + """ # noqa: E501 + from core.utils import ( + get_relevant_pages_for_blog_post, + run_agent_synchronously, + ) + + if not self.title_suggestion: + logger.warning( + "[InsertLinksIntoPost] No title suggestion found for blog post", + blog_post_id=self.id, + project_id=self.project_id, + ) + return self.content + + # Get internal project pages + manually_selected_project_pages = list(self.project.project_pages.filter(always_use=True)) + relevant_project_pages = list( + get_relevant_pages_for_blog_post( + self.project, + self.title_suggestion.suggested_meta_description, + max_pages=max_pages, + ) + ) + + all_project_pages = manually_selected_project_pages + relevant_project_pages + + # Get external project pages if link exchange is enabled + external_project_pages = [] + if self.project.particiate_in_link_exchange: + external_project_pages = list( + get_relevant_external_pages_for_blog_post( + meta_description=self.title_suggestion.suggested_meta_description, + exclude_project=self.project, + max_pages=max_external_pages, + ) + ) + # Filter to only include pages from projects that also participate in link exchange + external_project_pages = [ + page for page in external_project_pages if page.project.particiate_in_link_exchange + ] + + all_pages_to_link = all_project_pages + external_project_pages + + if not all_pages_to_link: + logger.info( + "[InsertLinksIntoPost] No pages found for link insertion", + blog_post_id=self.id, + project_id=self.project_id, + ) + return self.content + + project_page_contexts = [ + ProjectPageContext( + url=page.url, + title=page.title, + description=page.description, + summary=page.summary, + ) + for page in all_pages_to_link + ] + + # Extract URLs for logging + urls_to_insert = [page.url for page in all_pages_to_link] + internal_urls = [page.url for page in all_project_pages] + external_urls = [page.url for page in external_project_pages] + + link_insertion_context = LinkInsertionContext( + blog_post_content=self.content, + project_pages=project_page_contexts, + ) + + insert_links_agent = create_insert_links_agent() + + prompt = "Insert the provided project page links into the blog post content organically. Do not modify the existing content, only add links where appropriate." # noqa: E501 + + logger.info( + "[InsertLinksIntoPost] Running link insertion agent", + blog_post_id=self.id, + project_id=self.project_id, + num_total_pages=len(project_page_contexts), + num_internal_pages=len(all_project_pages), + num_external_pages=len(external_project_pages), + num_always_use_pages=len(manually_selected_project_pages), + participate_in_link_exchange=self.project.particiate_in_link_exchange, + urls_to_insert=urls_to_insert, + internal_urls=internal_urls, + external_urls=external_urls, + ) + + result = run_agent_synchronously( + insert_links_agent, + prompt, + deps=link_insertion_context, + function_name="insert_links_into_post", + model_name="GeneratedBlogPost", + ) + + content_with_links = result.output + + self.content = content_with_links + self.save(update_fields=["content"]) + + logger.info( + "[InsertLinksIntoPost] Links inserted successfully", + blog_post_id=self.id, + project_id=self.project_id, + ) + + return content_with_links diff --git a/content_generation/tests.py b/content_generation/tests.py new file mode 100644 index 0000000..a39b155 --- /dev/null +++ b/content_generation/tests.py @@ -0,0 +1 @@ +# Create your tests here. diff --git a/content_generation/views.py b/content_generation/views.py new file mode 100644 index 0000000..60f00ef --- /dev/null +++ b/content_generation/views.py @@ -0,0 +1 @@ +# Create your views here. diff --git a/core/agents/generate_blog_post_intro_conclusion_agent.py b/core/agents/generate_blog_post_intro_conclusion_agent.py new file mode 100644 index 0000000..281454f --- /dev/null +++ b/core/agents/generate_blog_post_intro_conclusion_agent.py @@ -0,0 +1,100 @@ +from django.utils import timezone +from pydantic_ai import Agent + +from core.agents.schemas import ( + BlogPostIntroConclusionGenerationContext, + GeneratedBlogPostIntroConclusionSchema, +) +from core.choices import ContentType, get_default_ai_model +from core.prompts import GENERATE_CONTENT_SYSTEM_PROMPTS + +INTRO_CONCLUSION_SYSTEM_PROMPT = """ +You are an expert blog post writer. + +Your task: write BOTH the Introduction and the Conclusion for a blog post in a single response. + +Rules: +- Return two fields only: introduction and conclusion. +- Do NOT include markdown headings for either section. No leading '#', '##', or '###'. +- Use the existing section contents as the source of truth for what the post covers. +- The introduction should set up the promise and smoothly lead into the first middle section. +- The conclusion should summarize the key takeaways and close cleanly without adding new topics. +- Do not add placeholders. +""" + + +def create_generate_blog_post_intro_conclusion_agent( + content_type: ContentType = ContentType.SHARING, model=None +): + """ + Create an agent to generate a blog post Introduction + Conclusion in one call. + """ + agent = Agent( + model or get_default_ai_model(), + output_type=GeneratedBlogPostIntroConclusionSchema, + deps_type=BlogPostIntroConclusionGenerationContext, + system_prompt=( + INTRO_CONCLUSION_SYSTEM_PROMPT + + "\n\n" + + (GENERATE_CONTENT_SYSTEM_PROMPTS.get(content_type, "") or "") + ), + retries=2, + model_settings={"max_tokens": 6000, "temperature": 0.7}, + ) + + @agent.system_prompt + def add_intro_conclusion_context(ctx) -> str: + intro_conclusion_context: BlogPostIntroConclusionGenerationContext = ctx.deps + generation_context = intro_conclusion_context.blog_post_generation_context + project_details = generation_context.project_details + title_suggestion = generation_context.title_suggestion + target_keywords = title_suggestion.target_keywords or [] + + section_titles_text = ( + "\n".join( + [ + f"- {title}" + for title in (intro_conclusion_context.section_titles_in_order or []) + if title + ] + ) + or "- (none)" + ) + + sections_text = "" + for index, section in enumerate(intro_conclusion_context.sections_in_order or [], start=1): + sections_text += f"\nSection {index}: {section.title}\n{section.content}\n" + + if not sections_text.strip(): + sections_text = "\n(none)\n" + + return f""" +Today's date: {timezone.now().strftime("%Y-%m-%d")} + +Project details: +- Project name: {project_details.name} +- Project type: {project_details.type} +- Project summary: {project_details.summary} +- Blog theme: {project_details.blog_theme} +- Key features: {project_details.key_features} +- Target audience: {project_details.target_audience_summary} +- Pain points: {project_details.pain_points} +- Product usage: {project_details.product_usage} + +Blog post title suggestion: +- Title: {title_suggestion.title} +- Category: {title_suggestion.category} +- Description: {title_suggestion.description} +- Suggested meta description: {title_suggestion.suggested_meta_description} +- Target keywords: {", ".join(target_keywords) if target_keywords else "None"} + +Outline: +{section_titles_text} + +All existing section contents (use this as the truth of what the post covers): +{sections_text} + +Language: Write in {project_details.language}. +""" + + return agent diff --git a/core/agents/generate_blog_post_section_content_agent.py b/core/agents/generate_blog_post_section_content_agent.py new file mode 100644 index 0000000..7c03082 --- /dev/null +++ b/core/agents/generate_blog_post_section_content_agent.py @@ -0,0 +1,123 @@ +from django.utils import timezone +from pydantic_ai import Agent + +from core.agents.schemas import ( + BlogPostSectionContentGenerationContext, + GeneratedBlogPostSectionContentSchema, +) +from core.choices import ContentType, get_default_ai_model +from core.prompts import GENERATE_CONTENT_SYSTEM_PROMPTS + +SECTION_CONTENT_SYSTEM_PROMPT = """ +You are an expert blog post writer. + +Your task: write the content for ONE blog post section (the body of the section only). + +Rules: +- Do NOT write the Introduction or Conclusion. +- Do NOT include the section title as a markdown header. No leading '#', '##', or '###'. +- Avoid markdown headings entirely. Use paragraphs, bullet lists, and numbered lists only when useful. +- Use the provided "Previous sections" to maintain continuity and avoid repetition. +- Use the provided research link outputs as factual grounding. Do not invent sources or cite URLs. +- Keep the section coherent with the overall outline and the order position provided. +- Do not add placeholders. +""" + + +def create_generate_blog_post_section_content_agent( + content_type: ContentType = ContentType.SHARING, model=None +): + """ + Create an agent to generate the content for a single middle section of a blog post. + """ + agent = Agent( + model or get_default_ai_model(), + output_type=GeneratedBlogPostSectionContentSchema, + deps_type=BlogPostSectionContentGenerationContext, + system_prompt=( + SECTION_CONTENT_SYSTEM_PROMPT + + "\n\n" + + (GENERATE_CONTENT_SYSTEM_PROMPTS.get(content_type, "") or "") + ), + retries=2, + model_settings={"max_tokens": 16000, "temperature": 0.7}, + ) + + @agent.system_prompt + def add_section_content_context(ctx) -> str: + section_context: BlogPostSectionContentGenerationContext = ctx.deps + generation_context = section_context.blog_post_generation_context + project_details = generation_context.project_details + title_suggestion = generation_context.title_suggestion + target_keywords = title_suggestion.target_keywords or [] + + other_titles = [title for title in (section_context.other_section_titles or []) if title] + other_titles_text = "\n".join([f"- {title}" for title in other_titles]) or "- (none)" + + previous_sections = section_context.previous_sections or [] + previous_sections_text = "" + for previous_section_index, previous_section in enumerate(previous_sections, start=1): + previous_sections_text += ( + f"\nPrevious section {previous_section_index}: {previous_section.title}\n" + f"{previous_section.content}\n" + ) + if not previous_sections_text.strip(): + previous_sections_text = "\n(none)\n" + + research_questions_text = "" + for question_index, question in enumerate( + section_context.research_questions or [], start=1 + ): + research_questions_text += ( + f"\nResearch question {question_index}: {question.question}\n" + ) + for link_index, link in enumerate(question.research_links or [], start=1): + research_questions_text += ( + f"\nAnswered research link {link_index}:\n" + f"- summary_for_question_research:\n{link.summary_for_question_research}\n" + f"- general_summary:\n{link.general_summary}\n" + f"- answer_to_question:\n{link.answer_to_question}\n" + ) + + if not research_questions_text.strip(): + research_questions_text = "\n(none)\n" + + return f""" +Today's date: {timezone.now().strftime("%Y-%m-%d")} + +Project details: +- Project name: {project_details.name} +- Project type: {project_details.type} +- Project summary: {project_details.summary} +- Blog theme: {project_details.blog_theme} +- Key features: {project_details.key_features} +- Target audience: {project_details.target_audience_summary} +- Pain points: {project_details.pain_points} +- Product usage: {project_details.product_usage} + +Blog post title suggestion: +- Title: {title_suggestion.title} +- Category: {title_suggestion.category} +- Description: {title_suggestion.description} +- Suggested meta description: {title_suggestion.suggested_meta_description} +- Target keywords: {", ".join(target_keywords) if target_keywords else "None"} + +Outline coherence: +- Other section titles: +{other_titles_text} + +Current section to write: +- Section title: {section_context.section_title} +- Section order in outline: {section_context.section_order} / {section_context.total_sections} +- Section order among middle sections: {section_context.research_section_order} / {section_context.total_research_sections} + +Previous sections (for continuity; do not repeat content): +{previous_sections_text} + +Research answers for this section (only include content that is supported by these answers): +{research_questions_text} + +Language: Write in {project_details.language}. +""" + + return agent diff --git a/core/agents/research_link_summary_agent.py b/core/agents/research_link_summary_agent.py index e38bfbe..75aedea 100644 --- a/core/agents/research_link_summary_agent.py +++ b/core/agents/research_link_summary_agent.py @@ -2,6 +2,7 @@ from pydantic_ai import Agent, RunContext from core.agents.schemas import ( + ResearchLinkAnalysis, ResearchLinkContextualSummaryContext, TextSummary, WebPageContent, @@ -88,3 +89,35 @@ def create_contextual_research_link_summary_agent(model=None): agent.system_prompt(_add_blog_post_research_context) agent.system_prompt(_add_webpage_content_from_contextual_deps) return agent + + +def create_research_link_analysis_agent(model=None): + """ + Analyze a research link in a single model call and return: + - a general page summary + - a contextual summary tailored to the blog post section's research question + - a direct answer to the research question (if possible from the page) + """ + agent = Agent( + model or get_default_ai_model(), + output_type=ResearchLinkAnalysis, + deps_type=ResearchLinkContextualSummaryContext, + system_prompt=( + "You are a research assistant helping write a blog post.\n" + "Using only the web page content provided, produce three outputs:\n" + "1) general_summary: a context-free 2-3 sentence summary of what the page is about.\n" + "2) summary_for_question_research: a markdown summary tailored to the research question. " + "Include: a short paragraph summary, 'Key takeaways' (3-7 bullets), and " + "'How this helps our section' (1-3 bullets).\n" + "3) answer_to_question: directly answer the research question in 1-6 sentences. " + "If the page does not answer it (or is irrelevant), say so clearly.\n" + "\n" + "Be concrete and avoid speculation. Prefer facts, definitions, steps, examples, and stats " + "that are present in the page.\n" + ), + retries=2, + model_settings={"temperature": 0.3}, + ) + agent.system_prompt(_add_blog_post_research_context) + agent.system_prompt(_add_webpage_content_from_contextual_deps) + return agent diff --git a/core/agents/schemas.py b/core/agents/schemas.py index 163e66d..872597d 100644 --- a/core/agents/schemas.py +++ b/core/agents/schemas.py @@ -18,6 +18,27 @@ class TextSummary(BaseModel): summary: str = Field(description="A concise summary of the provided content") +class ResearchLinkAnalysis(BaseModel): + general_summary: str = Field( + description=( + "A general, context-free summary of the page content. Keep it to 2-3 sentences." + ) + ) + summary_for_question_research: str = Field( + description=( + "A markdown summary tailored to the blog post's research question. Include: " + "a short paragraph summary, 'Key takeaways' (3-7 bullets), and " + "'How this helps our section' (1-3 bullets)." + ) + ) + answer_to_question: str = Field( + description=( + "A direct answer to the research question, based strictly on the page content. " + "If the page does not answer the question, say so clearly." + ) + ) + + class ProjectDetails(BaseModel): name: str = Field(description="Official name of the project or organization") type: str = Field( @@ -202,6 +223,83 @@ class ResearchLinkContextualSummaryContext(BaseModel): research_question: str = Field(description="Research question we are trying to answer") +class ResearchLinkAnswerSnippet(BaseModel): + summary_for_question_research: str = Field( + description="A markdown summary tailored to the research question" + ) + general_summary: str = Field(description="A general, context-free 2-3 sentence page summary") + answer_to_question: str = Field(description="A direct answer to the research question") + + +class ResearchQuestionWithAnsweredLinks(BaseModel): + question: str = Field(description="The research question we were answering") + research_links: list[ResearchLinkAnswerSnippet] = Field( + default_factory=list, + description="Only research links that include a non-empty answer_to_question", + ) + + +class PriorSectionContext(BaseModel): + title: str = Field(description="Section title") + content: str = Field(description="Section content (markdown)") + + +class BlogPostSectionContentGenerationContext(BaseModel): + blog_post_generation_context: BlogPostGenerationContext + blog_post_title: str = Field(description="Title of the blog post being written") + section_title: str = Field(description="Title of the section to write") + section_order: int = Field(description="Order of this section in the overall outline") + total_sections: int = Field(description="Total number of sections in the outline") + research_section_order: int = Field( + description="1-based order of this section among the middle (non-intro/non-conclusion) sections" + ) + total_research_sections: int = Field( + description="Total number of middle (non-intro/non-conclusion) sections" + ) + other_section_titles: list[str] = Field( + default_factory=list, + description="Titles of the other sections in the blog post (for coherence)", + ) + previous_sections: list[PriorSectionContext] = Field( + default_factory=list, + description="Previously generated section content (in order) to keep the narrative coherent", + ) + research_questions: list[ResearchQuestionWithAnsweredLinks] = Field( + default_factory=list, + description="Research questions for this section, with only answered research links included", + ) + + +class GeneratedBlogPostSectionContentSchema(BaseModel): + content: str = Field( + description=( + "Markdown content for the section body only (do not include the section title as a header)" + ) + ) + + +class BlogPostIntroConclusionGenerationContext(BaseModel): + blog_post_generation_context: BlogPostGenerationContext + blog_post_title: str = Field(description="Title of the blog post being written") + section_titles_in_order: list[str] = Field( + default_factory=list, + description="All section titles in outline order (including Introduction and Conclusion)", + ) + sections_in_order: list[PriorSectionContext] = Field( + default_factory=list, + description="All existing section contents in order (including middle sections) to base intro/conclusion on", + ) + + +class GeneratedBlogPostIntroConclusionSchema(BaseModel): + introduction: str = Field( + description="Markdown content for the Introduction section body only (no heading)" + ) + conclusion: str = Field( + description="Markdown content for the Conclusion section body only (no heading)" + ) + + class GeneratedBlogPostSchema(BaseModel): description: str = Field( description="Meta description (150-160 characters) optimized for search engines" diff --git a/core/content_generator/pipeline.py b/core/content_generator/pipeline.py index dfc8a6b..88226e4 100644 --- a/core/content_generator/pipeline.py +++ b/core/content_generator/pipeline.py @@ -1,6 +1,7 @@ from __future__ import annotations from django.conf import settings +from django.core.cache import cache from django.db import transaction from django.utils import timezone from django.utils.dateparse import parse_datetime @@ -12,13 +13,25 @@ create_blog_post_outline_agent, create_blog_post_section_research_questions_agent, ) +from core.agents.generate_blog_post_intro_conclusion_agent import ( + create_generate_blog_post_intro_conclusion_agent, +) +from core.agents.generate_blog_post_section_content_agent import ( + create_generate_blog_post_section_content_agent, +) from core.agents.research_link_summary_agent import ( - create_contextual_research_link_summary_agent, - create_general_research_link_summary_agent, + create_research_link_analysis_agent, ) from core.agents.schemas import ( BlogPostGenerationContext, + BlogPostIntroConclusionGenerationContext, + BlogPostSectionContentGenerationContext, + GeneratedBlogPostIntroConclusionSchema, + GeneratedBlogPostSectionContentSchema, + PriorSectionContext, + ResearchLinkAnswerSnippet, ResearchLinkContextualSummaryContext, + ResearchQuestionWithAnsweredLinks, WebPageContent, ) from core.choices import ContentType @@ -39,6 +52,8 @@ CONCLUSION_SECTION_TITLE = "Conclusion" NON_RESEARCH_SECTION_TITLES = {INTRODUCTION_SECTION_TITLE, CONCLUSION_SECTION_TITLE} MAX_RESEARCH_LINK_MARKDOWN_CHARS_FOR_SUMMARY = 25_000 +LOCAL_MAX_RESEARCH_QUESTIONS_PER_SECTION = 1 +SECTION_SYNTHESIS_RETRY_CACHE_TTL_SECONDS = 6 * 60 * 60 def _create_blog_post_generation_context( @@ -297,6 +312,11 @@ def populate_research_links_for_question_from_exa( months_back=months_back, ) + # If Exa returned no links for this question, nothing will trigger scrape/analyze kicks. + # This "kick" is safe (it will only queue synthesis when the overall blog post is ready). + if num_links_upserted == 0: + maybe_queue_section_content_synthesis_for_blog_post(blog_post_id=blog_post.id) + return num_links_upserted @@ -403,6 +423,7 @@ def analyze_research_link_content(*, research_link_id: int) -> int: Step 4b: For a single research link (that already has content), generate: - a general page summary - a blog-post-contextual summary for the research question/section + - an answer to the research question (answer_to_question) Returns: number of fields updated on the research link. """ @@ -434,16 +455,25 @@ def analyze_research_link_content(*, research_link_id: int) -> int: blog_post_id=blog_post.id, url=url, ) + research_link.date_analyzed = timezone.now() + research_link.save(update_fields=["date_analyzed"]) + maybe_queue_section_content_synthesis_for_blog_post(blog_post_id=blog_post.id) return 0 should_run_general_summary = not (research_link.general_summary or "").strip() should_run_contextual_summary = not (research_link.summary_for_question_research or "").strip() - if not should_run_general_summary and not should_run_contextual_summary: + should_run_answer_to_question = not (research_link.answer_to_question or "").strip() + if ( + not should_run_general_summary + and not should_run_contextual_summary + and not should_run_answer_to_question + ): logger.info( "[ContentGenerator] Research link already analyzed; skipping", research_link_id=research_link.id, blog_post_id=blog_post.id, ) + maybe_queue_section_content_synthesis_for_blog_post(blog_post_id=blog_post.id) return 0 webpage_content = WebPageContent( @@ -454,53 +484,50 @@ def analyze_research_link_content(*, research_link_id: int) -> int: update_fields: list[str] = [] - if should_run_general_summary: - general_summary_agent = create_general_research_link_summary_agent() - general_summary_result = run_agent_synchronously( - general_summary_agent, - "Summarize this page.", - deps=webpage_content, - function_name="analyze_research_link_content.general_summary", - model_name="GeneratedBlogPostResearchLink", - ) - research_link.general_summary = (general_summary_result.output.summary or "").strip() - update_fields.append("general_summary") + title_suggestion = blog_post.title_suggestion + if not title_suggestion: + raise ValueError(f"GeneratedBlogPost missing title_suggestion: {blog_post.id}") - if should_run_contextual_summary: - title_suggestion = blog_post.title_suggestion - if not title_suggestion: - raise ValueError(f"GeneratedBlogPost missing title_suggestion: {blog_post.id}") + content_type_to_use = title_suggestion.content_type or ContentType.SHARING + blog_post_generation_context = _create_blog_post_generation_context( + title_suggestion=title_suggestion, + content_type_to_use=content_type_to_use, + ) - content_type_to_use = title_suggestion.content_type or ContentType.SHARING - blog_post_generation_context = _create_blog_post_generation_context( - title_suggestion=title_suggestion, - content_type_to_use=content_type_to_use, - ) + section_title = (getattr(research_question.section, "title", "") or "").strip() + research_question_text = (research_question.question or "").strip() - section_title = (getattr(research_question.section, "title", "") or "").strip() - research_question_text = (research_question.question or "").strip() + analysis_agent = create_research_link_analysis_agent() + analysis_deps = ResearchLinkContextualSummaryContext( + url=url, + web_page_content=webpage_content, + blog_post_generation_context=blog_post_generation_context, + blog_post_title=(blog_post.title or title_suggestion.title or "").strip(), + section_title=section_title, + research_question=research_question_text, + ) + analysis_result = run_agent_synchronously( + analysis_agent, + "Analyze this page for blog-post research.", + deps=analysis_deps, + function_name="analyze_research_link_content.research_link_analysis", + model_name="GeneratedBlogPostResearchLink", + ) - contextual_summary_agent = create_contextual_research_link_summary_agent() - contextual_summary_deps = ResearchLinkContextualSummaryContext( - url=url, - web_page_content=webpage_content, - blog_post_generation_context=blog_post_generation_context, - blog_post_title=(blog_post.title or title_suggestion.title or "").strip(), - section_title=section_title, - research_question=research_question_text, - ) - contextual_summary_result = run_agent_synchronously( - contextual_summary_agent, - "Summarize this page specifically to help answer the research question for the blog post section.", # noqa: E501 - deps=contextual_summary_deps, - function_name="analyze_research_link_content.contextual_summary", - model_name="GeneratedBlogPostResearchLink", - ) + if should_run_general_summary: + research_link.general_summary = (analysis_result.output.general_summary or "").strip() + update_fields.append("general_summary") + + if should_run_contextual_summary: research_link.summary_for_question_research = ( - contextual_summary_result.output.summary or "" + analysis_result.output.summary_for_question_research or "" ).strip() update_fields.append("summary_for_question_research") + if should_run_answer_to_question: + research_link.answer_to_question = (analysis_result.output.answer_to_question or "").strip() + update_fields.append("answer_to_question") + research_link.date_analyzed = timezone.now() update_fields.append("date_analyzed") @@ -515,6 +542,8 @@ def analyze_research_link_content(*, research_link_id: int) -> int: url=url, ) + maybe_queue_section_content_synthesis_for_blog_post(blog_post_id=blog_post.id) + return len(set(update_fields)) @@ -583,6 +612,9 @@ def generate_research_questions_for_section(*, section_id: int) -> list[int]: ) ) + if settings.DEBUG: + questions_to_create = questions_to_create[:LOCAL_MAX_RESEARCH_QUESTIONS_PER_SECTION] + created_questions = GeneratedBlogPostResearchQuestion.objects.bulk_create(questions_to_create) created_question_ids = [ created_question.id for created_question in created_questions if created_question.id @@ -595,4 +627,637 @@ def generate_research_questions_for_section(*, section_id: int) -> list[int]: num_questions_created=len(created_question_ids), ) + # If no questions were created, nothing else will trigger Exa/scrape/analysis tasks. + # In that case, kick section synthesis so the pipeline can still proceed. + if not created_question_ids: + maybe_queue_section_content_synthesis_for_blog_post(blog_post_id=blog_post.id) + return created_question_ids + + +def _build_research_questions_with_answered_links_for_section( + *, section: GeneratedBlogPostSection +) -> list[ResearchQuestionWithAnsweredLinks]: + research_questions_with_answered_links: list[ResearchQuestionWithAnsweredLinks] = [] + + section_questions = list(section.research_questions.all()) + for research_question in section_questions: + question_text = (research_question.question or "").strip() + if not question_text: + continue + + research_links = list(research_question.research_links.all()) + answered_links = [ + research_link + for research_link in research_links + if (research_link.answer_to_question or "").strip() + ] + + research_link_snippets = [] + if answered_links: + research_link_snippets = [ + ResearchLinkAnswerSnippet( + summary_for_question_research=( + (research_link.summary_for_question_research or "").strip() + ), + general_summary=(research_link.general_summary or "").strip(), + answer_to_question=(research_link.answer_to_question or "").strip(), + ) + for research_link in answered_links + ] + + research_questions_with_answered_links.append( + ResearchQuestionWithAnsweredLinks( + question=question_text, + research_links=research_link_snippets, + ) + ) + + return research_questions_with_answered_links + + +def _build_prior_section_contexts( + *, sections_in_order: list[GeneratedBlogPostSection], current_section_order: int +) -> list[PriorSectionContext]: + prior_sections: list[PriorSectionContext] = [] + for section in sections_in_order: + if section.order >= current_section_order: + continue + if (section.title or "").strip() in NON_RESEARCH_SECTION_TITLES: + continue + content = (section.content or "").strip() + if not content: + continue + prior_sections.append( + PriorSectionContext(title=(section.title or "").strip(), content=content) + ) + return prior_sections + + +def synthesize_section_contents_for_blog_post(*, blog_post_id: int) -> int: + """ + Step 5: Synthesize content for each middle section sequentially (excluding Introduction/Conclusion). + + Context passed to the model: + - Project details + - Title suggestion details + - Current section info + - Research link results (only for links with non-empty answer_to_question) + - Other section titles + - Section order + previous section content for coherence + """ + blog_post = ( + GeneratedBlogPost.objects.select_related( + "title_suggestion", + "project", + ) + .prefetch_related( + "blog_post_sections__research_questions__research_links", + ) + .filter(id=blog_post_id) + .first() + ) + if not blog_post: + raise ValueError(f"GeneratedBlogPost not found: {blog_post_id}") + + title_suggestion = blog_post.title_suggestion + if not title_suggestion: + raise ValueError(f"GeneratedBlogPost missing title_suggestion: {blog_post_id}") + + content_type_to_use = title_suggestion.content_type or ContentType.SHARING + blog_post_generation_context = _create_blog_post_generation_context( + title_suggestion=title_suggestion, + content_type_to_use=content_type_to_use, + ) + + sections_in_order = sorted( + list(blog_post.blog_post_sections.all()), + key=lambda section: (section.order, section.id), + ) + + all_section_titles = [ + (section.title or "").strip() + for section in sections_in_order + if (section.title or "").strip() + ] + total_sections = len(sections_in_order) + + middle_sections_in_order = [ + section + for section in sections_in_order + if (section.title or "").strip() not in NON_RESEARCH_SECTION_TITLES + ] + total_research_sections = len(middle_sections_in_order) + + section_agent = create_generate_blog_post_section_content_agent( + content_type=content_type_to_use + ) + + num_sections_generated = 0 + for research_section_index, section in enumerate(middle_sections_in_order, start=1): + section_title = (section.title or "").strip() + if not section_title: + continue + + existing_content = (section.content or "").strip() + if existing_content: + continue + + research_questions = _build_research_questions_with_answered_links_for_section( + section=section + ) + prior_sections = _build_prior_section_contexts( + sections_in_order=sections_in_order, + current_section_order=section.order, + ) + + section_context = BlogPostSectionContentGenerationContext( + blog_post_generation_context=blog_post_generation_context, + blog_post_title=(blog_post.title or title_suggestion.title or "").strip(), + section_title=section_title, + section_order=section.order, + total_sections=total_sections, + research_section_order=research_section_index, + total_research_sections=total_research_sections, + other_section_titles=all_section_titles, + previous_sections=prior_sections, + research_questions=research_questions, + ) + + prompt = f"Write the section body content for: {section_title}" + generation_result = run_agent_synchronously( + section_agent, + prompt, + deps=section_context, + function_name="synthesize_section_contents_for_blog_post.section_content", + model_name="GeneratedBlogPostSection", + ) + + generated_schema: GeneratedBlogPostSectionContentSchema | None = ( + generation_result.output if generation_result and generation_result.output else None + ) + generated_content = (generated_schema.content if generated_schema else "").strip() + if not generated_content: + logger.warning( + "[ContentGenerator] Section content generation returned empty content", + blog_post_id=blog_post.id, + section_id=section.id, + section_title=section_title, + ) + continue + + section.content = generated_content + section.save(update_fields=["content"]) + num_sections_generated += 1 + + logger.info( + "[ContentGenerator] Section content synthesized", + blog_post_id=blog_post.id, + section_id=section.id, + section_title=section_title, + section_order=section.order, + research_section_order=research_section_index, + total_research_sections=total_research_sections, + content_length=len(generated_content), + ) + + maybe_queue_intro_conclusion_generation_for_blog_post(blog_post_id=blog_post.id) + maybe_queue_section_content_synthesis_retry_for_blog_post(blog_post_id=blog_post.id) + return num_sections_generated + + +def _get_section_synthesis_retry_cache_key(*, blog_post_id: int) -> str: + return f"content_generator:section_synthesis_retry_count:{blog_post_id}" + + +def maybe_queue_section_content_synthesis_retry_for_blog_post(*, blog_post_id: int) -> bool: + """ + Retry mechanism for Step 5: + + If research is "done enough" (all links are in a terminal analyzed/attempted state), + but some middle sections still have empty content (e.g. a model returned empty output + or a task was missed), re-queue section synthesis a bounded number of times. + """ + blog_post = ( + GeneratedBlogPost.objects.prefetch_related("blog_post_sections") + .filter(id=blog_post_id) + .first() + ) + if not blog_post: + return False + + sections_in_order = _get_sections_in_order_for_blog_post(blog_post) + middle_sections = [ + section + for section in sections_in_order + if (section.title or "").strip() not in NON_RESEARCH_SECTION_TITLES + ] + has_any_middle_section_missing_content = any( + not (section.content or "").strip() for section in middle_sections + ) + if not has_any_middle_section_missing_content: + return False + + # Only retry when link processing is "complete" (including failures). + # If there are links still being processed, let the normal kicks handle it. + links_queryset = GeneratedBlogPostResearchLink.objects.filter(blog_post_id=blog_post_id) + has_any_pending_link = links_queryset.filter(date_analyzed__isnull=True).exists() + if has_any_pending_link: + return False + + max_retries = 5 if settings.DEBUG else 2 + retry_cache_key = _get_section_synthesis_retry_cache_key(blog_post_id=blog_post_id) + retry_count = cache.get(retry_cache_key, 0) or 0 + if retry_count >= max_retries: + logger.warning( + "[ContentGenerator] Not retrying section synthesis; max retries reached", + blog_post_id=blog_post_id, + retry_count=retry_count, + max_retries=max_retries, + num_middle_sections=len(middle_sections), + num_links_total=links_queryset.count(), + ) + return False + + cache.set(retry_cache_key, retry_count + 1, timeout=SECTION_SYNTHESIS_RETRY_CACHE_TTL_SECONDS) + async_task( + "core.content_generator.tasks.synthesize_section_contents_for_blog_post_task", + blog_post_id, + group="Synthesize Section Content (Retry)", + ) + logger.info( + "[ContentGenerator] Queued section content synthesis retry task", + blog_post_id=blog_post_id, + retry_count=retry_count + 1, + max_retries=max_retries, + num_middle_sections=len(middle_sections), + num_links_total=links_queryset.count(), + ) + return True + + +def maybe_queue_section_content_synthesis_for_blog_post(*, blog_post_id: int) -> bool: + """ + Queue Step 5 once research work is in a terminal state for all required inputs. + + This is intentionally best-effort + idempotent: + - It may queue more than once, but the synthesis step skips sections that already have content. + """ + blog_post = ( + GeneratedBlogPost.objects.prefetch_related( + "blog_post_sections__research_questions__research_links" + ) + .filter(id=blog_post_id) + .first() + ) + if not blog_post: + return False + + sections_in_order = _get_sections_in_order_for_blog_post(blog_post) + middle_sections_missing_content = [ + section + for section in sections_in_order + if (section.title or "").strip() not in NON_RESEARCH_SECTION_TITLES + and not (section.content or "").strip() + ] + + num_pending_links = 0 + num_scrape_tasks_queued = 0 + num_analyze_tasks_queued = 0 + + for section in middle_sections_missing_content: + section_questions = list(section.research_questions.all()) + for research_question in section_questions: + research_links = list(research_question.research_links.all()) + for research_link in research_links: + # Terminal state: we attempted analysis for this link (even if it failed). + if research_link.date_analyzed is not None: + continue + + num_pending_links += 1 + + link_content = (research_link.content or "").strip() + if not link_content: + # If we haven't scraped content yet (or it failed previously but wasn't marked), + # re-queue a scrape attempt. The scrape task will always queue analysis next. + async_task( + "core.content_generator.tasks.scrape_research_link_content_task", + research_link.id, + group="Scrape Research Links (Retry/Kick)", + ) + num_scrape_tasks_queued += 1 + continue + + # Content exists, but analysis hasn't run yet: queue AI augmentation. + async_task( + "core.content_generator.tasks.analyze_research_link_content_task", + research_link.id, + group="Analyze Research Links (Retry/Kick)", + ) + num_analyze_tasks_queued += 1 + + if num_pending_links > 0: + logger.info( + "[ContentGenerator] Not queuing section synthesis; research links still pending", + blog_post_id=blog_post_id, + num_middle_sections_missing_content=len(middle_sections_missing_content), + num_pending_links=num_pending_links, + num_scrape_tasks_queued=num_scrape_tasks_queued, + num_analyze_tasks_queued=num_analyze_tasks_queued, + ) + return False + + async_task( + "core.content_generator.tasks.synthesize_section_contents_for_blog_post_task", + blog_post_id, + group="Synthesize Section Content", + ) + logger.info( + "[ContentGenerator] Queued section content synthesis task", + blog_post_id=blog_post_id, + num_middle_sections_missing_content=len(middle_sections_missing_content), + ) + return True + + +def _get_sections_in_order_for_blog_post( + blog_post: GeneratedBlogPost, +) -> list[GeneratedBlogPostSection]: + return sorted( + list(blog_post.blog_post_sections.all()), + key=lambda section: (section.order, section.id), + ) + + +def generate_intro_and_conclusion_for_blog_post(*, blog_post_id: int) -> int: + """ + Step 6: Generate Introduction + Conclusion in a single model call. + + Runs only when all middle sections have content. + """ + blog_post = ( + GeneratedBlogPost.objects.select_related( + "title_suggestion", + "project", + ) + .prefetch_related("blog_post_sections") + .filter(id=blog_post_id) + .first() + ) + if not blog_post: + raise ValueError(f"GeneratedBlogPost not found: {blog_post_id}") + + title_suggestion = blog_post.title_suggestion + if not title_suggestion: + raise ValueError(f"GeneratedBlogPost missing title_suggestion: {blog_post_id}") + + content_type_to_use = title_suggestion.content_type or ContentType.SHARING + blog_post_generation_context = _create_blog_post_generation_context( + title_suggestion=title_suggestion, + content_type_to_use=content_type_to_use, + ) + + sections_in_order = _get_sections_in_order_for_blog_post(blog_post) + section_titles_in_order = [ + (section.title or "").strip() + for section in sections_in_order + if (section.title or "").strip() + ] + + intro_section = next( + ( + section + for section in sections_in_order + if (section.title or "").strip() == INTRODUCTION_SECTION_TITLE + ), + None, + ) + conclusion_section = next( + ( + section + for section in sections_in_order + if (section.title or "").strip() == CONCLUSION_SECTION_TITLE + ), + None, + ) + if not intro_section or not conclusion_section: + raise ValueError(f"Blog post is missing Introduction/Conclusion sections: {blog_post_id}") + + should_generate_intro = not (intro_section.content or "").strip() + should_generate_conclusion = not (conclusion_section.content or "").strip() + if not should_generate_intro and not should_generate_conclusion: + return 0 + + middle_sections = [ + section + for section in sections_in_order + if (section.title or "").strip() not in NON_RESEARCH_SECTION_TITLES + ] + has_any_middle_section_missing_content = any( + not (section.content or "").strip() for section in middle_sections + ) + if has_any_middle_section_missing_content: + logger.info( + "[ContentGenerator] Skipping intro/conclusion generation; middle sections not ready", + blog_post_id=blog_post.id, + num_middle_sections=len(middle_sections), + ) + return 0 + + existing_sections_context = [ + PriorSectionContext( + title=(section.title or "").strip(), + content=(section.content or "").strip(), + ) + for section in sections_in_order + if (section.title or "").strip() and (section.content or "").strip() + ] + + intro_conclusion_context = BlogPostIntroConclusionGenerationContext( + blog_post_generation_context=blog_post_generation_context, + blog_post_title=(blog_post.title or title_suggestion.title or "").strip(), + section_titles_in_order=section_titles_in_order, + sections_in_order=existing_sections_context, + ) + + agent = create_generate_blog_post_intro_conclusion_agent(content_type=content_type_to_use) + result = run_agent_synchronously( + agent, + "Write the Introduction and Conclusion for this blog post.", + deps=intro_conclusion_context, + function_name="generate_intro_and_conclusion_for_blog_post.intro_conclusion", + model_name="GeneratedBlogPostSection", + ) + + output: GeneratedBlogPostIntroConclusionSchema | None = ( + result.output if result and result.output else None + ) + if not output: + return 0 + + num_sections_updated = 0 + if should_generate_intro: + introduction_content = (output.introduction or "").strip() + if introduction_content: + intro_section.content = introduction_content + intro_section.save(update_fields=["content"]) + num_sections_updated += 1 + + if should_generate_conclusion: + conclusion_content = (output.conclusion or "").strip() + if conclusion_content: + conclusion_section.content = conclusion_content + conclusion_section.save(update_fields=["content"]) + num_sections_updated += 1 + + logger.info( + "[ContentGenerator] Intro/conclusion generated", + blog_post_id=blog_post.id, + intro_generated=bool((intro_section.content or "").strip()), + conclusion_generated=bool((conclusion_section.content or "").strip()), + num_sections_updated=num_sections_updated, + ) + + maybe_populate_generated_blog_post_content(blog_post_id=blog_post.id) + return num_sections_updated + + +def maybe_queue_intro_conclusion_generation_for_blog_post(*, blog_post_id: int) -> bool: + """ + Queue Step 6 only when all middle sections have content. + + Best-effort + idempotent: if it queues multiple times, the generation step skips when already present. + """ + blog_post = ( + GeneratedBlogPost.objects.prefetch_related("blog_post_sections") + .filter(id=blog_post_id) + .first() + ) + if not blog_post: + return False + + sections_in_order = _get_sections_in_order_for_blog_post(blog_post) + middle_sections = [ + section + for section in sections_in_order + if (section.title or "").strip() not in NON_RESEARCH_SECTION_TITLES + ] + + if any(not (section.content or "").strip() for section in middle_sections): + return False + + async_task( + "core.content_generator.tasks.generate_intro_and_conclusion_for_blog_post_task", + blog_post_id, + group="Generate Intro and Conclusion", + ) + logger.info( + "[ContentGenerator] Queued intro/conclusion generation task", + blog_post_id=blog_post_id, + num_middle_sections=len(middle_sections), + ) + return True + + +def _build_full_blog_post_markdown(*, blog_post: GeneratedBlogPost) -> str: + blog_post_title = (blog_post.title or "").strip() + if not blog_post_title: + return "" + + sections_in_order = _get_sections_in_order_for_blog_post(blog_post) + markdown_chunks = [f"# {blog_post_title}", ""] + + for section in sections_in_order: + section_title = (section.title or "").strip() + section_content = (section.content or "").strip() + if not section_title or not section_content: + continue + + markdown_chunks.append(f"## {section_title}") + markdown_chunks.append("") + markdown_chunks.append(section_content) + markdown_chunks.append("") + + full_markdown = "\n".join(markdown_chunks).strip() + "\n" + return full_markdown + + +def populate_generated_blog_post_content(*, blog_post_id: int) -> bool: + """ + Step 7: Populate GeneratedBlogPost.content from the generated section contents. + + Runs only when: + - All sections (including Introduction + Conclusion) have non-empty content + - GeneratedBlogPost.content is currently empty + """ + blog_post = ( + GeneratedBlogPost.objects.prefetch_related("blog_post_sections") + .filter(id=blog_post_id) + .first() + ) + if not blog_post: + raise ValueError(f"GeneratedBlogPost not found: {blog_post_id}") + + if (blog_post.content or "").strip(): + return False + + sections_in_order = _get_sections_in_order_for_blog_post(blog_post) + if any(not (section.content or "").strip() for section in sections_in_order): + logger.info( + "[ContentGenerator] Skipping blog_post.content population; not all sections have content", + blog_post_id=blog_post.id, + num_sections=len(sections_in_order), + ) + return False + + full_markdown = _build_full_blog_post_markdown(blog_post=blog_post) + if not full_markdown.strip(): + logger.warning( + "[ContentGenerator] Skipping blog_post.content population; built markdown is empty", + blog_post_id=blog_post.id, + ) + return False + + blog_post.content = full_markdown + blog_post.save(update_fields=["content"]) + + logger.info( + "[ContentGenerator] Populated GeneratedBlogPost.content from sections", + blog_post_id=blog_post.id, + content_length=len(full_markdown), + ) + return True + + +def maybe_populate_generated_blog_post_content(*, blog_post_id: int) -> bool: + """ + Queue Step 7 when the whole pipeline is done. + + Best-effort + idempotent: population skips if blog_post.content is already non-empty. + """ + blog_post = ( + GeneratedBlogPost.objects.prefetch_related("blog_post_sections") + .filter(id=blog_post_id) + .first() + ) + if not blog_post: + return False + + if (blog_post.content or "").strip(): + return False + + sections_in_order = _get_sections_in_order_for_blog_post(blog_post) + if any(not (section.content or "").strip() for section in sections_in_order): + return False + + async_task( + "core.content_generator.tasks.populate_generated_blog_post_content_task", + blog_post_id, + group="Finalize Generated Blog Post Content", + ) + logger.info( + "[ContentGenerator] Queued blog_post.content population task", + blog_post_id=blog_post_id, + num_sections=len(sections_in_order), + ) + return True diff --git a/core/content_generator/tasks.py b/core/content_generator/tasks.py index ca432a6..5f2463c 100644 --- a/core/content_generator/tasks.py +++ b/core/content_generator/tasks.py @@ -1,17 +1,23 @@ from __future__ import annotations +from django.conf import settings from django_q.tasks import async_task from core.content_generator.pipeline import ( analyze_research_link_content, + generate_intro_and_conclusion_for_blog_post, generate_research_questions_for_section, + populate_generated_blog_post_content, populate_research_links_for_question_from_exa, scrape_research_link_content, + synthesize_section_contents_for_blog_post, ) from tuxseo.utils import get_tuxseo_logger logger = get_tuxseo_logger(__name__) +LOCAL_NUM_EXA_RESULTS_PER_QUESTION = 2 + def populate_research_links_for_question_from_exa_task( research_question_id: int, @@ -21,15 +27,20 @@ def populate_research_links_for_question_from_exa_task( """ Populate Exa research links for one research question. """ + num_results_per_question_to_use = ( + LOCAL_NUM_EXA_RESULTS_PER_QUESTION if settings.DEBUG else num_results_per_question + ) num_links = populate_research_links_for_question_from_exa( research_question_id=research_question_id, - num_results_per_question=num_results_per_question, + num_results_per_question=num_results_per_question_to_use, months_back=months_back, ) logger.info( "[ContentGenerator Tasks] Populated Exa research links for question", research_question_id=research_question_id, num_links_upserted=num_links, + num_results_per_question=num_results_per_question_to_use, + months_back=months_back, ) return f"Populated {num_links} research links for research question {research_question_id}" @@ -37,7 +48,12 @@ def populate_research_links_for_question_from_exa_task( def scrape_research_link_content_task(research_link_id: int): """ Fetch research link content using Jina Reader. - If content is successfully fetched, queue the analysis task. + Always queue the analysis task after the scrape attempt. + + Rationale: + - Jina can return empty content for some URLs (parsing failures). + - We still want the pipeline to progress and eventually synthesize sections using + whatever research succeeded, rather than stalling forever on a few bad links. """ did_fetch_content = scrape_research_link_content(research_link_id=research_link_id) logger.info( @@ -45,12 +61,11 @@ def scrape_research_link_content_task(research_link_id: int): research_link_id=research_link_id, did_fetch_content=did_fetch_content, ) - if did_fetch_content: - async_task( - "core.content_generator.tasks.analyze_research_link_content_task", - research_link_id, - group="Analyze Research Links", - ) + async_task( + "core.content_generator.tasks.analyze_research_link_content_task", + research_link_id, + group="Analyze Research Links", + ) return f"Scraped research link {research_link_id} (did_fetch_content={did_fetch_content})" @@ -59,6 +74,7 @@ def analyze_research_link_content_task(research_link_id: int): Analyze a research link that has already been scraped: - generate general summary - generate blog-post contextual summary for the research question/section + - generate an answer to the research question """ num_fields_updated = analyze_research_link_content(research_link_id=research_link_id) logger.info( @@ -69,6 +85,48 @@ def analyze_research_link_content_task(research_link_id: int): return f"Analyzed research link {research_link_id} (updated_fields={num_fields_updated})" +def synthesize_section_contents_for_blog_post_task(blog_post_id: int): + """ + Synthesize the content for each middle section sequentially (excluding Introduction/Conclusion). + """ + num_sections_generated = synthesize_section_contents_for_blog_post(blog_post_id=blog_post_id) + logger.info( + "[ContentGenerator Tasks] Synthesized section contents for blog post", + blog_post_id=blog_post_id, + num_sections_generated=num_sections_generated, + ) + return f"Synthesized {num_sections_generated} section(s) for blog post {blog_post_id}" + + +def generate_intro_and_conclusion_for_blog_post_task(blog_post_id: int): + """ + Generate Introduction + Conclusion in one AI call. + Only runs once all middle sections have content. + """ + num_sections_updated = generate_intro_and_conclusion_for_blog_post(blog_post_id=blog_post_id) + logger.info( + "[ContentGenerator Tasks] Generated intro and conclusion for blog post", + blog_post_id=blog_post_id, + num_sections_updated=num_sections_updated, + ) + return ( + f"Generated intro/conclusion (updated={num_sections_updated}) for blog post {blog_post_id}" + ) + + +def populate_generated_blog_post_content_task(blog_post_id: int): + """ + Populate GeneratedBlogPost.content from the generated sections. + """ + did_populate = populate_generated_blog_post_content(blog_post_id=blog_post_id) + logger.info( + "[ContentGenerator Tasks] Populated GeneratedBlogPost.content", + blog_post_id=blog_post_id, + did_populate=did_populate, + ) + return f"Populated GeneratedBlogPost.content for blog post {blog_post_id} (did_populate={did_populate})" + + def generate_research_questions_for_section_task(section_id: int): """ Generate research questions for one section, then queue Exa research link tasks for each diff --git a/core/migrations/0050_backlink_generatedblogpostresearchquestion_and_more.py b/core/migrations/0050_backlink_generatedblogpostresearchquestion_and_more.py deleted file mode 100644 index 8e12c27..0000000 --- a/core/migrations/0050_backlink_generatedblogpostresearchquestion_and_more.py +++ /dev/null @@ -1,95 +0,0 @@ -# Generated by Django 5.2.8 on 2025-12-26 21:43 - -import django.db.models.deletion -import pgvector.django.vector -import uuid -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('core', '0049_alter_emailsent_email_type'), - ] - - operations = [ - migrations.CreateModel( - name='Backlink', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('uuid', models.UUIDField(default=uuid.uuid4, editable=False)), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('deleted_at', models.DateTimeField(blank=True, null=True)), - ('linked_from_project_page', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='backlinks_from', to='core.project')), - ('linked_to_project_page', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='backlinks_to', to='core.project')), - ('linking_from_blog_post', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='backlinks', to='core.generatedblogpost')), - ('linkning_to_project_page', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='backlinks', to='core.projectpage')), - ], - options={ - 'abstract': False, - }, - ), - migrations.CreateModel( - name='GeneratedBlogPostResearchQuestion', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('uuid', models.UUIDField(default=uuid.uuid4, editable=False)), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('deleted_at', models.DateTimeField(blank=True, null=True)), - ('question', models.CharField(max_length=250)), - ('blog_post', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='research_questions', to='core.generatedblogpost')), - ], - options={ - 'abstract': False, - }, - ), - migrations.CreateModel( - name='GeneratedBlogPostResearchLink', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('uuid', models.UUIDField(default=uuid.uuid4, editable=False)), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('deleted_at', models.DateTimeField(blank=True, null=True)), - ('url', models.URLField()), - ('title', models.CharField(blank=True, default='', max_length=500)), - ('author', models.CharField(blank=True, default='', max_length=250)), - ('description', models.TextField(blank=True, default='')), - ('markdown_content', models.TextField(blank=True, default='')), - ('question', models.CharField(max_length=250)), - ('date_scraped', models.DateTimeField(blank=True, null=True)), - ('date_analyzed', models.DateTimeField(blank=True, null=True)), - ('summary', models.TextField(blank=True)), - ('embedding', pgvector.django.vector.VectorField(blank=True, default=None, dimensions=1024, null=True)), - ('blog_post', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='research_links', to='core.generatedblogpost')), - ('research_question', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='research_links', to='core.generatedblogpostresearchquestion')), - ], - options={ - 'abstract': False, - }, - ), - migrations.CreateModel( - name='GeneratedBlogPostSection', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('uuid', models.UUIDField(default=uuid.uuid4, editable=False)), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('deleted_at', models.DateTimeField(blank=True, null=True)), - ('title', models.CharField(max_length=250)), - ('content', models.TextField(blank=True, default='')), - ('order', models.IntegerField(default=0)), - ('blog_post', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='blog_post_sections', to='core.generatedblogpost')), - ], - options={ - 'abstract': False, - }, - ), - migrations.AddField( - model_name='generatedblogpostresearchquestion', - name='section', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='research_questions', to='core.generatedblogpostsection'), - ), - ] diff --git a/core/migrations/0051_rename_markdown_content_generatedblogpostresearchlink_content_and_more.py b/core/migrations/0051_rename_markdown_content_generatedblogpostresearchlink_content_and_more.py deleted file mode 100644 index dde01ab..0000000 --- a/core/migrations/0051_rename_markdown_content_generatedblogpostresearchlink_content_and_more.py +++ /dev/null @@ -1,44 +0,0 @@ -# Generated by Django 5.2.9 on 2025-12-27 12:14 - -import django.utils.timezone -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('core', '0050_backlink_generatedblogpostresearchquestion_and_more'), - ] - - operations = [ - migrations.RenameField( - model_name='generatedblogpostresearchlink', - old_name='markdown_content', - new_name='content', - ), - migrations.RenameField( - model_name='generatedblogpostresearchlink', - old_name='summary', - new_name='general_summary', - ), - migrations.RemoveField( - model_name='generatedblogpostresearchlink', - name='question', - ), - migrations.AddField( - model_name='generatedblogpostresearchlink', - name='published_date', - field=models.DateTimeField(blank=True, null=True), - ), - migrations.AddField( - model_name='generatedblogpostresearchlink', - name='summary_for_question_research', - field=models.TextField(blank=True, default=''), - ), - migrations.AlterField( - model_name='generatedblogpostresearchlink', - name='date_scraped', - field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), - preserve_default=False, - ), - ] diff --git a/core/models.py b/core/models.py index 8ac9f57..0005af3 100644 --- a/core/models.py +++ b/core/models.py @@ -1249,7 +1249,8 @@ class GeneratedBlogPostResearchLink(BaseModel): date_analyzed = models.DateTimeField(null=True, blank=True) summary_for_question_research = models.TextField(blank=True, default="") general_summary = models.TextField(blank=True) - embedding = VectorField(dimensions=1024, default=None, null=True, blank=True) + general_summary_embedding = VectorField(dimensions=1024, default=None, null=True, blank=True) + answer_to_question = models.TextField(blank=True, default="") class ProjectPage(BaseModel): diff --git a/core/urls.py b/core/urls.py index 8df36d2..b90da66 100644 --- a/core/urls.py +++ b/core/urls.py @@ -56,6 +56,11 @@ views.GeneratedBlogPostDetailView.as_view(), name="generated_blog_post_detail", ), + path( + "project//title-suggestion//research/", + views.BlogPostResearchProcessView.as_view(), + name="blog_post_research_process", + ), path( "project//post//download-pdf/", views.download_blog_post_pdf, diff --git a/core/views.py b/core/views.py index 2524cfa..21d30c2 100644 --- a/core/views.py +++ b/core/views.py @@ -27,6 +27,7 @@ from core.models import ( AutoSubmissionSetting, BlogPost, + BlogPostTitleSuggestion, Competitor, GeneratedBlogPost, KeywordTrend, @@ -38,6 +39,7 @@ track_event, try_create_posthog_alias, ) +from core.utils import get_relevant_external_pages_for_blog_post from tuxseo.utils import get_tuxseo_logger stripe.api_key = settings.STRIPE_SECRET_KEY @@ -842,6 +844,7 @@ def get_queryset(self): def get_context_data(self, **kwargs): from urllib.parse import urlparse + from django.core.paginator import Paginator context = super().get_context_data(**kwargs) @@ -977,6 +980,213 @@ def get_context_data(self, **kwargs): return context +class BlogPostResearchProcessView(LoginRequiredMixin, DetailView): + model = BlogPostTitleSuggestion + template_name = "blog/blog_post_research_process.html" + context_object_name = "title_suggestion" + + def get_queryset(self): + return BlogPostTitleSuggestion.objects.filter( + project__profile=self.request.user.profile, + project__pk=self.kwargs["project_pk"], + ) + + def _get_generated_blog_posts(self, title_suggestion: BlogPostTitleSuggestion): + return ( + title_suggestion.generated_blog_posts.select_related("project", "title_suggestion") + .prefetch_related( + "blog_post_sections__research_questions__research_links", + "research_questions__research_links", + ) + .order_by("-id") + ) + + def _build_generated_blog_posts_data(self, generated_blog_posts): + generated_blog_posts_data = [] + + for generated_blog_post in generated_blog_posts: + sections = sorted( + list(generated_blog_post.blog_post_sections.all()), + key=lambda section: (section.order, section.id), + ) + blog_level_questions = sorted( + [ + question + for question in generated_blog_post.research_questions.all() + if not question.section_id + ], + key=lambda question: question.id, + ) + + sections_data = [] + for section in sections: + section_questions = sorted( + list(section.research_questions.all()), + key=lambda question: question.id, + ) + section_questions_data = [] + for section_question in section_questions: + research_links = sorted( + list(section_question.research_links.all()), + key=lambda research_link: research_link.id, + ) + section_questions_data.append( + { + "id": section_question.id, + "question": section_question.question, + "links": research_links, + } + ) + + sections_data.append( + { + "id": section.id, + "order": section.order, + "title": section.title, + "content": section.content or "", + "questions": section_questions_data, + } + ) + + blog_level_questions_data = [] + for blog_level_question in blog_level_questions: + research_links = sorted( + list(blog_level_question.research_links.all()), + key=lambda research_link: research_link.id, + ) + blog_level_questions_data.append( + { + "id": blog_level_question.id, + "question": blog_level_question.question, + "links": research_links, + } + ) + + generated_blog_posts_data.append( + { + "id": generated_blog_post.id, + "project_id": generated_blog_post.project_id, + "title_suggestion_id": generated_blog_post.title_suggestion_id, + "title": generated_blog_post.title, + "description": generated_blog_post.description, + "slug": generated_blog_post.slug, + "tags": generated_blog_post.tags, + "posted": generated_blog_post.posted, + "date_posted": generated_blog_post.date_posted, + "content_length": len(generated_blog_post.content or ""), + "sections": sections_data, + "blog_level_questions": blog_level_questions_data, + } + ) + + return generated_blog_posts_data + + def _get_internal_links( + self, title_suggestion: BlogPostTitleSuggestion, should_compute_links: bool + ): + manually_selected_project_pages = list( + title_suggestion.project.project_pages.filter(always_use=True) + ) + if not should_compute_links: + return manually_selected_project_pages + + if not settings.JINA_READER_API_KEY: + return manually_selected_project_pages + + return title_suggestion.get_internal_links(max_pages=2) + + def _get_external_links( + self, title_suggestion: BlogPostTitleSuggestion, should_compute_links: bool + ): + if not should_compute_links: + return [] + + if not settings.JINA_READER_API_KEY: + return [] + + meta_description = title_suggestion.suggested_meta_description or "" + external_pages = get_relevant_external_pages_for_blog_post( + meta_description=meta_description, + exclude_project=title_suggestion.project, + max_pages=3, + ) + return list(external_pages) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + title_suggestion = self.object + project = title_suggestion.project + profile = self.request.user.profile + + should_compute_links = self.request.GET.get("compute_links") == "true" + + project_keywords = project.get_keywords() + title_suggestion.keywords_with_usage = [] + if title_suggestion.target_keywords: + for keyword_text in title_suggestion.target_keywords: + keyword_info = project_keywords.get( + keyword_text.lower(), + {"keyword": None, "in_use": False, "project_keyword_id": None}, + ) + title_suggestion.keywords_with_usage.append( + { + "text": keyword_text, + "keyword": keyword_info["keyword"], + "in_use": keyword_info["in_use"], + "project_keyword_id": keyword_info["project_keyword_id"], + } + ) + + generated_blog_posts = self._get_generated_blog_posts(title_suggestion) + generated_blog_posts_data = self._build_generated_blog_posts_data(generated_blog_posts) + + try: + keywords_to_use = title_suggestion.get_blog_post_keywords() + except (AttributeError, TypeError): + logger.warning( + "[BlogPostResearchProcessView] Failed to compute keywords_to_use", + title_suggestion_id=title_suggestion.id, + project_id=project.id, + exc_info=True, + ) + keywords_to_use = [] + + try: + internal_links = self._get_internal_links(title_suggestion, should_compute_links) + except (AttributeError, TypeError, ValueError): + logger.warning( + "[BlogPostResearchProcessView] Failed to compute internal_links", + title_suggestion_id=title_suggestion.id, + project_id=project.id, + should_compute_links=should_compute_links, + exc_info=True, + ) + internal_links = [] + + try: + external_links = self._get_external_links(title_suggestion, should_compute_links) + except (AttributeError, TypeError, ValueError): + logger.warning( + "[BlogPostResearchProcessView] Failed to compute external_links", + title_suggestion_id=title_suggestion.id, + project_id=project.id, + should_compute_links=should_compute_links, + exc_info=True, + ) + external_links = [] + + context["project"] = project + context["has_pro_subscription"] = profile.is_on_pro_plan + context["jina_api_key_configured"] = bool(settings.JINA_READER_API_KEY) + context["should_compute_links"] = should_compute_links + context["keywords_to_use"] = keywords_to_use + context["internal_links"] = internal_links or [] + context["external_links"] = external_links or [] + context["generated_blog_posts"] = generated_blog_posts_data + + return context + + class CompetitorBlogPostDetailView(LoginRequiredMixin, DetailView): model = Competitor template_name = "project/competitor_blog_post_detail.html" diff --git a/frontend/templates/blog/blog_post_research_process.html b/frontend/templates/blog/blog_post_research_process.html new file mode 100644 index 0000000..d180a54 --- /dev/null +++ b/frontend/templates/blog/blog_post_research_process.html @@ -0,0 +1,336 @@ +{% extends "base_project.html" %} +{% load static %} + +{% block meta %} +Research Process - {{ title_suggestion.title }} - TuxSEO +{% endblock meta %} + +{% block project_content %} +
+
+
+ + +

{{ title_suggestion.title }}

+ {% if title_suggestion.description %} +

{{ title_suggestion.description }}

+ {% endif %} +
+ +
+ {% if jina_api_key_configured %} + {% if should_compute_links %} + + Hide computed links + + {% else %} + + Compute links + + {% endif %} + {% else %} + + Link computation requires Jina API key + + {% endif %} +
+
+ +
+
+

Title Suggestion

+ +
+
+
Suggestion ID
+
{{ title_suggestion.id }}
+
+
+
Content type
+
{{ title_suggestion.content_type }}
+
+
+
Category
+
{{ title_suggestion.category }}
+
+
+
Created
+
{{ title_suggestion.created_at|date:"F j, Y g:i A" }}
+
+
+ + {% if title_suggestion.target_keywords %} +
+
Target keywords
+
+ {% for keyword_data in title_suggestion.keywords_with_usage %} + {% include "components/keyword_chip.html" with keyword=keyword_data.text project_id=project.id keyword_in_use=keyword_data.in_use %} + {% endfor %} +
+
+ {% endif %} + + {% if title_suggestion.suggested_meta_description %} +
+
Suggested meta description
+
+ {{ title_suggestion.suggested_meta_description }} +
+
+ {% endif %} + + {% if title_suggestion.prompt %} +
+
Prompt
+
{{ title_suggestion.prompt }}
+
+ {% endif %} +
+ +
+
+

Derived inputs

+
+ {% if should_compute_links %} + Computed links are enabled. + {% else %} + Computed links are disabled (fast mode). + {% endif %} +
+
+ +
+
+
Keywords to use ({{ keywords_to_use|length }})
+ {% if keywords_to_use %} +
+ {% for keyword_text in keywords_to_use %} + + {{ keyword_text }} + + {% endfor %} +
+ {% else %} +
No keywords computed.
+ {% endif %} +
+ +
+
Internal links ({{ internal_links|length }})
+ {% if internal_links %} +
+ + + + + + + + + + {% for project_page in internal_links %} + + + + + + {% endfor %} + +
TitleURLAlways use
{{ project_page.title }} + + {{ project_page.url }} + + {{ project_page.always_use|yesno:"Yes,No" }}
+
+ {% else %} +
No internal links available.
+ {% endif %} +
+ +
+
External links ({{ external_links|length }})
+ {% if external_links %} +
+ + + + + + + + + + {% for project_page in external_links %} + + + + + + {% endfor %} + +
ProjectTitleURL
{{ project_page.project.name }}{{ project_page.title }} + + {{ project_page.url }} + +
+
+ {% else %} +
No external links available.
+ {% endif %} +
+
+
+ +
+

Generated blog posts ({{ generated_blog_posts|length }})

+ + {% if generated_blog_posts %} +
+ {% for blog_post in generated_blog_posts %} +
+ +
+
#{{ blog_post.id }} — {{ blog_post.title }}
+
+ content_length={{ blog_post.content_length }} · posted={{ blog_post.posted|yesno:"true,false" }} + {% if blog_post.slug %} · slug={{ blog_post.slug }}{% endif %} +
+
+
+ {% if blog_post.content_length > 0 %} + + View post + + {% endif %} +
+
+ +
+ {% if blog_post.description %} +
+
Description
+
{{ blog_post.description }}
+
+ {% endif %} + + {% if blog_post.sections %} +
+
Sections ({{ blog_post.sections|length }})
+
+ {% for section in blog_post.sections %} +
+ + [{{ section.order }}] {{ section.title }} + +
+ {% if section.content %} +
{{ section.content }}
+ {% endif %} + +
+
Research questions ({{ section.questions|length }})
+ {% if section.questions %} +
+ {% for research_question in section.questions %} +
+
Q{{ research_question.id }}: {{ research_question.question }}
+
+
Links ({{ research_question.links|length }})
+ {% if research_question.links %} +
    + {% for research_link in research_question.links %} +
  • +
    {{ research_link.title|default:"(no title)" }}
    + + {{ research_link.url }} + +
    + author={{ research_link.author|default:"" }} + {% if research_link.published_date %} · published={{ research_link.published_date|date:"Y-m-d" }}{% endif %} + {% if research_link.date_scraped %} · scraped={{ research_link.date_scraped|date:"Y-m-d H:i" }}{% endif %} + {% if research_link.date_analyzed %} · analyzed={{ research_link.date_analyzed|date:"Y-m-d H:i" }}{% endif %} +
    +
  • + {% endfor %} +
+ {% else %} +
No links.
+ {% endif %} +
+
+ {% endfor %} +
+ {% else %} +
No research questions.
+ {% endif %} +
+
+
+ {% endfor %} +
+
+ {% endif %} + + {% if blog_post.blog_level_questions %} +
+
Blog-level research questions ({{ blog_post.blog_level_questions|length }})
+
+ {% for research_question in blog_post.blog_level_questions %} +
+
Q{{ research_question.id }}: {{ research_question.question }}
+
+
Links ({{ research_question.links|length }})
+ {% if research_question.links %} +
    + {% for research_link in research_question.links %} +
  • +
    {{ research_link.title|default:"(no title)" }}
    + + {{ research_link.url }} + +
    + author={{ research_link.author|default:"" }} + {% if research_link.published_date %} · published={{ research_link.published_date|date:"Y-m-d" }}{% endif %} + {% if research_link.date_scraped %} · scraped={{ research_link.date_scraped|date:"Y-m-d H:i" }}{% endif %} + {% if research_link.date_analyzed %} · analyzed={{ research_link.date_analyzed|date:"Y-m-d H:i" }}{% endif %} +
    +
  • + {% endfor %} +
+ {% else %} +
No links.
+ {% endif %} +
+
+ {% endfor %} +
+
+ {% endif %} +
+
+ {% endfor %} +
+ {% else %} +
No generated blog posts found for this title suggestion yet.
+ {% endif %} +
+
+
+{% endblock project_content %} diff --git a/frontend/templates/blog/generated_blog_post_detail.html b/frontend/templates/blog/generated_blog_post_detail.html index c5daf0e..9dc8002 100644 --- a/frontend/templates/blog/generated_blog_post_detail.html +++ b/frontend/templates/blog/generated_blog_post_detail.html @@ -30,6 +30,20 @@

{{ generated_post.description }}

{% endif %} + + {% if generated_post.title_suggestion_id %} + + {% endif %} diff --git a/frontend/templates/components/blog_post_suggestion_card.html b/frontend/templates/components/blog_post_suggestion_card.html index 408b6ce..00ab42e 100644 --- a/frontend/templates/components/blog_post_suggestion_card.html +++ b/frontend/templates/components/blog_post_suggestion_card.html @@ -164,8 +164,18 @@

- -
+
+ + + + + Research + + +