From 615d1bdb9eef69626b36645113616213f812474a Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 5 Apr 2026 09:34:01 +0000 Subject: [PATCH 1/2] feat: NLP patch insights + standalone demo mode - dlib/ai/insights.py: pure-Python NLP analysis that correlates accepted AI suggestion operations/keywords/sections with submission outcomes (pending_review / published = positive, archived = negative) - Backend: GET /api/v1/insights route + service + Pydantic schema - Frontend: InsightsPanel component with bar charts for operation impact, section impact, and keyword signal lift scores - Insights tab added to the version panel; compact preview on doc overview - NEXT_PUBLIC_DEMO=true makes the webapp fully standalone: loads DEMO_DOCUMENTS / DEMO_SUBMISSIONS / DEMO_INSIGHTS from demo-data.ts, disables all mutating actions, shows a DEMO badge in the top bar - apps/webapp/public/demo-cv.docx: static dummy CV (Alex Rivera) for demo - scripts/gen_demo_cv.py: script to regenerate the demo DOCX - .env.example: document NEXT_PUBLIC_DEMO flag https://claude.ai/code/session_01LWxu2qrwY6BRjUFXXn7NiM --- .env.example | 5 + apps/backend/fastapi/app/api/router.py | 3 +- .../fastapi/app/api/routes/insights.py | 41 ++++ apps/backend/fastapi/app/schemas/insights.py | 34 ++++ apps/backend/fastapi/app/services/insights.py | 37 ++++ apps/webapp/public/demo-cv.docx | Bin 0 -> 37550 bytes apps/webapp/src/app/dashboard/demo-data.ts | 165 +++++++++++++++ apps/webapp/src/app/dashboard/page.tsx | 83 ++++++-- .../src/components/cv/InsightsPanel.tsx | 134 +++++++++++++ apps/webapp/src/libs/api.ts | 19 ++ dlib/ai/insights.py | 189 ++++++++++++++++++ scripts/gen_demo_cv.py | 87 ++++++++ 12 files changed, 780 insertions(+), 17 deletions(-) create mode 100644 apps/backend/fastapi/app/api/routes/insights.py create mode 100644 apps/backend/fastapi/app/schemas/insights.py create mode 100644 apps/backend/fastapi/app/services/insights.py create mode 100644 apps/webapp/public/demo-cv.docx create mode 100644 apps/webapp/src/app/dashboard/demo-data.ts create mode 100644 apps/webapp/src/components/cv/InsightsPanel.tsx create mode 100644 dlib/ai/insights.py create mode 100644 scripts/gen_demo_cv.py diff --git a/.env.example b/.env.example index 48b9b6d..772b570 100644 --- a/.env.example +++ b/.env.example @@ -56,3 +56,8 @@ AUTHENTIK_CLIENT_SECRET= # ── AI tailoring (optional) ─────────────────────────────────────────────────── # Leave blank to use the built-in rule-based tailoring instead of Claude. ANTHROPIC_API_KEY= + +# ── Demo mode ───────────────────────────────────────────────────────────────── +# Set to true to enable standalone demo mode in the webapp. +# Demo mode uses hardcoded dummy data — no backend or DB required. +NEXT_PUBLIC_DEMO=false diff --git a/apps/backend/fastapi/app/api/router.py b/apps/backend/fastapi/app/api/router.py index dccc0ca..25ab068 100644 --- a/apps/backend/fastapi/app/api/router.py +++ b/apps/backend/fastapi/app/api/router.py @@ -2,10 +2,11 @@ from __future__ import annotations from fastapi import APIRouter -from app.api.routes import documents, versions, submissions, public +from app.api.routes import documents, insights, versions, submissions, public api_router = APIRouter() api_router.include_router(documents.router) api_router.include_router(versions.router) api_router.include_router(submissions.router) api_router.include_router(public.router) +api_router.include_router(insights.router) diff --git a/apps/backend/fastapi/app/api/routes/insights.py b/apps/backend/fastapi/app/api/routes/insights.py new file mode 100644 index 0000000..5cdae76 --- /dev/null +++ b/apps/backend/fastapi/app/api/routes/insights.py @@ -0,0 +1,41 @@ +from __future__ import annotations + +from fastapi import APIRouter, Depends +from sqlalchemy.ext.asyncio import AsyncSession + +from app.api.deps import get_current_user, get_db +from app.schemas.insights import InsightsResponse +from app.services.insights import get_insights +from dlib.auth import AuthenticatedUser + +router = APIRouter(prefix="/insights", tags=["insights"]) + + +@router.get("", response_model=InsightsResponse) +async def insights_endpoint( + session: AsyncSession = Depends(get_db), + user: AuthenticatedUser = Depends(get_current_user), +): + result = await get_insights(session, owner_id=user.sub) + return InsightsResponse( + total_submissions=result.total_submissions, + positive_count=result.positive_count, + positive_rate=result.positive_rate, + operation_impact=[ + {"operation": o.operation, "total": o.total, "positive": o.positive, "rate": o.rate} + for o in result.operation_impact + ], + top_positive_keywords=[ + {"keyword": k.keyword, "positive_count": k.positive_count, "negative_count": k.negative_count, "lift": k.lift} + for k in result.top_positive_keywords + ], + top_negative_keywords=[ + {"keyword": k.keyword, "positive_count": k.positive_count, "negative_count": k.negative_count, "lift": k.lift} + for k in result.top_negative_keywords + ], + section_impact=[ + {"section": s.section, "positive_rate": s.positive_rate, "count": s.count} + for s in result.section_impact + ], + has_data=result.has_data, + ) diff --git a/apps/backend/fastapi/app/schemas/insights.py b/apps/backend/fastapi/app/schemas/insights.py new file mode 100644 index 0000000..84eff18 --- /dev/null +++ b/apps/backend/fastapi/app/schemas/insights.py @@ -0,0 +1,34 @@ +from __future__ import annotations + +from pydantic import BaseModel + + +class OperationImpactSchema(BaseModel): + operation: str + total: int + positive: int + rate: float + + +class KeywordSignalSchema(BaseModel): + keyword: str + positive_count: int + negative_count: int + lift: float + + +class SectionImpactSchema(BaseModel): + section: str + positive_rate: float + count: int + + +class InsightsResponse(BaseModel): + total_submissions: int + positive_count: int + positive_rate: float + operation_impact: list[OperationImpactSchema] + top_positive_keywords: list[KeywordSignalSchema] + top_negative_keywords: list[KeywordSignalSchema] + section_impact: list[SectionImpactSchema] + has_data: bool diff --git a/apps/backend/fastapi/app/services/insights.py b/apps/backend/fastapi/app/services/insights.py new file mode 100644 index 0000000..a876e78 --- /dev/null +++ b/apps/backend/fastapi/app/services/insights.py @@ -0,0 +1,37 @@ +from __future__ import annotations + +from sqlalchemy import select +from sqlalchemy.ext.asyncio import AsyncSession +from sqlalchemy.orm import selectinload + +from dlib.ai.insights import InsightsResult, SubmissionRecord, SuggestionRecord, analyze +from app.models import AiSuggestion, CvDocument, CvVersion, Submission + + +async def get_insights(session: AsyncSession, *, owner_id: str) -> InsightsResult: + stmt = ( + select(Submission) + .join(Submission.version) + .join(CvVersion.document) + .where(CvDocument.owner_id == owner_id) + .options(selectinload(Submission.suggestions)) + ) + rows = list((await session.execute(stmt)).scalars().all()) + + records = [ + SubmissionRecord( + status=s.status.value, + suggestions=[ + SuggestionRecord( + operation=sug.operation, + target_path=sug.target_path, + proposed_text=sug.proposed_text, + rationale=sug.rationale, + accepted=sug.accepted, + ) + for sug in s.suggestions + ], + ) + for s in rows + ] + return analyze(records) diff --git a/apps/webapp/public/demo-cv.docx b/apps/webapp/public/demo-cv.docx new file mode 100644 index 0000000000000000000000000000000000000000..e32e6a008743257fce05558eb0e69624804012dd GIT binary patch literal 37550 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 new Date(Date.now() - daysAgo * 86_400_000).toISOString(); + +const ROOT_VERSION_ID = 'demo-v1'; +const ML_VERSION_ID = 'demo-v2'; +const BACKEND_VERSION_ID = 'demo-v3'; +export const DEMO_DOC_ID = 'demo-doc-1'; + +export const DEMO_DOCUMENTS: Document[] = [ + { + id: DEMO_DOC_ID, + title: 'Alex Rivera — Software Engineer', + description: 'Main CV, ATS-safe baseline', + owner_id: 'demo-user', + root_version_id: ROOT_VERSION_ID, + created_at: D(45), + updated_at: D(3), + versions: [ + { + id: ROOT_VERSION_ID, + branch_name: 'root', + version_label: 'v1.0 baseline', + parent_version_id: null, + structured_blocks: [ + { path: 'heading[1]', block_type: 'heading', text: 'Alex Rivera', keywords: [] }, + { path: 'summary[1]', block_type: 'summary', text: 'Software engineer with 5 years of experience building distributed systems and ML pipelines at scale.', keywords: ['distributed', 'systems', 'machine', 'learning'] }, + { path: 'heading[2]', block_type: 'heading', text: 'Experience', keywords: [] }, + { path: 'bullet[1]', block_type: 'bullet', text: 'Led migration of monolithic data pipeline to distributed microservices, reducing p99 latency by 40%.', keywords: ['distributed', 'microservices', 'latency', 'pipeline'] }, + { path: 'bullet[2]', block_type: 'bullet', text: 'Designed feature flag system used by 50+ engineers across 3 teams.', keywords: ['system', 'design', 'engineers'] }, + { path: 'heading[3]', block_type: 'heading', text: 'Skills', keywords: [] }, + { path: 'skills[1]', block_type: 'skills', text: 'Python, Go, TypeScript, SQL, Kubernetes, AWS, PyTorch', keywords: ['python', 'go', 'typescript', 'pytorch', 'kubernetes'] }, + ], + artifact_docx_key: 'demo/demo-cv.docx', + patches: [], + public_assets: [], + created_at: D(45), + updated_at: D(45), + }, + { + id: ML_VERSION_ID, + branch_name: 'ml-engineer', + version_label: 'ML-focused variant', + parent_version_id: ROOT_VERSION_ID, + structured_blocks: [ + { path: 'heading[1]', block_type: 'heading', text: 'Alex Rivera', keywords: [] }, + { path: 'summary[1]', block_type: 'summary', text: 'ML engineer specialising in large-scale PyTorch training pipelines, distributed inference, and production-grade MLOps.', keywords: ['pytorch', 'distributed', 'mlops', 'inference'] }, + { path: 'heading[2]', block_type: 'heading', text: 'Experience', keywords: [] }, + { path: 'bullet[1]', block_type: 'bullet', text: 'Contributed PyTorch anomaly detection model achieving 92% precision on production traffic at 2M events/day.', keywords: ['pytorch', 'machine learning', 'production', 'precision'] }, + { path: 'bullet[2]', block_type: 'bullet', text: 'Built streaming data ingestion system (Kafka + Flink) powering real-time ML feature store.', keywords: ['kafka', 'flink', 'streaming', 'feature store'] }, + { path: 'heading[3]', block_type: 'heading', text: 'Skills', keywords: [] }, + { path: 'skills[1]', block_type: 'skills', text: 'PyTorch, Python, Go, Kubernetes, Spark, dbt, AWS SageMaker', keywords: ['pytorch', 'python', 'kubernetes', 'spark', 'sagemaker'] }, + ], + artifact_docx_key: 'demo/demo-cv.docx', + patches: [ + { id: 'dp1', target_path: 'summary[1]', operation: 'replace_text', old_value: 'Software engineer…', new_value: 'ML engineer specialising…', created_at: D(30) }, + { id: 'dp2', target_path: 'skills[1]', operation: 'boost_keyword', old_value: null, new_value: 'PyTorch', created_at: D(30) }, + ], + public_assets: [{ + id: 'demo-asset-1', slug: 'alex-ml', artifact_key: 'public/alex-ml.docx', + is_public: true, url: '/demo-cv.docx', version_id: ML_VERSION_ID, submission_id: null, created_at: D(20), + }], + created_at: D(30), + updated_at: D(3), + }, + { + id: BACKEND_VERSION_ID, + branch_name: 'backend-engineer', + version_label: 'Backend-focused variant', + parent_version_id: ROOT_VERSION_ID, + structured_blocks: [ + { path: 'heading[1]', block_type: 'heading', text: 'Alex Rivera', keywords: [] }, + { path: 'summary[1]', block_type: 'summary', text: 'Backend engineer focused on high-throughput API design, distributed systems, and reliability engineering.', keywords: ['backend', 'api', 'distributed', 'reliability'] }, + { path: 'bullet[1]', block_type: 'bullet', text: 'Led migration to microservices, reducing p99 latency by 40% under 10k RPS sustained load.', keywords: ['microservices', 'latency', 'rps', 'distributed'] }, + { path: 'skills[1]', block_type: 'skills', text: 'Go, Python, PostgreSQL, Redis, gRPC, Kubernetes, AWS', keywords: ['go', 'postgresql', 'redis', 'grpc', 'kubernetes'] }, + ], + artifact_docx_key: 'demo/demo-cv.docx', + patches: [ + { id: 'dp3', target_path: 'summary[1]', operation: 'replace_text', old_value: 'Software engineer…', new_value: 'Backend engineer…', created_at: D(25) }, + ], + public_assets: [], + created_at: D(25), + updated_at: D(10), + }, + ], + }, +]; + +export const DEMO_SUBMISSIONS: Submission[] = [ + { + id: 'ds1', version_id: ML_VERSION_ID, company_name: 'Anthropic', role_title: 'ML Research Engineer', + job_url: null, job_description: null, status: 'pending_review', created_at: D(18), + suggestions: [ + { id: 's1', target_path: 'summary[1]', operation: 'boost_keyword', proposed_text: 'constitutional ai', rationale: 'Highlight alignment research experience', accepted: true, metadata_json: { confidence: 0.82 } }, + { id: 's2', target_path: 'bullet[1]', operation: 'replace_text', proposed_text: 'Built distributed PyTorch training pipeline handling constitutional AI fine-tuning at scale.', rationale: 'Align with Anthropic stack', accepted: true, metadata_json: { confidence: 0.74 } }, + ], + }, + { + id: 'ds2', version_id: ML_VERSION_ID, company_name: 'Google DeepMind', role_title: 'Senior ML Engineer', + job_url: null, job_description: null, status: 'pending_review', created_at: D(14), + suggestions: [ + { id: 's3', target_path: 'skills[1]', operation: 'boost_keyword', proposed_text: 'JAX', rationale: 'DeepMind uses JAX heavily', accepted: true, metadata_json: { confidence: 0.71 } }, + { id: 's4', target_path: 'bullet[2]', operation: 'replace_text', proposed_text: 'Built large-scale streaming pipeline underpinning real-time feature store for JAX model serving.', rationale: 'Add JAX context', accepted: true, metadata_json: { confidence: 0.68 } }, + ], + }, + { + id: 'ds3', version_id: ML_VERSION_ID, company_name: 'OpenAI', role_title: 'Research Engineer', + job_url: null, job_description: null, status: 'published', created_at: D(10), + suggestions: [ + { id: 's5', target_path: 'summary[1]', operation: 'replace_text', proposed_text: 'ML engineer with track record in large-scale training infrastructure and RLHF pipelines.', rationale: 'OpenAI focus on RLHF', accepted: true, metadata_json: { confidence: 0.77 } }, + ], + }, + { + id: 'ds4', version_id: ML_VERSION_ID, company_name: 'Meta AI', role_title: 'ML Infrastructure Engineer', + job_url: null, job_description: null, status: 'archived', created_at: D(22), + suggestions: [ + { id: 's6', target_path: 'bullet[1]', operation: 'boost_keyword', proposed_text: 'PyTorch', rationale: 'Meta maintains PyTorch', accepted: true, metadata_json: { confidence: 0.55 } }, + { id: 's7', target_path: 'summary[1]', operation: 'suppress_block', proposed_text: null, rationale: 'Summary too generic', accepted: false, metadata_json: { confidence: 0.3 } }, + ], + }, + { + id: 'ds5', version_id: BACKEND_VERSION_ID, company_name: 'Stripe', role_title: 'Senior Backend Engineer', + job_url: null, job_description: null, status: 'pending_review', created_at: D(8), + suggestions: [ + { id: 's8', target_path: 'bullet[1]', operation: 'replace_text', proposed_text: 'Led migration to microservices achieving 99.99% uptime across Stripe-scale payment processing.', rationale: 'Emphasise reliability', accepted: true, metadata_json: { confidence: 0.79 } }, + ], + }, + { + id: 'ds6', version_id: BACKEND_VERSION_ID, company_name: 'Cloudflare', role_title: 'Staff Engineer', + job_url: null, job_description: null, status: 'archived', created_at: D(20), + suggestions: [ + { id: 's9', target_path: 'skills[1]', operation: 'boost_keyword', proposed_text: 'Rust', rationale: 'Cloudflare uses Rust', accepted: true, metadata_json: { confidence: 0.4 } }, + ], + }, +]; + +export const DEMO_INSIGHTS: InsightsResult = { + total_submissions: 6, + positive_count: 4, + positive_rate: 0.667, + has_data: true, + operation_impact: [ + { operation: 'replace_text', total: 5, positive: 4, rate: 0.8 }, + { operation: 'boost_keyword', total: 5, positive: 3, rate: 0.6 }, + { operation: 'suppress_block', total: 1, positive: 0, rate: 0.0 }, + ], + top_positive_keywords: [ + { keyword: 'pytorch', positive_count: 4, negative_count: 1, lift: 4.0 }, + { keyword: 'distributed', positive_count: 3, negative_count: 0, lift: 3.0 }, + { keyword: 'pipeline', positive_count: 3, negative_count: 1, lift: 3.0 }, + { keyword: 'scale', positive_count: 3, negative_count: 1, lift: 3.0 }, + { keyword: 'reliability', positive_count: 2, negative_count: 0, lift: 2.0 }, + { keyword: 'inference', positive_count: 2, negative_count: 0, lift: 2.0 }, + ], + top_negative_keywords: [ + { keyword: 'generic', positive_count: 0, negative_count: 2, lift: 0.0 }, + { keyword: 'suppress', positive_count: 0, negative_count: 1, lift: 0.0 }, + ], + section_impact: [ + { section: 'summary', positive_rate: 0.83, count: 6 }, + { section: 'bullet', positive_rate: 0.75, count: 4 }, + { section: 'skills', positive_rate: 0.5, count: 4 }, + ], +}; diff --git a/apps/webapp/src/app/dashboard/page.tsx b/apps/webapp/src/app/dashboard/page.tsx index 7054698..a4c26ab 100644 --- a/apps/webapp/src/app/dashboard/page.tsx +++ b/apps/webapp/src/app/dashboard/page.tsx @@ -3,12 +3,15 @@ import { useEffect, useRef, useState } from 'react'; import CVTree from '@/components/cv/CVTree'; import DiffViewer from '@/components/cv/DiffViewer'; +import InsightsPanel from '@/components/cv/InsightsPanel'; import Link from 'next/link'; import { appendPatches, createBranch, createSubmission, deleteDocument, deleteVersion, Document, downloadVersionUrl, - fetchDocuments, fetchSubmissions, fetchPublicAssetAnalytics, getPublicPdfUrl, + fetchDocuments, fetchInsights, fetchSubmissions, fetchPublicAssetAnalytics, getPublicPdfUrl, + InsightsResult, + IS_DEMO, publishVersion, PublicAsset, PublicAssetAnalytics, requestAiSuggestions, Submission, @@ -20,6 +23,9 @@ import { uploadDocument, Version, } from '@/libs/api'; +import { + DEMO_DOCUMENTS, DEMO_DOC_ID, DEMO_INSIGHTS, DEMO_SUBMISSIONS, +} from './demo-data'; // ── helpers ─────────────────────────────────────────────────────────────────── @@ -548,7 +554,7 @@ function SubmissionsTab({ // ── main dashboard ──────────────────────────────────────────────────────────── type Modal = 'upload' | 'branch' | 'submission' | 'publish' | null; -type Tab = 'content' | 'patches' | 'submissions'; +type Tab = 'content' | 'patches' | 'submissions' | 'insights'; export default function Dashboard() { const [docs, setDocs] = useState([]); @@ -568,8 +574,17 @@ export default function Dashboard() { const [docHovered, setDocHovered] = useState(null); const [applyLoading, setApplyLoading] = useState(false); const [applyError, setApplyError] = useState(''); + const [insights, setInsights] = useState(null); useEffect(() => { + if (IS_DEMO) { + setDocs(DEMO_DOCUMENTS); + setAllSubmissions(DEMO_SUBMISSIONS); + setSelectedDocId(DEMO_DOC_ID); + setInsights(DEMO_INSIGHTS); + setLoading(false); + return; + } Promise.all([fetchDocuments(), fetchSubmissions().catch(() => [])]) .then(([d, allSubs]) => { setDocs(d); @@ -580,6 +595,11 @@ export default function Dashboard() { .finally(() => setLoading(false)); }, []); + useEffect(() => { + if (IS_DEMO || !selectedDocId) return; + fetchInsights().then(setInsights).catch(() => setInsights(null)); + }, [selectedDocId]); + useEffect(() => { setPendingEdits(new Map()); setApplyError(''); @@ -691,6 +711,7 @@ export default function Dashboard() { }; const handleDeleteDoc = async (docId: string) => { + if (IS_DEMO) return; if (!confirm('Delete this CV and all its branches? This cannot be undone.')) return; try { await deleteDocument(docId); @@ -706,6 +727,7 @@ export default function Dashboard() { }; const handleDeleteVersion = async (versionId: string) => { + if (IS_DEMO) return; const hasChildren = selectedDoc?.versions.some(v => v.parent_version_id === versionId); const msg = hasChildren ? 'Delete this branch and all its sub-branches? This cannot be undone.' @@ -758,12 +780,21 @@ export default function Dashboard() {

- - + {IS_DEMO && ( + + DEMO + + )} + {!IS_DEMO && ( + + )} + {!IS_DEMO && ( + + )}
@@ -900,6 +931,13 @@ export default function Dashboard() { onSelect={selectVersion} /> + + {insights?.has_data && ( +
+
NLP insights
+ +
+ )} ) : (
@@ -938,10 +976,15 @@ export default function Dashboard() { {/* action buttons */}
- - - - {selectedVersion.artifact_docx_key && selectedDoc && ( + {!IS_DEMO && } + {!IS_DEMO && } + {!IS_DEMO && } + {IS_DEMO && ( + + ↓ DOCX + + )} + {!IS_DEMO && selectedVersion.artifact_docx_key && selectedDoc && ( ↓ DOCX @@ -1044,7 +1087,7 @@ export default function Dashboard() { {/* tabs */}
- {(['content', 'patches', 'submissions'] as Tab[]).map(t => ( + {(['content', 'patches', 'submissions', 'insights'] as Tab[]).map(t => (
)} diff --git a/apps/webapp/src/components/cv/InsightsPanel.tsx b/apps/webapp/src/components/cv/InsightsPanel.tsx new file mode 100644 index 0000000..bbdcd8c --- /dev/null +++ b/apps/webapp/src/components/cv/InsightsPanel.tsx @@ -0,0 +1,134 @@ +'use client'; + +import type { InsightsResult } from '@/libs/api'; + +function Bar({ rate, positive }: { rate: number; positive?: boolean }) { + return ( +
+
= 0.6 ? '#22c55e' : rate >= 0.4 ? '#f59e0b' : '#94a3b8', + borderRadius: 3, + transition: 'width 0.3s', + }} /> +
+ ); +} + +function Pct({ v }: { v: number }) { + return = 0.6 ? '#16a34a' : v >= 0.4 ? '#d97706' : '#6b7280' }}>{Math.round(v * 100)}%; +} + +export default function InsightsPanel({ data }: { data: InsightsResult | null }) { + if (!data) return ( +
+ Loading insights… +
+ ); + + if (!data.has_data) return ( +
+ Not enough data yet. Submit applications and mark outcomes to unlock insights. +
+ ); + + return ( +
+ {/* headline numbers */} +
+ {[ + { label: 'Total submissions', value: data.total_submissions }, + { label: 'Passed screening', value: data.positive_count }, + { label: 'Screening rate', value: `${Math.round(data.positive_rate * 100)}%` }, + ].map(({ label, value }) => ( +
+
{label}
+
{value}
+
+ ))} +
+ + {/* operation impact */} + {data.operation_impact.length > 0 && ( +
+
Patch operation impact
+
+ {data.operation_impact.map(op => ( +
+ + {op.operation} + + + + + {op.positive}/{op.total} + +
+ ))} +
+

+ % of accepted patches of this type in submissions that passed screening. +

+
+ )} + + {/* section impact */} + {data.section_impact.length > 0 && ( +
+
CV section impact
+
+ {data.section_impact.map(s => ( +
+ + {s.section} + + + + + {s.count} edits + +
+ ))} +
+
+ )} + + {/* keyword signals */} + {(data.top_positive_keywords.length > 0 || data.top_negative_keywords.length > 0) && ( +
+
Keyword signals
+
+
+
Positive signals
+
+ {data.top_positive_keywords.map(k => ( +
+ {k.keyword} + +{k.positive_count} ({k.lift}×) +
+ ))} +
+
+
+
Negative signals
+
+ {data.top_negative_keywords.length === 0 + ? None yet + : data.top_negative_keywords.map(k => ( +
+ {k.keyword} + {k.negative_count}× +
+ ))} +
+
+
+

+ Keywords extracted from accepted AI suggestions, split by outcome. +

+
+ )} +
+ ); +} diff --git a/apps/webapp/src/libs/api.ts b/apps/webapp/src/libs/api.ts index 736f4a9..6260fe8 100644 --- a/apps/webapp/src/libs/api.ts +++ b/apps/webapp/src/libs/api.ts @@ -1,4 +1,5 @@ const API = ""; +export const IS_DEMO = process.env.NEXT_PUBLIC_DEMO === 'true'; export type StructuredBlock = { path: string; @@ -87,6 +88,21 @@ export type PublicAssetAnalytics = { last_viewed_at?: string | null; }; +export type OperationImpact = { operation: string; total: number; positive: number; rate: number }; +export type KeywordSignal = { keyword: string; positive_count: number; negative_count: number; lift: number }; +export type SectionImpact = { section: string; positive_rate: number; count: number }; + +export type InsightsResult = { + total_submissions: number; + positive_count: number; + positive_rate: number; + operation_impact: OperationImpact[]; + top_positive_keywords: KeywordSignal[]; + top_negative_keywords: KeywordSignal[]; + section_impact: SectionImpact[]; + has_data: boolean; +}; + // reads OIDC bearer token from client-readable cookie (set by /api/auth/callback) function getAuthHeader(): Record { if (typeof document === 'undefined') return {}; @@ -238,6 +254,9 @@ export async function deleteDocument(documentId: string): Promise { } } +export const fetchInsights = (): Promise => + req('/api/v1/insights'); + export async function deleteVersion(versionId: string): Promise { const res = await fetch(`${API}/api/v1/versions/${versionId}`, { method: 'DELETE', diff --git a/dlib/ai/insights.py b/dlib/ai/insights.py new file mode 100644 index 0000000..db87003 --- /dev/null +++ b/dlib/ai/insights.py @@ -0,0 +1,189 @@ +from __future__ import annotations + +import re +from collections import Counter, defaultdict +from dataclasses import dataclass, field +from typing import Literal + +STOPWORDS = frozenset( + "a an the and or but in on at to for of with is are was were be been have has" + " had do does did this that these those it its i you he she we they their our" + " your my his her from by into through about as so if then when where which who" + " can will may should would could also just not no more some all any each" + " than other up out off over how what new using use used with well per".split() +) + +Outcome = Literal["positive", "negative"] # positive = pending_review / published + + +@dataclass +class SuggestionRecord: + operation: str + target_path: str + proposed_text: str | None + rationale: str | None + accepted: bool | None + + +@dataclass +class SubmissionRecord: + status: str + suggestions: list[SuggestionRecord] = field(default_factory=list) + + +@dataclass +class OperationImpact: + operation: str + total: int + positive: int + rate: float + + +@dataclass +class KeywordSignal: + keyword: str + positive_count: int + negative_count: int + lift: float # positive_count / max(negative_count, 1) + + +@dataclass +class SectionImpact: + section: str + positive_rate: float + count: int + + +@dataclass +class InsightsResult: + total_submissions: int + positive_count: int + positive_rate: float + operation_impact: list[OperationImpact] + top_positive_keywords: list[KeywordSignal] + top_negative_keywords: list[KeywordSignal] + section_impact: list[SectionImpact] + has_data: bool + + +def _outcome(status: str) -> Outcome | None: + if status in ("pending_review", "published"): + return "positive" + if status == "archived": + return "negative" + return None # draft / tailoring — not enough signal + + +def _tokens(text: str | None) -> list[str]: + if not text: + return [] + return [ + t for t in re.findall(r"[a-z][a-z0-9+.-]{1,}", text.lower()) + if t not in STOPWORDS and len(t) > 2 + ] + + +def _section_prefix(path: str) -> str: + """heading[1] -> heading, bullet[3] -> bullet, table[1].0-1 -> table""" + return re.match(r"([a-z_]+)", path).group(1) if path else "unknown" + + +def analyze(submissions: list[SubmissionRecord]) -> InsightsResult: + labeled = [(s, _outcome(s.status)) for s in submissions] + labeled_known = [(s, o) for s, o in labeled if o is not None] + + positive_count = sum(1 for _, o in labeled_known if o == "positive") + + # operation impact: only accepted suggestions in outcome-labeled submissions + op_positive: Counter[str] = Counter() + op_total: Counter[str] = Counter() + for sub, outcome in labeled_known: + for sug in sub.suggestions: + if sug.accepted is not True: + continue + op_total[sug.operation] += 1 + if outcome == "positive": + op_positive[sug.operation] += 1 + + op_impact = sorted( + [ + OperationImpact( + operation=op, + total=total, + positive=op_positive[op], + rate=round(op_positive[op] / total, 3), + ) + for op, total in op_total.items() + ], + key=lambda x: x.rate, + reverse=True, + ) + + # keyword signals from accepted-suggestion text in outcome-labeled submissions + kw_pos: Counter[str] = Counter() + kw_neg: Counter[str] = Counter() + for sub, outcome in labeled_known: + bucket = kw_pos if outcome == "positive" else kw_neg + for sug in sub.suggestions: + if sug.accepted is not True: + continue + for t in _tokens(sug.proposed_text) + _tokens(sug.rationale): + bucket[t] += 1 + + all_kws = set(kw_pos) | set(kw_neg) + signals = [ + KeywordSignal( + keyword=kw, + positive_count=kw_pos[kw], + negative_count=kw_neg[kw], + lift=round(kw_pos[kw] / max(kw_neg[kw], 1), 2), + ) + for kw in all_kws + if kw_pos[kw] + kw_neg[kw] >= 2 # minimum support + ] + top_pos_kw = sorted( + [s for s in signals if s.positive_count > 0], + key=lambda s: (s.lift, s.positive_count), + reverse=True, + )[:8] + top_neg_kw = sorted( + [s for s in signals if s.negative_count > 0], + key=lambda s: (s.negative_count, -s.lift), + reverse=True, + )[:8] + + # section impact: group target_path prefix by outcome + sec_pos: Counter[str] = Counter() + sec_total: Counter[str] = Counter() + for sub, outcome in labeled_known: + for sug in sub.suggestions: + if sug.accepted is not True: + continue + sec = _section_prefix(sug.target_path) + sec_total[sec] += 1 + if outcome == "positive": + sec_pos[sec] += 1 + + section_impact = sorted( + [ + SectionImpact( + section=sec, + positive_rate=round(sec_pos[sec] / total, 3), + count=total, + ) + for sec, total in sec_total.items() + ], + key=lambda s: s.positive_rate, + reverse=True, + ) + + return InsightsResult( + total_submissions=len(submissions), + positive_count=positive_count, + positive_rate=round(positive_count / len(submissions), 3) if submissions else 0.0, + operation_impact=op_impact, + top_positive_keywords=top_pos_kw, + top_negative_keywords=top_neg_kw, + section_impact=section_impact, + has_data=bool(labeled_known), + ) diff --git a/scripts/gen_demo_cv.py b/scripts/gen_demo_cv.py new file mode 100644 index 0000000..fbb055d --- /dev/null +++ b/scripts/gen_demo_cv.py @@ -0,0 +1,87 @@ +"""Generate the static demo CV DOCX used by DEMO mode in the webapp.""" +from __future__ import annotations + +import sys +from pathlib import Path + +from docx import Document +from docx.shared import Pt, RGBColor +from docx.enum.text import WD_ALIGN_PARAGRAPH + + +def add_heading(doc: Document, text: str, level: int = 1) -> None: + p = doc.add_heading(text, level=level) + p.alignment = WD_ALIGN_PARAGRAPH.LEFT + + +def add_bullet(doc: Document, text: str) -> None: + doc.add_paragraph(text, style="List Bullet") + + +def build(path: Path) -> None: + doc = Document() + + # Name / contact + name_para = doc.add_paragraph() + name_para.alignment = WD_ALIGN_PARAGRAPH.CENTER + run = name_para.add_run("Alex Rivera") + run.bold = True + run.font.size = Pt(18) + + contact = doc.add_paragraph() + contact.alignment = WD_ALIGN_PARAGRAPH.CENTER + contact.add_run("alex.rivera@email.com · linkedin.com/in/alexrivera · github.com/alexrivera") + + doc.add_paragraph() # spacer + + # Summary + add_heading(doc, "Summary", level=2) + doc.add_paragraph( + "Software engineer with 5 years of experience building distributed systems and " + "machine learning pipelines at scale. Strong background in Python, Go, and cloud-native " + "architectures. Passionate about developer tooling and open-source contribution." + ) + + # Experience + add_heading(doc, "Experience", level=2) + + add_heading(doc, "Senior Software Engineer — Acme Corp", level=3) + doc.add_paragraph("Jan 2022 – Present · San Francisco, CA") + add_bullet(doc, "Led migration of monolithic data pipeline to distributed microservices, reducing p99 latency by 40%.") + add_bullet(doc, "Designed and shipped an internal feature flag system used by 50+ engineers across 3 teams.") + add_bullet(doc, "Mentored 4 junior engineers and ran weekly technical design review sessions.") + + add_heading(doc, "Software Engineer — DataFlow Inc", level=3) + doc.add_paragraph("Aug 2019 – Dec 2021 · Remote") + add_bullet(doc, "Built real-time streaming ingestion system processing 2M events/day using Kafka and Flink.") + add_bullet(doc, "Developed Python SDK for internal data platform, adopted by 8 product teams.") + add_bullet(doc, "Contributed PyTorch-based anomaly detection model achieving 92% precision on production traffic.") + + # Education + add_heading(doc, "Education", level=2) + add_heading(doc, "B.S. Computer Science — State University", level=3) + doc.add_paragraph("Graduated May 2019 · GPA 3.8 / 4.0") + add_bullet(doc, "Senior thesis: Efficient approximate nearest-neighbour search for high-dimensional embeddings.") + + # Skills + add_heading(doc, "Skills", level=2) + skills_para = doc.add_paragraph() + skills_para.add_run("Languages: ").bold = True + skills_para.add_run("Python, Go, TypeScript, SQL") + + infra_para = doc.add_paragraph() + infra_para.add_run("Infrastructure: ").bold = True + infra_para.add_run("Kubernetes, AWS, GCP, Terraform, Docker") + + ml_para = doc.add_paragraph() + ml_para.add_run("ML / Data: ").bold = True + ml_para.add_run("PyTorch, scikit-learn, Spark, Kafka, dbt") + + doc.save(path) + print(f"Saved demo CV to {path}") + + +if __name__ == "__main__": + out = Path(sys.argv[1]) if len(sys.argv) > 1 else Path("apps/webapp/public/demo-cv.docx") + out.parent.mkdir(parents=True, exist_ok=True) + build(out) From ba4fedd1fa90f1ff8a4ebb01f0425558408c3970 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 5 Apr 2026 09:34:23 +0000 Subject: [PATCH 2/2] chore: update uv.lock after dependency resolution https://claude.ai/code/session_01LWxu2qrwY6BRjUFXXn7NiM --- uv.lock | 632 +++++++++++++++++++++++++------------------------------- 1 file changed, 276 insertions(+), 356 deletions(-) diff --git a/uv.lock b/uv.lock index 86fff20..68f5a7a 100644 --- a/uv.lock +++ b/uv.lock @@ -2,15 +2,6 @@ version = 1 revision = 3 requires-python = ">=3.12" -[[package]] -name = "absl-py" -version = "2.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/64/c7/8de93764ad66968d19329a7e0c147a2bb3c7054c554d4a119111b8f9440f/absl_py-2.4.0.tar.gz", hash = "sha256:8c6af82722b35cf71e0f4d1d47dcaebfff286e27110a99fc359349b247dfb5d4", size = 116543, upload-time = "2026-01-28T10:17:05.322Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/18/a6/907a406bb7d359e6a63f99c313846d9eec4f7e6f7437809e03aa00fa3074/absl_py-2.4.0-py3-none-any.whl", hash = "sha256:88476fd881ca8aab94ffa78b7b6c632a782ab3ba1cd19c9bd423abc4fb4cd28d", size = 135750, upload-time = "2026-01-28T10:17:04.19Z" }, -] - [[package]] name = "alembic" version = "1.18.4" @@ -103,6 +94,46 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" }, ] +[[package]] +name = "asyncpg" +version = "0.31.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/cc/d18065ce2380d80b1bcce927c24a2642efd38918e33fd724bc4bca904877/asyncpg-0.31.0.tar.gz", hash = "sha256:c989386c83940bfbd787180f2b1519415e2d3d6277a70d9d0f0145ac73500735", size = 993667, upload-time = "2025-11-24T23:27:00.812Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/a6/59d0a146e61d20e18db7396583242e32e0f120693b67a8de43f1557033e2/asyncpg-0.31.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b44c31e1efc1c15188ef183f287c728e2046abb1d26af4d20858215d50d91fad", size = 662042, upload-time = "2025-11-24T23:25:49.578Z" }, + { url = "https://files.pythonhosted.org/packages/36/01/ffaa189dcb63a2471720615e60185c3f6327716fdc0fc04334436fbb7c65/asyncpg-0.31.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0c89ccf741c067614c9b5fc7f1fc6f3b61ab05ae4aaa966e6fd6b93097c7d20d", size = 638504, upload-time = "2025-11-24T23:25:51.501Z" }, + { url = "https://files.pythonhosted.org/packages/9f/62/3f699ba45d8bd24c5d65392190d19656d74ff0185f42e19d0bbd973bb371/asyncpg-0.31.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:12b3b2e39dc5470abd5e98c8d3373e4b1d1234d9fbdedf538798b2c13c64460a", size = 3426241, upload-time = "2025-11-24T23:25:53.278Z" }, + { url = "https://files.pythonhosted.org/packages/8c/d1/a867c2150f9c6e7af6462637f613ba67f78a314b00db220cd26ff559d532/asyncpg-0.31.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:aad7a33913fb8bcb5454313377cc330fbb19a0cd5faa7272407d8a0c4257b671", size = 3520321, upload-time = "2025-11-24T23:25:54.982Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1a/cce4c3f246805ecd285a3591222a2611141f1669d002163abef999b60f98/asyncpg-0.31.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3df118d94f46d85b2e434fd62c84cb66d5834d5a890725fe625f498e72e4d5ec", size = 3316685, upload-time = "2025-11-24T23:25:57.43Z" }, + { url = "https://files.pythonhosted.org/packages/40/ae/0fc961179e78cc579e138fad6eb580448ecae64908f95b8cb8ee2f241f67/asyncpg-0.31.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bd5b6efff3c17c3202d4b37189969acf8927438a238c6257f66be3c426beba20", size = 3471858, upload-time = "2025-11-24T23:25:59.636Z" }, + { url = "https://files.pythonhosted.org/packages/52/b2/b20e09670be031afa4cbfabd645caece7f85ec62d69c312239de568e058e/asyncpg-0.31.0-cp312-cp312-win32.whl", hash = "sha256:027eaa61361ec735926566f995d959ade4796f6a49d3bde17e5134b9964f9ba8", size = 527852, upload-time = "2025-11-24T23:26:01.084Z" }, + { url = "https://files.pythonhosted.org/packages/b5/f0/f2ed1de154e15b107dc692262395b3c17fc34eafe2a78fc2115931561730/asyncpg-0.31.0-cp312-cp312-win_amd64.whl", hash = "sha256:72d6bdcbc93d608a1158f17932de2321f68b1a967a13e014998db87a72ed3186", size = 597175, upload-time = "2025-11-24T23:26:02.564Z" }, + { url = "https://files.pythonhosted.org/packages/95/11/97b5c2af72a5d0b9bc3fa30cd4b9ce22284a9a943a150fdc768763caf035/asyncpg-0.31.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c204fab1b91e08b0f47e90a75d1b3c62174dab21f670ad6c5d0f243a228f015b", size = 661111, upload-time = "2025-11-24T23:26:04.467Z" }, + { url = "https://files.pythonhosted.org/packages/1b/71/157d611c791a5e2d0423f09f027bd499935f0906e0c2a416ce712ba51ef3/asyncpg-0.31.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:54a64f91839ba59008eccf7aad2e93d6e3de688d796f35803235ea1c4898ae1e", size = 636928, upload-time = "2025-11-24T23:26:05.944Z" }, + { url = "https://files.pythonhosted.org/packages/2e/fc/9e3486fb2bbe69d4a867c0b76d68542650a7ff1574ca40e84c3111bb0c6e/asyncpg-0.31.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0e0822b1038dc7253b337b0f3f676cadc4ac31b126c5d42691c39691962e403", size = 3424067, upload-time = "2025-11-24T23:26:07.957Z" }, + { url = "https://files.pythonhosted.org/packages/12/c6/8c9d076f73f07f995013c791e018a1cd5f31823c2a3187fc8581706aa00f/asyncpg-0.31.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bef056aa502ee34204c161c72ca1f3c274917596877f825968368b2c33f585f4", size = 3518156, upload-time = "2025-11-24T23:26:09.591Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3b/60683a0baf50fbc546499cfb53132cb6835b92b529a05f6a81471ab60d0c/asyncpg-0.31.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0bfbcc5b7ffcd9b75ab1558f00db2ae07db9c80637ad1b2469c43df79d7a5ae2", size = 3319636, upload-time = "2025-11-24T23:26:11.168Z" }, + { url = "https://files.pythonhosted.org/packages/50/dc/8487df0f69bd398a61e1792b3cba0e47477f214eff085ba0efa7eac9ce87/asyncpg-0.31.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:22bc525ebbdc24d1261ecbf6f504998244d4e3be1721784b5f64664d61fbe602", size = 3472079, upload-time = "2025-11-24T23:26:13.164Z" }, + { url = "https://files.pythonhosted.org/packages/13/a1/c5bbeeb8531c05c89135cb8b28575ac2fac618bcb60119ee9696c3faf71c/asyncpg-0.31.0-cp313-cp313-win32.whl", hash = "sha256:f890de5e1e4f7e14023619399a471ce4b71f5418cd67a51853b9910fdfa73696", size = 527606, upload-time = "2025-11-24T23:26:14.78Z" }, + { url = "https://files.pythonhosted.org/packages/91/66/b25ccb84a246b470eb943b0107c07edcae51804912b824054b3413995a10/asyncpg-0.31.0-cp313-cp313-win_amd64.whl", hash = "sha256:dc5f2fa9916f292e5c5c8b2ac2813763bcd7f58e130055b4ad8a0531314201ab", size = 596569, upload-time = "2025-11-24T23:26:16.189Z" }, + { url = "https://files.pythonhosted.org/packages/3c/36/e9450d62e84a13aea6580c83a47a437f26c7ca6fa0f0fd40b6670793ea30/asyncpg-0.31.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:f6b56b91bb0ffc328c4e3ed113136cddd9deefdf5f79ab448598b9772831df44", size = 660867, upload-time = "2025-11-24T23:26:17.631Z" }, + { url = "https://files.pythonhosted.org/packages/82/4b/1d0a2b33b3102d210439338e1beea616a6122267c0df459ff0265cd5807a/asyncpg-0.31.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:334dec28cf20d7f5bb9e45b39546ddf247f8042a690bff9b9573d00086e69cb5", size = 638349, upload-time = "2025-11-24T23:26:19.689Z" }, + { url = "https://files.pythonhosted.org/packages/41/aa/e7f7ac9a7974f08eff9183e392b2d62516f90412686532d27e196c0f0eeb/asyncpg-0.31.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:98cc158c53f46de7bb677fd20c417e264fc02b36d901cc2a43bd6cb0dc6dbfd2", size = 3410428, upload-time = "2025-11-24T23:26:21.275Z" }, + { url = "https://files.pythonhosted.org/packages/6f/de/bf1b60de3dede5c2731e6788617a512bc0ebd9693eac297ee74086f101d7/asyncpg-0.31.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9322b563e2661a52e3cdbc93eed3be7748b289f792e0011cb2720d278b366ce2", size = 3471678, upload-time = "2025-11-24T23:26:23.627Z" }, + { url = "https://files.pythonhosted.org/packages/46/78/fc3ade003e22d8bd53aaf8f75f4be48f0b460fa73738f0391b9c856a9147/asyncpg-0.31.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:19857a358fc811d82227449b7ca40afb46e75b33eb8897240c3839dd8b744218", size = 3313505, upload-time = "2025-11-24T23:26:25.235Z" }, + { url = "https://files.pythonhosted.org/packages/bf/e9/73eb8a6789e927816f4705291be21f2225687bfa97321e40cd23055e903a/asyncpg-0.31.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ba5f8886e850882ff2c2ace5732300e99193823e8107e2c53ef01c1ebfa1e85d", size = 3434744, upload-time = "2025-11-24T23:26:26.944Z" }, + { url = "https://files.pythonhosted.org/packages/08/4b/f10b880534413c65c5b5862f79b8e81553a8f364e5238832ad4c0af71b7f/asyncpg-0.31.0-cp314-cp314-win32.whl", hash = "sha256:cea3a0b2a14f95834cee29432e4ddc399b95700eb1d51bbc5bfee8f31fa07b2b", size = 532251, upload-time = "2025-11-24T23:26:28.404Z" }, + { url = "https://files.pythonhosted.org/packages/d3/2d/7aa40750b7a19efa5d66e67fc06008ca0f27ba1bd082e457ad82f59aba49/asyncpg-0.31.0-cp314-cp314-win_amd64.whl", hash = "sha256:04d19392716af6b029411a0264d92093b6e5e8285ae97a39957b9a9c14ea72be", size = 604901, upload-time = "2025-11-24T23:26:30.34Z" }, + { url = "https://files.pythonhosted.org/packages/ce/fe/b9dfe349b83b9dee28cc42360d2c86b2cdce4cb551a2c2d27e156bcac84d/asyncpg-0.31.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:bdb957706da132e982cc6856bb2f7b740603472b54c3ebc77fe60ea3e57e1bd2", size = 702280, upload-time = "2025-11-24T23:26:32Z" }, + { url = "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6d11b198111a72f47154fa03b85799f9be63701e068b43f84ac25da0bda9cb31", size = 682931, upload-time = "2025-11-24T23:26:33.572Z" }, + { url = "https://files.pythonhosted.org/packages/a6/45/6009040da85a1648dd5bc75b3b0a062081c483e75a1a29041ae63a0bf0dc/asyncpg-0.31.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:18c83b03bc0d1b23e6230f5bf8d4f217dc9bc08644ce0502a9d91dc9e634a9c7", size = 3581608, upload-time = "2025-11-24T23:26:35.638Z" }, + { url = "https://files.pythonhosted.org/packages/7e/06/2e3d4d7608b0b2b3adbee0d0bd6a2d29ca0fc4d8a78f8277df04e2d1fd7b/asyncpg-0.31.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e009abc333464ff18b8f6fd146addffd9aaf63e79aa3bb40ab7a4c332d0c5e9e", size = 3498738, upload-time = "2025-11-24T23:26:37.275Z" }, + { url = "https://files.pythonhosted.org/packages/7d/aa/7d75ede780033141c51d83577ea23236ba7d3a23593929b32b49db8ed36e/asyncpg-0.31.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3b1fbcb0e396a5ca435a8826a87e5c2c2cc0c8c68eb6fadf82168056b0e53a8c", size = 3401026, upload-time = "2025-11-24T23:26:39.423Z" }, + { url = "https://files.pythonhosted.org/packages/ba/7a/15e37d45e7f7c94facc1e9148c0e455e8f33c08f0b8a0b1deb2c5171771b/asyncpg-0.31.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8df714dba348efcc162d2adf02d213e5fab1bd9f557e1305633e851a61814a7a", size = 3429426, upload-time = "2025-11-24T23:26:41.032Z" }, + { url = "https://files.pythonhosted.org/packages/13/d5/71437c5f6ae5f307828710efbe62163974e71237d5d46ebd2869ea052d10/asyncpg-0.31.0-cp314-cp314t-win32.whl", hash = "sha256:1b41f1afb1033f2b44f3234993b15096ddc9cd71b21a42dbd87fc6a57b43d65d", size = 614495, upload-time = "2025-11-24T23:26:42.659Z" }, + { url = "https://files.pythonhosted.org/packages/3c/d7/8fb3044eaef08a310acfe23dae9a8e2e07d305edc29a53497e52bc76eca7/asyncpg-0.31.0-cp314-cp314t-win_amd64.whl", hash = "sha256:bd4107bb7cdd0e9e65fae66a62afd3a249663b844fa34d479f6d5b3bef9c04c3", size = 706062, upload-time = "2025-11-24T23:26:44.086Z" }, +] + [[package]] name = "attrs" version = "25.4.0" @@ -189,6 +220,34 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458, upload-time = "2024-11-08T17:25:46.184Z" }, ] +[[package]] +name = "boto3" +version = "1.42.83" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore" }, + { name = "jmespath" }, + { name = "s3transfer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9f/87/1ed88eaa1e814841a37e71fee74c2b74341d14b791c0c6038b7ba914bea1/boto3-1.42.83.tar.gz", hash = "sha256:cc5621e603982cb3145b7f6c9970e02e297a1a0eb94637cc7f7b69d3017640ee", size = 112719, upload-time = "2026-04-03T19:34:21.254Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/b1/8a066bc8f02937d49783c0b3948ab951d8284e6fde436cab9f359dbd4d93/boto3-1.42.83-py3-none-any.whl", hash = "sha256:544846fdb10585bb7837e409868e8e04c6b372fa04479ba1597ce82cf1242076", size = 140555, upload-time = "2026-04-03T19:34:17.935Z" }, +] + +[[package]] +name = "botocore" +version = "1.42.83" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jmespath" }, + { name = "python-dateutil" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4e/01/b46a3f8b6e9362258f78f1890db1a96d4ed73214d6a36420dc158dcfd221/botocore-1.42.83.tar.gz", hash = "sha256:34bc8cb64b17ac17f8901f073fe4fc9572a5cac9393a37b2b3ea372a83b87f4a", size = 15140337, upload-time = "2026-04-03T19:34:08.779Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/97/0d6f50822dc8c1df7f3eadb0bc6822fc0f98f02287c4efc7c7c88fde129a/botocore-1.42.83-py3-none-any.whl", hash = "sha256:ec0c3ecb3772936ed22a3bdda09883b34858933f71004686d460d829bab39d8e", size = 14818388, upload-time = "2026-04-03T19:34:03.333Z" }, +] + [[package]] name = "cachetools" version = "7.0.3" @@ -541,29 +600,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/20/0c/7bb51e3acfafd16c48875bf3db03607674df16f5b6ef8d056586af7e2b8b/cssselect-1.4.0-py3-none-any.whl", hash = "sha256:c0ec5c0191c8ee39fcc8afc1540331d8b55b0183478c50e9c8a79d44dbceb1d8", size = 18540, upload-time = "2026-01-29T07:00:24.994Z" }, ] -[[package]] -name = "cuda-bindings" -version = "12.9.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cuda-pathfinder" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/c1/dabe88f52c3e3760d861401bb994df08f672ec893b8f7592dc91626adcf3/cuda_bindings-12.9.4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fda147a344e8eaeca0c6ff113d2851ffca8f7dfc0a6c932374ee5c47caa649c8", size = 12151019, upload-time = "2025-10-21T14:51:43.167Z" }, - { url = "https://files.pythonhosted.org/packages/63/56/e465c31dc9111be3441a9ba7df1941fe98f4aa6e71e8788a3fb4534ce24d/cuda_bindings-12.9.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:32bdc5a76906be4c61eb98f546a6786c5773a881f3b166486449b5d141e4a39f", size = 11906628, upload-time = "2025-10-21T14:51:49.905Z" }, - { url = "https://files.pythonhosted.org/packages/a3/84/1e6be415e37478070aeeee5884c2022713c1ecc735e6d82d744de0252eee/cuda_bindings-12.9.4-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:56e0043c457a99ac473ddc926fe0dc4046694d99caef633e92601ab52cbe17eb", size = 11925991, upload-time = "2025-10-21T14:51:56.535Z" }, - { url = "https://files.pythonhosted.org/packages/d1/af/6dfd8f2ed90b1d4719bc053ff8940e494640fe4212dc3dd72f383e4992da/cuda_bindings-12.9.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8b72ee72a9cc1b531db31eebaaee5c69a8ec3500e32c6933f2d3b15297b53686", size = 11922703, upload-time = "2025-10-21T14:52:03.585Z" }, - { url = "https://files.pythonhosted.org/packages/6c/19/90ac264acc00f6df8a49378eedec9fd2db3061bf9263bf9f39fd3d8377c3/cuda_bindings-12.9.4-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d80bffc357df9988dca279734bc9674c3934a654cab10cadeed27ce17d8635ee", size = 11924658, upload-time = "2025-10-21T14:52:10.411Z" }, -] - -[[package]] -name = "cuda-pathfinder" -version = "1.4.1" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/07/02/59a5bc738a09def0b49aea0e460bdf97f65206d0d041246147cf6207e69c/cuda_pathfinder-1.4.1-py3-none-any.whl", hash = "sha256:40793006082de88e0950753655e55558a446bed9a7d9d0bcb48b2506d50ed82a", size = 43903, upload-time = "2026-03-06T21:05:24.372Z" }, -] - [[package]] name = "cycler" version = "0.12.1" @@ -619,6 +655,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/55/e2/2537ebcff11c1ee1ff17d8d0b6f4db75873e3b0fb32c2d4a2ee31ecb310a/docstring_parser-0.17.0-py3-none-any.whl", hash = "sha256:cf2569abd23dce8099b300f9b4fa8191e9582dda731fd533daf54c4551658708", size = 36896, upload-time = "2025-07-21T07:35:00.684Z" }, ] +[[package]] +name = "ecdsa" +version = "0.19.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/25/ca/8de7744cb3bc966c85430ca2d0fcaeea872507c6a4cf6e007f7fe269ed9d/ecdsa-0.19.2.tar.gz", hash = "sha256:62635b0ac1ca2e027f82122b5b81cb706edc38cd91c63dda28e4f3455a2bf930", size = 202432, upload-time = "2026-03-26T09:58:17.675Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/79/119091c98e2bf49e24ed9f3ae69f816d715d2904aefa6a2baa039a2ba0b0/ecdsa-0.19.2-py2.py3-none-any.whl", hash = "sha256:840f5dc5e375c68f36c1a7a5b9caad28f95daa65185c9253c0c08dd952bb7399", size = 150818, upload-time = "2026-03-26T09:58:15.808Z" }, +] + [[package]] name = "exceptiongroup" version = "1.3.1" @@ -745,15 +793,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/4e/ce75a57ff3aebf6fc1f4e9d508b8e5810618a33d900ad6c19eb30b290b97/fonttools-4.61.1-py3-none-any.whl", hash = "sha256:17d2bf5d541add43822bcf0c43d7d847b160c9bb01d15d5007d84e2217aaa371", size = 1148996, upload-time = "2025-12-12T17:31:21.03Z" }, ] -[[package]] -name = "fsspec" -version = "2026.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/51/7c/f60c259dcbf4f0c47cc4ddb8f7720d2dcdc8888c8e5ad84c73ea4531cc5b/fsspec-2026.2.0.tar.gz", hash = "sha256:6544e34b16869f5aacd5b90bdf1a71acb37792ea3ddf6125ee69a22a53fb8bff", size = 313441, upload-time = "2026-02-05T21:50:53.743Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/ab/fb21f4c939bb440104cc2b396d3be1d9b7a9fd3c6c2a53d98c45b3d7c954/fsspec-2026.2.0-py3-none-any.whl", hash = "sha256:98de475b5cb3bd66bedd5c4679e87b4fdfe1a3bf4d707b151b3c07e58c9a2437", size = 202505, upload-time = "2026-02-05T21:50:51.819Z" }, -] - [[package]] name = "gitdb" version = "4.0.12" @@ -837,6 +876,7 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ea/ab/1608e5a7578e62113506740b88066bf09888322a311cff602105e619bd87/greenlet-3.3.2-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:ac8d61d4343b799d1e526db579833d72f23759c71e07181c2d2944e429eb09cd", size = 280358, upload-time = "2026-02-20T20:17:43.971Z" }, { url = "https://files.pythonhosted.org/packages/a5/23/0eae412a4ade4e6623ff7626e38998cb9b11e9ff1ebacaa021e4e108ec15/greenlet-3.3.2-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ceec72030dae6ac0c8ed7591b96b70410a8be370b6a477b1dbc072856ad02bd", size = 601217, upload-time = "2026-02-20T20:47:31.462Z" }, { url = "https://files.pythonhosted.org/packages/f8/16/5b1678a9c07098ecb9ab2dd159fafaf12e963293e61ee8d10ecb55273e5e/greenlet-3.3.2-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a2a5be83a45ce6188c045bcc44b0ee037d6a518978de9a5d97438548b953a1ac", size = 611792, upload-time = "2026-02-20T20:55:58.423Z" }, + { url = "https://files.pythonhosted.org/packages/5c/c5/cc09412a29e43406eba18d61c70baa936e299bc27e074e2be3806ed29098/greenlet-3.3.2-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ae9e21c84035c490506c17002f5c8ab25f980205c3e61ddb3a2a2a2e6c411fcb", size = 626250, upload-time = "2026-02-20T21:02:46.596Z" }, { url = "https://files.pythonhosted.org/packages/50/1f/5155f55bd71cabd03765a4aac9ac446be129895271f73872c36ebd4b04b6/greenlet-3.3.2-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43e99d1749147ac21dde49b99c9abffcbc1e2d55c67501465ef0930d6e78e070", size = 613875, upload-time = "2026-02-20T20:21:01.102Z" }, { url = "https://files.pythonhosted.org/packages/fc/dd/845f249c3fcd69e32df80cdab059b4be8b766ef5830a3d0aa9d6cad55beb/greenlet-3.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4c956a19350e2c37f2c48b336a3afb4bff120b36076d9d7fb68cb44e05d95b79", size = 1571467, upload-time = "2026-02-20T20:49:33.495Z" }, { url = "https://files.pythonhosted.org/packages/2a/50/2649fe21fcc2b56659a452868e695634722a6655ba245d9f77f5656010bf/greenlet-3.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6c6f8ba97d17a1e7d664151284cb3315fc5f8353e75221ed4324f84eb162b395", size = 1640001, upload-time = "2026-02-20T20:21:09.154Z" }, @@ -845,6 +885,7 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ac/48/f8b875fa7dea7dd9b33245e37f065af59df6a25af2f9561efa8d822fde51/greenlet-3.3.2-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:aa6ac98bdfd716a749b84d4034486863fd81c3abde9aa3cf8eff9127981a4ae4", size = 279120, upload-time = "2026-02-20T20:19:01.9Z" }, { url = "https://files.pythonhosted.org/packages/49/8d/9771d03e7a8b1ee456511961e1b97a6d77ae1dea4a34a5b98eee706689d3/greenlet-3.3.2-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ab0c7e7901a00bc0a7284907273dc165b32e0d109a6713babd04471327ff7986", size = 603238, upload-time = "2026-02-20T20:47:32.873Z" }, { url = "https://files.pythonhosted.org/packages/59/0e/4223c2bbb63cd5c97f28ffb2a8aee71bdfb30b323c35d409450f51b91e3e/greenlet-3.3.2-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d248d8c23c67d2291ffd47af766e2a3aa9fa1c6703155c099feb11f526c63a92", size = 614219, upload-time = "2026-02-20T20:55:59.817Z" }, + { url = "https://files.pythonhosted.org/packages/94/2b/4d012a69759ac9d77210b8bfb128bc621125f5b20fc398bce3940d036b1c/greenlet-3.3.2-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ccd21bb86944ca9be6d967cf7691e658e43417782bce90b5d2faeda0ff78a7dd", size = 628268, upload-time = "2026-02-20T21:02:48.024Z" }, { url = "https://files.pythonhosted.org/packages/7a/34/259b28ea7a2a0c904b11cd36c79b8cef8019b26ee5dbe24e73b469dea347/greenlet-3.3.2-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b6997d360a4e6a4e936c0f9625b1c20416b8a0ea18a8e19cabbefc712e7397ab", size = 616774, upload-time = "2026-02-20T20:21:02.454Z" }, { url = "https://files.pythonhosted.org/packages/0a/03/996c2d1689d486a6e199cb0f1cf9e4aa940c500e01bdf201299d7d61fa69/greenlet-3.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:64970c33a50551c7c50491671265d8954046cb6e8e2999aacdd60e439b70418a", size = 1571277, upload-time = "2026-02-20T20:49:34.795Z" }, { url = "https://files.pythonhosted.org/packages/d9/c4/2570fc07f34a39f2caf0bf9f24b0a1a0a47bc2e8e465b2c2424821389dfc/greenlet-3.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1a9172f5bf6bd88e6ba5a84e0a68afeac9dc7b6b412b245dd64f52d83c81e55b", size = 1640455, upload-time = "2026-02-20T20:21:10.261Z" }, @@ -853,6 +894,7 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3f/ae/8bffcbd373b57a5992cd077cbe8858fff39110480a9d50697091faea6f39/greenlet-3.3.2-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:8d1658d7291f9859beed69a776c10822a0a799bc4bfe1bd4272bb60e62507dab", size = 279650, upload-time = "2026-02-20T20:18:00.783Z" }, { url = "https://files.pythonhosted.org/packages/d1/c0/45f93f348fa49abf32ac8439938726c480bd96b2a3c6f4d949ec0124b69f/greenlet-3.3.2-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:18cb1b7337bca281915b3c5d5ae19f4e76d35e1df80f4ad3c1a7be91fadf1082", size = 650295, upload-time = "2026-02-20T20:47:34.036Z" }, { url = "https://files.pythonhosted.org/packages/b3/de/dd7589b3f2b8372069ab3e4763ea5329940fc7ad9dcd3e272a37516d7c9b/greenlet-3.3.2-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c2e47408e8ce1c6f1ceea0dffcdf6ebb85cc09e55c7af407c99f1112016e45e9", size = 662163, upload-time = "2026-02-20T20:56:01.295Z" }, + { url = "https://files.pythonhosted.org/packages/cd/ac/85804f74f1ccea31ba518dcc8ee6f14c79f73fe36fa1beba38930806df09/greenlet-3.3.2-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e3cb43ce200f59483eb82949bf1835a99cf43d7571e900d7c8d5c62cdf25d2f9", size = 675371, upload-time = "2026-02-20T21:02:49.664Z" }, { url = "https://files.pythonhosted.org/packages/d2/d8/09bfa816572a4d83bccd6750df1926f79158b1c36c5f73786e26dbe4ee38/greenlet-3.3.2-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63d10328839d1973e5ba35e98cccbca71b232b14051fd957b6f8b6e8e80d0506", size = 664160, upload-time = "2026-02-20T20:21:04.015Z" }, { url = "https://files.pythonhosted.org/packages/48/cf/56832f0c8255d27f6c35d41b5ec91168d74ec721d85f01a12131eec6b93c/greenlet-3.3.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8e4ab3cfb02993c8cc248ea73d7dae6cec0253e9afa311c9b37e603ca9fad2ce", size = 1619181, upload-time = "2026-02-20T20:49:36.052Z" }, { url = "https://files.pythonhosted.org/packages/0a/23/b90b60a4aabb4cec0796e55f25ffbfb579a907c3898cd2905c8918acaa16/greenlet-3.3.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:94ad81f0fd3c0c0681a018a976e5c2bd2ca2d9d94895f23e7bb1af4e8af4e2d5", size = 1687713, upload-time = "2026-02-20T20:21:11.684Z" }, @@ -861,53 +903,13 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/98/6d/8f2ef704e614bcf58ed43cfb8d87afa1c285e98194ab2cfad351bf04f81e/greenlet-3.3.2-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:e26e72bec7ab387ac80caa7496e0f908ff954f31065b0ffc1f8ecb1338b11b54", size = 286617, upload-time = "2026-02-20T20:19:29.856Z" }, { url = "https://files.pythonhosted.org/packages/5e/0d/93894161d307c6ea237a43988f27eba0947b360b99ac5239ad3fe09f0b47/greenlet-3.3.2-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b466dff7a4ffda6ca975979bab80bdadde979e29fc947ac3be4451428d8b0e4", size = 655189, upload-time = "2026-02-20T20:47:35.742Z" }, { url = "https://files.pythonhosted.org/packages/f5/2c/d2d506ebd8abcb57386ec4f7ba20f4030cbe56eae541bc6fd6ef399c0b41/greenlet-3.3.2-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b8bddc5b73c9720bea487b3bffdb1840fe4e3656fba3bd40aa1489e9f37877ff", size = 658225, upload-time = "2026-02-20T20:56:02.527Z" }, + { url = "https://files.pythonhosted.org/packages/d1/67/8197b7e7e602150938049d8e7f30de1660cfb87e4c8ee349b42b67bdb2e1/greenlet-3.3.2-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:59b3e2c40f6706b05a9cd299c836c6aa2378cabe25d021acd80f13abf81181cf", size = 666581, upload-time = "2026-02-20T21:02:51.526Z" }, { url = "https://files.pythonhosted.org/packages/8e/30/3a09155fbf728673a1dea713572d2d31159f824a37c22da82127056c44e4/greenlet-3.3.2-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b26b0f4428b871a751968285a1ac9648944cea09807177ac639b030bddebcea4", size = 657907, upload-time = "2026-02-20T20:21:05.259Z" }, { url = "https://files.pythonhosted.org/packages/f3/fd/d05a4b7acd0154ed758797f0a43b4c0962a843bedfe980115e842c5b2d08/greenlet-3.3.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1fb39a11ee2e4d94be9a76671482be9398560955c9e568550de0224e41104727", size = 1618857, upload-time = "2026-02-20T20:49:37.309Z" }, { url = "https://files.pythonhosted.org/packages/6f/e1/50ee92a5db521de8f35075b5eff060dd43d39ebd46c2181a2042f7070385/greenlet-3.3.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:20154044d9085151bc309e7689d6f7ba10027f8f5a8c0676ad398b951913d89e", size = 1680010, upload-time = "2026-02-20T20:21:13.427Z" }, { url = "https://files.pythonhosted.org/packages/29/4b/45d90626aef8e65336bed690106d1382f7a43665e2249017e9527df8823b/greenlet-3.3.2-cp314-cp314t-win_amd64.whl", hash = "sha256:c04c5e06ec3e022cbfe2cd4a846e1d4e50087444f875ff6d2c2ad8445495cf1a", size = 237086, upload-time = "2026-02-20T20:20:45.786Z" }, ] -[[package]] -name = "grpcio" -version = "1.78.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/8a/3d098f35c143a89520e568e6539cc098fcd294495910e359889ce8741c84/grpcio-1.78.0.tar.gz", hash = "sha256:7382b95189546f375c174f53a5fa873cef91c4b8005faa05cc5b3beea9c4f1c5", size = 12852416, upload-time = "2026-02-06T09:57:18.093Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/f4/7384ed0178203d6074446b3c4f46c90a22ddf7ae0b3aee521627f54cfc2a/grpcio-1.78.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:f9ab915a267fc47c7e88c387a3a28325b58c898e23d4995f765728f4e3dedb97", size = 5913985, upload-time = "2026-02-06T09:55:26.832Z" }, - { url = "https://files.pythonhosted.org/packages/81/ed/be1caa25f06594463f685b3790b320f18aea49b33166f4141bfdc2bfb236/grpcio-1.78.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3f8904a8165ab21e07e58bf3e30a73f4dffc7a1e0dbc32d51c61b5360d26f43e", size = 11811853, upload-time = "2026-02-06T09:55:29.224Z" }, - { url = "https://files.pythonhosted.org/packages/24/a7/f06d151afc4e64b7e3cc3e872d331d011c279aaab02831e40a81c691fb65/grpcio-1.78.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:859b13906ce098c0b493af92142ad051bf64c7870fa58a123911c88606714996", size = 6475766, upload-time = "2026-02-06T09:55:31.825Z" }, - { url = "https://files.pythonhosted.org/packages/8a/a8/4482922da832ec0082d0f2cc3a10976d84a7424707f25780b82814aafc0a/grpcio-1.78.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:b2342d87af32790f934a79c3112641e7b27d63c261b8b4395350dad43eff1dc7", size = 7170027, upload-time = "2026-02-06T09:55:34.7Z" }, - { url = "https://files.pythonhosted.org/packages/54/bf/f4a3b9693e35d25b24b0b39fa46d7d8a3c439e0a3036c3451764678fec20/grpcio-1.78.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:12a771591ae40bc65ba67048fa52ef4f0e6db8279e595fd349f9dfddeef571f9", size = 6690766, upload-time = "2026-02-06T09:55:36.902Z" }, - { url = "https://files.pythonhosted.org/packages/c7/b9/521875265cc99fe5ad4c5a17010018085cae2810a928bf15ebe7d8bcd9cc/grpcio-1.78.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:185dea0d5260cbb2d224c507bf2a5444d5abbb1fa3594c1ed7e4c709d5eb8383", size = 7266161, upload-time = "2026-02-06T09:55:39.824Z" }, - { url = "https://files.pythonhosted.org/packages/05/86/296a82844fd40a4ad4a95f100b55044b4f817dece732bf686aea1a284147/grpcio-1.78.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:51b13f9aed9d59ee389ad666b8c2214cc87b5de258fa712f9ab05f922e3896c6", size = 8253303, upload-time = "2026-02-06T09:55:42.353Z" }, - { url = "https://files.pythonhosted.org/packages/f3/e4/ea3c0caf5468537f27ad5aab92b681ed7cc0ef5f8c9196d3fd42c8c2286b/grpcio-1.78.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fd5f135b1bd58ab088930b3c613455796dfa0393626a6972663ccdda5b4ac6ce", size = 7698222, upload-time = "2026-02-06T09:55:44.629Z" }, - { url = "https://files.pythonhosted.org/packages/d7/47/7f05f81e4bb6b831e93271fb12fd52ba7b319b5402cbc101d588f435df00/grpcio-1.78.0-cp312-cp312-win32.whl", hash = "sha256:94309f498bcc07e5a7d16089ab984d42ad96af1d94b5a4eb966a266d9fcabf68", size = 4066123, upload-time = "2026-02-06T09:55:47.644Z" }, - { url = "https://files.pythonhosted.org/packages/ad/e7/d6914822c88aa2974dbbd10903d801a28a19ce9cd8bad7e694cbbcf61528/grpcio-1.78.0-cp312-cp312-win_amd64.whl", hash = "sha256:9566fe4ababbb2610c39190791e5b829869351d14369603702e890ef3ad2d06e", size = 4797657, upload-time = "2026-02-06T09:55:49.86Z" }, - { url = "https://files.pythonhosted.org/packages/05/a9/8f75894993895f361ed8636cd9237f4ab39ef87fd30db17467235ed1c045/grpcio-1.78.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:ce3a90455492bf8bfa38e56fbbe1dbd4f872a3d8eeaf7337dc3b1c8aa28c271b", size = 5920143, upload-time = "2026-02-06T09:55:52.035Z" }, - { url = "https://files.pythonhosted.org/packages/55/06/0b78408e938ac424100100fd081189451b472236e8a3a1f6500390dc4954/grpcio-1.78.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:2bf5e2e163b356978b23652c4818ce4759d40f4712ee9ec5a83c4be6f8c23a3a", size = 11803926, upload-time = "2026-02-06T09:55:55.494Z" }, - { url = "https://files.pythonhosted.org/packages/88/93/b59fe7832ff6ae3c78b813ea43dac60e295fa03606d14d89d2e0ec29f4f3/grpcio-1.78.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8f2ac84905d12918e4e55a16da17939eb63e433dc11b677267c35568aa63fc84", size = 6478628, upload-time = "2026-02-06T09:55:58.533Z" }, - { url = "https://files.pythonhosted.org/packages/ed/df/e67e3734527f9926b7d9c0dde6cd998d1d26850c3ed8eeec81297967ac67/grpcio-1.78.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:b58f37edab4a3881bc6c9bca52670610e0c9ca14e2ea3cf9debf185b870457fb", size = 7173574, upload-time = "2026-02-06T09:56:01.786Z" }, - { url = "https://files.pythonhosted.org/packages/a6/62/cc03fffb07bfba982a9ec097b164e8835546980aec25ecfa5f9c1a47e022/grpcio-1.78.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:735e38e176a88ce41840c21bb49098ab66177c64c82426e24e0082500cc68af5", size = 6692639, upload-time = "2026-02-06T09:56:04.529Z" }, - { url = "https://files.pythonhosted.org/packages/bf/9a/289c32e301b85bdb67d7ec68b752155e674ee3ba2173a1858f118e399ef3/grpcio-1.78.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2045397e63a7a0ee7957c25f7dbb36ddc110e0cfb418403d110c0a7a68a844e9", size = 7268838, upload-time = "2026-02-06T09:56:08.397Z" }, - { url = "https://files.pythonhosted.org/packages/0e/79/1be93f32add280461fa4773880196572563e9c8510861ac2da0ea0f892b6/grpcio-1.78.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9f136fbafe7ccf4ac7e8e0c28b31066e810be52d6e344ef954a3a70234e1702", size = 8251878, upload-time = "2026-02-06T09:56:10.914Z" }, - { url = "https://files.pythonhosted.org/packages/65/65/793f8e95296ab92e4164593674ae6291b204bb5f67f9d4a711489cd30ffa/grpcio-1.78.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:748b6138585379c737adc08aeffd21222abbda1a86a0dca2a39682feb9196c20", size = 7695412, upload-time = "2026-02-06T09:56:13.593Z" }, - { url = "https://files.pythonhosted.org/packages/1c/9f/1e233fe697ecc82845942c2822ed06bb522e70d6771c28d5528e4c50f6a4/grpcio-1.78.0-cp313-cp313-win32.whl", hash = "sha256:271c73e6e5676afe4fc52907686670c7cea22ab2310b76a59b678403ed40d670", size = 4064899, upload-time = "2026-02-06T09:56:15.601Z" }, - { url = "https://files.pythonhosted.org/packages/4d/27/d86b89e36de8a951501fb06a0f38df19853210f341d0b28f83f4aa0ffa08/grpcio-1.78.0-cp313-cp313-win_amd64.whl", hash = "sha256:f2d4e43ee362adfc05994ed479334d5a451ab7bc3f3fee1b796b8ca66895acb4", size = 4797393, upload-time = "2026-02-06T09:56:17.882Z" }, - { url = "https://files.pythonhosted.org/packages/29/f2/b56e43e3c968bfe822fa6ce5bca10d5c723aa40875b48791ce1029bb78c7/grpcio-1.78.0-cp314-cp314-linux_armv7l.whl", hash = "sha256:e87cbc002b6f440482b3519e36e1313eb5443e9e9e73d6a52d43bd2004fcfd8e", size = 5920591, upload-time = "2026-02-06T09:56:20.758Z" }, - { url = "https://files.pythonhosted.org/packages/5d/81/1f3b65bd30c334167bfa8b0d23300a44e2725ce39bba5b76a2460d85f745/grpcio-1.78.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:c41bc64626db62e72afec66b0c8a0da76491510015417c127bfc53b2fe6d7f7f", size = 11813685, upload-time = "2026-02-06T09:56:24.315Z" }, - { url = "https://files.pythonhosted.org/packages/0e/1c/bbe2f8216a5bd3036119c544d63c2e592bdf4a8ec6e4a1867592f4586b26/grpcio-1.78.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8dfffba826efcf366b1e3ccc37e67afe676f290e13a3b48d31a46739f80a8724", size = 6487803, upload-time = "2026-02-06T09:56:27.367Z" }, - { url = "https://files.pythonhosted.org/packages/16/5c/a6b2419723ea7ddce6308259a55e8e7593d88464ce8db9f4aa857aba96fa/grpcio-1.78.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:74be1268d1439eaaf552c698cdb11cd594f0c49295ae6bb72c34ee31abbe611b", size = 7173206, upload-time = "2026-02-06T09:56:29.876Z" }, - { url = "https://files.pythonhosted.org/packages/df/1e/b8801345629a415ea7e26c83d75eb5dbe91b07ffe5210cc517348a8d4218/grpcio-1.78.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:be63c88b32e6c0f1429f1398ca5c09bc64b0d80950c8bb7807d7d7fb36fb84c7", size = 6693826, upload-time = "2026-02-06T09:56:32.305Z" }, - { url = "https://files.pythonhosted.org/packages/34/84/0de28eac0377742679a510784f049738a80424b17287739fc47d63c2439e/grpcio-1.78.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3c586ac70e855c721bda8f548d38c3ca66ac791dc49b66a8281a1f99db85e452", size = 7277897, upload-time = "2026-02-06T09:56:34.915Z" }, - { url = "https://files.pythonhosted.org/packages/ca/9c/ad8685cfe20559a9edb66f735afdcb2b7d3de69b13666fdfc542e1916ebd/grpcio-1.78.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:35eb275bf1751d2ffbd8f57cdbc46058e857cf3971041521b78b7db94bdaf127", size = 8252404, upload-time = "2026-02-06T09:56:37.553Z" }, - { url = "https://files.pythonhosted.org/packages/3c/05/33a7a4985586f27e1de4803887c417ec7ced145ebd069bc38a9607059e2b/grpcio-1.78.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:207db540302c884b8848036b80db352a832b99dfdf41db1eb554c2c2c7800f65", size = 7696837, upload-time = "2026-02-06T09:56:40.173Z" }, - { url = "https://files.pythonhosted.org/packages/73/77/7382241caf88729b106e49e7d18e3116216c778e6a7e833826eb96de22f7/grpcio-1.78.0-cp314-cp314-win32.whl", hash = "sha256:57bab6deef2f4f1ca76cc04565df38dc5713ae6c17de690721bdf30cb1e0545c", size = 4142439, upload-time = "2026-02-06T09:56:43.258Z" }, - { url = "https://files.pythonhosted.org/packages/48/b2/b096ccce418882fbfda4f7496f9357aaa9a5af1896a9a7f60d9f2b275a06/grpcio-1.78.0-cp314-cp314-win_amd64.whl", hash = "sha256:dce09d6116df20a96acfdbf85e4866258c3758180e8c49845d6ba8248b6d0bbb", size = 4929852, upload-time = "2026-02-06T09:56:45.885Z" }, -] - [[package]] name = "gunicorn" version = "25.1.0" @@ -1114,6 +1116,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/67/8a/a342b2f0251f3dac4ca17618265d93bf244a2a4d089126e81e4c1056ac50/jiter-0.13.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bb00b6d26db67a05fe3e12c76edc75f32077fb51deed13822dc648fa373bc19", size = 343768, upload-time = "2026-02-02T12:37:55.055Z" }, ] +[[package]] +name = "jmespath" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d3/59/322338183ecda247fb5d1763a6cbe46eff7222eaeebafd9fa65d4bf5cb11/jmespath-1.1.0.tar.gz", hash = "sha256:472c87d80f36026ae83c6ddd0f1d05d4e510134ed462851fd5f754c8c3cbb88d", size = 27377, upload-time = "2026-01-22T16:35:26.279Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl", hash = "sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64", size = 20419, upload-time = "2026-01-22T16:35:24.919Z" }, +] + [[package]] name = "joblib" version = "1.5.3" @@ -1302,6 +1313,86 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b2/c8/d148e041732d631fc76036f8b30fae4e77b027a1e95b7a84bb522481a940/librt-0.8.1-cp314-cp314t-win_arm64.whl", hash = "sha256:bf512a71a23504ed08103a13c941f763db13fb11177beb3d9244c98c29fb4a61", size = 48755, upload-time = "2026-02-17T16:12:47.943Z" }, ] +[[package]] +name = "lxml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/88/262177de60548e5a2bfc46ad28232c9e9cbde697bd94132aeb80364675cb/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62", size = 4073426, upload-time = "2025-09-22T04:04:59.287Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/c8/8ff2bc6b920c84355146cd1ab7d181bc543b89241cfb1ebee824a7c81457/lxml-6.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a59f5448ba2ceccd06995c95ea59a7674a10de0810f2ce90c9006f3cbc044456", size = 8661887, upload-time = "2025-09-22T04:01:17.265Z" }, + { url = "https://files.pythonhosted.org/packages/37/6f/9aae1008083bb501ef63284220ce81638332f9ccbfa53765b2b7502203cf/lxml-6.0.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e8113639f3296706fbac34a30813929e29247718e88173ad849f57ca59754924", size = 4667818, upload-time = "2025-09-22T04:01:19.688Z" }, + { url = "https://files.pythonhosted.org/packages/f1/ca/31fb37f99f37f1536c133476674c10b577e409c0a624384147653e38baf2/lxml-6.0.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a8bef9b9825fa8bc816a6e641bb67219489229ebc648be422af695f6e7a4fa7f", size = 4950807, upload-time = "2025-09-22T04:01:21.487Z" }, + { url = "https://files.pythonhosted.org/packages/da/87/f6cb9442e4bada8aab5ae7e1046264f62fdbeaa6e3f6211b93f4c0dd97f1/lxml-6.0.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:65ea18d710fd14e0186c2f973dc60bb52039a275f82d3c44a0e42b43440ea534", size = 5109179, upload-time = "2025-09-22T04:01:23.32Z" }, + { url = "https://files.pythonhosted.org/packages/c8/20/a7760713e65888db79bbae4f6146a6ae5c04e4a204a3c48896c408cd6ed2/lxml-6.0.2-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c371aa98126a0d4c739ca93ceffa0fd7a5d732e3ac66a46e74339acd4d334564", size = 5023044, upload-time = "2025-09-22T04:01:25.118Z" }, + { url = "https://files.pythonhosted.org/packages/a2/b0/7e64e0460fcb36471899f75831509098f3fd7cd02a3833ac517433cb4f8f/lxml-6.0.2-cp312-cp312-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:700efd30c0fa1a3581d80a748157397559396090a51d306ea59a70020223d16f", size = 5359685, upload-time = "2025-09-22T04:01:27.398Z" }, + { url = "https://files.pythonhosted.org/packages/b9/e1/e5df362e9ca4e2f48ed6411bd4b3a0ae737cc842e96877f5bf9428055ab4/lxml-6.0.2-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c33e66d44fe60e72397b487ee92e01da0d09ba2d66df8eae42d77b6d06e5eba0", size = 5654127, upload-time = "2025-09-22T04:01:29.629Z" }, + { url = "https://files.pythonhosted.org/packages/c6/d1/232b3309a02d60f11e71857778bfcd4acbdb86c07db8260caf7d008b08f8/lxml-6.0.2-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90a345bbeaf9d0587a3aaffb7006aa39ccb6ff0e96a57286c0cb2fd1520ea192", size = 5253958, upload-time = "2025-09-22T04:01:31.535Z" }, + { url = "https://files.pythonhosted.org/packages/35/35/d955a070994725c4f7d80583a96cab9c107c57a125b20bb5f708fe941011/lxml-6.0.2-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:064fdadaf7a21af3ed1dcaa106b854077fbeada827c18f72aec9346847cd65d0", size = 4711541, upload-time = "2025-09-22T04:01:33.801Z" }, + { url = "https://files.pythonhosted.org/packages/1e/be/667d17363b38a78c4bd63cfd4b4632029fd68d2c2dc81f25ce9eb5224dd5/lxml-6.0.2-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fbc74f42c3525ac4ffa4b89cbdd00057b6196bcefe8bce794abd42d33a018092", size = 5267426, upload-time = "2025-09-22T04:01:35.639Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/62c70aa4a1c26569bc958c9ca86af2bb4e1f614e8c04fb2989833874f7ae/lxml-6.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6ddff43f702905a4e32bc24f3f2e2edfe0f8fde3277d481bffb709a4cced7a1f", size = 5064917, upload-time = "2025-09-22T04:01:37.448Z" }, + { url = "https://files.pythonhosted.org/packages/bd/55/6ceddaca353ebd0f1908ef712c597f8570cc9c58130dbb89903198e441fd/lxml-6.0.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6da5185951d72e6f5352166e3da7b0dc27aa70bd1090b0eb3f7f7212b53f1bb8", size = 4788795, upload-time = "2025-09-22T04:01:39.165Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e8/fd63e15da5e3fd4c2146f8bbb3c14e94ab850589beab88e547b2dbce22e1/lxml-6.0.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:57a86e1ebb4020a38d295c04fc79603c7899e0df71588043eb218722dabc087f", size = 5676759, upload-time = "2025-09-22T04:01:41.506Z" }, + { url = "https://files.pythonhosted.org/packages/76/47/b3ec58dc5c374697f5ba37412cd2728f427d056315d124dd4b61da381877/lxml-6.0.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:2047d8234fe735ab77802ce5f2297e410ff40f5238aec569ad7c8e163d7b19a6", size = 5255666, upload-time = "2025-09-22T04:01:43.363Z" }, + { url = "https://files.pythonhosted.org/packages/19/93/03ba725df4c3d72afd9596eef4a37a837ce8e4806010569bedfcd2cb68fd/lxml-6.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f91fd2b2ea15a6800c8e24418c0775a1694eefc011392da73bc6cef2623b322", size = 5277989, upload-time = "2025-09-22T04:01:45.215Z" }, + { url = "https://files.pythonhosted.org/packages/c6/80/c06de80bfce881d0ad738576f243911fccf992687ae09fd80b734712b39c/lxml-6.0.2-cp312-cp312-win32.whl", hash = "sha256:3ae2ce7d6fedfb3414a2b6c5e20b249c4c607f72cb8d2bb7cc9c6ec7c6f4e849", size = 3611456, upload-time = "2025-09-22T04:01:48.243Z" }, + { url = "https://files.pythonhosted.org/packages/f7/d7/0cdfb6c3e30893463fb3d1e52bc5f5f99684a03c29a0b6b605cfae879cd5/lxml-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:72c87e5ee4e58a8354fb9c7c84cbf95a1c8236c127a5d1b7683f04bed8361e1f", size = 4011793, upload-time = "2025-09-22T04:01:50.042Z" }, + { url = "https://files.pythonhosted.org/packages/ea/7b/93c73c67db235931527301ed3785f849c78991e2e34f3fd9a6663ffda4c5/lxml-6.0.2-cp312-cp312-win_arm64.whl", hash = "sha256:61cb10eeb95570153e0c0e554f58df92ecf5109f75eacad4a95baa709e26c3d6", size = 3672836, upload-time = "2025-09-22T04:01:52.145Z" }, + { url = "https://files.pythonhosted.org/packages/53/fd/4e8f0540608977aea078bf6d79f128e0e2c2bba8af1acf775c30baa70460/lxml-6.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9b33d21594afab46f37ae58dfadd06636f154923c4e8a4d754b0127554eb2e77", size = 8648494, upload-time = "2025-09-22T04:01:54.242Z" }, + { url = "https://files.pythonhosted.org/packages/5d/f4/2a94a3d3dfd6c6b433501b8d470a1960a20ecce93245cf2db1706adf6c19/lxml-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c8963287d7a4c5c9a432ff487c52e9c5618667179c18a204bdedb27310f022f", size = 4661146, upload-time = "2025-09-22T04:01:56.282Z" }, + { url = "https://files.pythonhosted.org/packages/25/2e/4efa677fa6b322013035d38016f6ae859d06cac67437ca7dc708a6af7028/lxml-6.0.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1941354d92699fb5ffe6ed7b32f9649e43c2feb4b97205f75866f7d21aa91452", size = 4946932, upload-time = "2025-09-22T04:01:58.989Z" }, + { url = "https://files.pythonhosted.org/packages/ce/0f/526e78a6d38d109fdbaa5049c62e1d32fdd70c75fb61c4eadf3045d3d124/lxml-6.0.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb2f6ca0ae2d983ded09357b84af659c954722bbf04dea98030064996d156048", size = 5100060, upload-time = "2025-09-22T04:02:00.812Z" }, + { url = "https://files.pythonhosted.org/packages/81/76/99de58d81fa702cc0ea7edae4f4640416c2062813a00ff24bd70ac1d9c9b/lxml-6.0.2-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb2a12d704f180a902d7fa778c6d71f36ceb7b0d317f34cdc76a5d05aa1dd1df", size = 5019000, upload-time = "2025-09-22T04:02:02.671Z" }, + { url = "https://files.pythonhosted.org/packages/b5/35/9e57d25482bc9a9882cb0037fdb9cc18f4b79d85df94fa9d2a89562f1d25/lxml-6.0.2-cp313-cp313-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:6ec0e3f745021bfed19c456647f0298d60a24c9ff86d9d051f52b509663feeb1", size = 5348496, upload-time = "2025-09-22T04:02:04.904Z" }, + { url = "https://files.pythonhosted.org/packages/a6/8e/cb99bd0b83ccc3e8f0f528e9aa1f7a9965dfec08c617070c5db8d63a87ce/lxml-6.0.2-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:846ae9a12d54e368933b9759052d6206a9e8b250291109c48e350c1f1f49d916", size = 5643779, upload-time = "2025-09-22T04:02:06.689Z" }, + { url = "https://files.pythonhosted.org/packages/d0/34/9e591954939276bb679b73773836c6684c22e56d05980e31d52a9a8deb18/lxml-6.0.2-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef9266d2aa545d7374938fb5c484531ef5a2ec7f2d573e62f8ce722c735685fd", size = 5244072, upload-time = "2025-09-22T04:02:08.587Z" }, + { url = "https://files.pythonhosted.org/packages/8d/27/b29ff065f9aaca443ee377aff699714fcbffb371b4fce5ac4ca759e436d5/lxml-6.0.2-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:4077b7c79f31755df33b795dc12119cb557a0106bfdab0d2c2d97bd3cf3dffa6", size = 4718675, upload-time = "2025-09-22T04:02:10.783Z" }, + { url = "https://files.pythonhosted.org/packages/2b/9f/f756f9c2cd27caa1a6ef8c32ae47aadea697f5c2c6d07b0dae133c244fbe/lxml-6.0.2-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a7c5d5e5f1081955358533be077166ee97ed2571d6a66bdba6ec2f609a715d1a", size = 5255171, upload-time = "2025-09-22T04:02:12.631Z" }, + { url = "https://files.pythonhosted.org/packages/61/46/bb85ea42d2cb1bd8395484fd72f38e3389611aa496ac7772da9205bbda0e/lxml-6.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8f8d0cbd0674ee89863a523e6994ac25fd5be9c8486acfc3e5ccea679bad2679", size = 5057175, upload-time = "2025-09-22T04:02:14.718Z" }, + { url = "https://files.pythonhosted.org/packages/95/0c/443fc476dcc8e41577f0af70458c50fe299a97bb6b7505bb1ae09aa7f9ac/lxml-6.0.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2cbcbf6d6e924c28f04a43f3b6f6e272312a090f269eff68a2982e13e5d57659", size = 4785688, upload-time = "2025-09-22T04:02:16.957Z" }, + { url = "https://files.pythonhosted.org/packages/48/78/6ef0b359d45bb9697bc5a626e1992fa5d27aa3f8004b137b2314793b50a0/lxml-6.0.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dfb874cfa53340009af6bdd7e54ebc0d21012a60a4e65d927c2e477112e63484", size = 5660655, upload-time = "2025-09-22T04:02:18.815Z" }, + { url = "https://files.pythonhosted.org/packages/ff/ea/e1d33808f386bc1339d08c0dcada6e4712d4ed8e93fcad5f057070b7988a/lxml-6.0.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fb8dae0b6b8b7f9e96c26fdd8121522ce5de9bb5538010870bd538683d30e9a2", size = 5247695, upload-time = "2025-09-22T04:02:20.593Z" }, + { url = "https://files.pythonhosted.org/packages/4f/47/eba75dfd8183673725255247a603b4ad606f4ae657b60c6c145b381697da/lxml-6.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:358d9adae670b63e95bc59747c72f4dc97c9ec58881d4627fe0120da0f90d314", size = 5269841, upload-time = "2025-09-22T04:02:22.489Z" }, + { url = "https://files.pythonhosted.org/packages/76/04/5c5e2b8577bc936e219becb2e98cdb1aca14a4921a12995b9d0c523502ae/lxml-6.0.2-cp313-cp313-win32.whl", hash = "sha256:e8cd2415f372e7e5a789d743d133ae474290a90b9023197fd78f32e2dc6873e2", size = 3610700, upload-time = "2025-09-22T04:02:24.465Z" }, + { url = "https://files.pythonhosted.org/packages/fe/0a/4643ccc6bb8b143e9f9640aa54e38255f9d3b45feb2cbe7ae2ca47e8782e/lxml-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:b30d46379644fbfc3ab81f8f82ae4de55179414651f110a1514f0b1f8f6cb2d7", size = 4010347, upload-time = "2025-09-22T04:02:26.286Z" }, + { url = "https://files.pythonhosted.org/packages/31/ef/dcf1d29c3f530577f61e5fe2f1bd72929acf779953668a8a47a479ae6f26/lxml-6.0.2-cp313-cp313-win_arm64.whl", hash = "sha256:13dcecc9946dca97b11b7c40d29fba63b55ab4170d3c0cf8c0c164343b9bfdcf", size = 3671248, upload-time = "2025-09-22T04:02:27.918Z" }, + { url = "https://files.pythonhosted.org/packages/03/15/d4a377b385ab693ce97b472fe0c77c2b16ec79590e688b3ccc71fba19884/lxml-6.0.2-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:b0c732aa23de8f8aec23f4b580d1e52905ef468afb4abeafd3fec77042abb6fe", size = 8659801, upload-time = "2025-09-22T04:02:30.113Z" }, + { url = "https://files.pythonhosted.org/packages/c8/e8/c128e37589463668794d503afaeb003987373c5f94d667124ffd8078bbd9/lxml-6.0.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4468e3b83e10e0317a89a33d28f7aeba1caa4d1a6fd457d115dd4ffe90c5931d", size = 4659403, upload-time = "2025-09-22T04:02:32.119Z" }, + { url = "https://files.pythonhosted.org/packages/00/ce/74903904339decdf7da7847bb5741fc98a5451b42fc419a86c0c13d26fe2/lxml-6.0.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:abd44571493973bad4598a3be7e1d807ed45aa2adaf7ab92ab7c62609569b17d", size = 4966974, upload-time = "2025-09-22T04:02:34.155Z" }, + { url = "https://files.pythonhosted.org/packages/1f/d3/131dec79ce61c5567fecf82515bd9bc36395df42501b50f7f7f3bd065df0/lxml-6.0.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:370cd78d5855cfbffd57c422851f7d3864e6ae72d0da615fca4dad8c45d375a5", size = 5102953, upload-time = "2025-09-22T04:02:36.054Z" }, + { url = "https://files.pythonhosted.org/packages/3a/ea/a43ba9bb750d4ffdd885f2cd333572f5bb900cd2408b67fdda07e85978a0/lxml-6.0.2-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:901e3b4219fa04ef766885fb40fa516a71662a4c61b80c94d25336b4934b71c0", size = 5055054, upload-time = "2025-09-22T04:02:38.154Z" }, + { url = "https://files.pythonhosted.org/packages/60/23/6885b451636ae286c34628f70a7ed1fcc759f8d9ad382d132e1c8d3d9bfd/lxml-6.0.2-cp314-cp314-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:a4bf42d2e4cf52c28cc1812d62426b9503cdb0c87a6de81442626aa7d69707ba", size = 5352421, upload-time = "2025-09-22T04:02:40.413Z" }, + { url = "https://files.pythonhosted.org/packages/48/5b/fc2ddfc94ddbe3eebb8e9af6e3fd65e2feba4967f6a4e9683875c394c2d8/lxml-6.0.2-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2c7fdaa4d7c3d886a42534adec7cfac73860b89b4e5298752f60aa5984641a0", size = 5673684, upload-time = "2025-09-22T04:02:42.288Z" }, + { url = "https://files.pythonhosted.org/packages/29/9c/47293c58cc91769130fbf85531280e8cc7868f7fbb6d92f4670071b9cb3e/lxml-6.0.2-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:98a5e1660dc7de2200b00d53fa00bcd3c35a3608c305d45a7bbcaf29fa16e83d", size = 5252463, upload-time = "2025-09-22T04:02:44.165Z" }, + { url = "https://files.pythonhosted.org/packages/9b/da/ba6eceb830c762b48e711ded880d7e3e89fc6c7323e587c36540b6b23c6b/lxml-6.0.2-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:dc051506c30b609238d79eda75ee9cab3e520570ec8219844a72a46020901e37", size = 4698437, upload-time = "2025-09-22T04:02:46.524Z" }, + { url = "https://files.pythonhosted.org/packages/a5/24/7be3f82cb7990b89118d944b619e53c656c97dc89c28cfb143fdb7cd6f4d/lxml-6.0.2-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8799481bbdd212470d17513a54d568f44416db01250f49449647b5ab5b5dccb9", size = 5269890, upload-time = "2025-09-22T04:02:48.812Z" }, + { url = "https://files.pythonhosted.org/packages/1b/bd/dcfb9ea1e16c665efd7538fc5d5c34071276ce9220e234217682e7d2c4a5/lxml-6.0.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9261bb77c2dab42f3ecd9103951aeca2c40277701eb7e912c545c1b16e0e4917", size = 5097185, upload-time = "2025-09-22T04:02:50.746Z" }, + { url = "https://files.pythonhosted.org/packages/21/04/a60b0ff9314736316f28316b694bccbbabe100f8483ad83852d77fc7468e/lxml-6.0.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:65ac4a01aba353cfa6d5725b95d7aed6356ddc0a3cd734de00124d285b04b64f", size = 4745895, upload-time = "2025-09-22T04:02:52.968Z" }, + { url = "https://files.pythonhosted.org/packages/d6/bd/7d54bd1846e5a310d9c715921c5faa71cf5c0853372adf78aee70c8d7aa2/lxml-6.0.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b22a07cbb82fea98f8a2fd814f3d1811ff9ed76d0fc6abc84eb21527596e7cc8", size = 5695246, upload-time = "2025-09-22T04:02:54.798Z" }, + { url = "https://files.pythonhosted.org/packages/fd/32/5643d6ab947bc371da21323acb2a6e603cedbe71cb4c99c8254289ab6f4e/lxml-6.0.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:d759cdd7f3e055d6bc8d9bec3ad905227b2e4c785dc16c372eb5b5e83123f48a", size = 5260797, upload-time = "2025-09-22T04:02:57.058Z" }, + { url = "https://files.pythonhosted.org/packages/33/da/34c1ec4cff1eea7d0b4cd44af8411806ed943141804ac9c5d565302afb78/lxml-6.0.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:945da35a48d193d27c188037a05fec5492937f66fb1958c24fc761fb9d40d43c", size = 5277404, upload-time = "2025-09-22T04:02:58.966Z" }, + { url = "https://files.pythonhosted.org/packages/82/57/4eca3e31e54dc89e2c3507e1cd411074a17565fa5ffc437c4ae0a00d439e/lxml-6.0.2-cp314-cp314-win32.whl", hash = "sha256:be3aaa60da67e6153eb15715cc2e19091af5dc75faef8b8a585aea372507384b", size = 3670072, upload-time = "2025-09-22T04:03:38.05Z" }, + { url = "https://files.pythonhosted.org/packages/e3/e0/c96cf13eccd20c9421ba910304dae0f619724dcf1702864fd59dd386404d/lxml-6.0.2-cp314-cp314-win_amd64.whl", hash = "sha256:fa25afbadead523f7001caf0c2382afd272c315a033a7b06336da2637d92d6ed", size = 4080617, upload-time = "2025-09-22T04:03:39.835Z" }, + { url = "https://files.pythonhosted.org/packages/d5/5d/b3f03e22b3d38d6f188ef044900a9b29b2fe0aebb94625ce9fe244011d34/lxml-6.0.2-cp314-cp314-win_arm64.whl", hash = "sha256:063eccf89df5b24e361b123e257e437f9e9878f425ee9aae3144c77faf6da6d8", size = 3754930, upload-time = "2025-09-22T04:03:41.565Z" }, + { url = "https://files.pythonhosted.org/packages/5e/5c/42c2c4c03554580708fc738d13414801f340c04c3eff90d8d2d227145275/lxml-6.0.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:6162a86d86893d63084faaf4ff937b3daea233e3682fb4474db07395794fa80d", size = 8910380, upload-time = "2025-09-22T04:03:01.645Z" }, + { url = "https://files.pythonhosted.org/packages/bf/4f/12df843e3e10d18d468a7557058f8d3733e8b6e12401f30b1ef29360740f/lxml-6.0.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:414aaa94e974e23a3e92e7ca5b97d10c0cf37b6481f50911032c69eeb3991bba", size = 4775632, upload-time = "2025-09-22T04:03:03.814Z" }, + { url = "https://files.pythonhosted.org/packages/e4/0c/9dc31e6c2d0d418483cbcb469d1f5a582a1cd00a1f4081953d44051f3c50/lxml-6.0.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48461bd21625458dd01e14e2c38dd0aea69addc3c4f960c30d9f59d7f93be601", size = 4975171, upload-time = "2025-09-22T04:03:05.651Z" }, + { url = "https://files.pythonhosted.org/packages/e7/2b/9b870c6ca24c841bdd887504808f0417aa9d8d564114689266f19ddf29c8/lxml-6.0.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:25fcc59afc57d527cfc78a58f40ab4c9b8fd096a9a3f964d2781ffb6eb33f4ed", size = 5110109, upload-time = "2025-09-22T04:03:07.452Z" }, + { url = "https://files.pythonhosted.org/packages/bf/0c/4f5f2a4dd319a178912751564471355d9019e220c20d7db3fb8307ed8582/lxml-6.0.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5179c60288204e6ddde3f774a93350177e08876eaf3ab78aa3a3649d43eb7d37", size = 5041061, upload-time = "2025-09-22T04:03:09.297Z" }, + { url = "https://files.pythonhosted.org/packages/12/64/554eed290365267671fe001a20d72d14f468ae4e6acef1e179b039436967/lxml-6.0.2-cp314-cp314t-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:967aab75434de148ec80597b75062d8123cadf2943fb4281f385141e18b21338", size = 5306233, upload-time = "2025-09-22T04:03:11.651Z" }, + { url = "https://files.pythonhosted.org/packages/7a/31/1d748aa275e71802ad9722df32a7a35034246b42c0ecdd8235412c3396ef/lxml-6.0.2-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d100fcc8930d697c6561156c6810ab4a508fb264c8b6779e6e61e2ed5e7558f9", size = 5604739, upload-time = "2025-09-22T04:03:13.592Z" }, + { url = "https://files.pythonhosted.org/packages/8f/41/2c11916bcac09ed561adccacceaedd2bf0e0b25b297ea92aab99fd03d0fa/lxml-6.0.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ca59e7e13e5981175b8b3e4ab84d7da57993eeff53c07764dcebda0d0e64ecd", size = 5225119, upload-time = "2025-09-22T04:03:15.408Z" }, + { url = "https://files.pythonhosted.org/packages/99/05/4e5c2873d8f17aa018e6afde417c80cc5d0c33be4854cce3ef5670c49367/lxml-6.0.2-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:957448ac63a42e2e49531b9d6c0fa449a1970dbc32467aaad46f11545be9af1d", size = 4633665, upload-time = "2025-09-22T04:03:17.262Z" }, + { url = "https://files.pythonhosted.org/packages/0f/c9/dcc2da1bebd6275cdc723b515f93edf548b82f36a5458cca3578bc899332/lxml-6.0.2-cp314-cp314t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b7fc49c37f1786284b12af63152fe1d0990722497e2d5817acfe7a877522f9a9", size = 5234997, upload-time = "2025-09-22T04:03:19.14Z" }, + { url = "https://files.pythonhosted.org/packages/9c/e2/5172e4e7468afca64a37b81dba152fc5d90e30f9c83c7c3213d6a02a5ce4/lxml-6.0.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e19e0643cc936a22e837f79d01a550678da8377d7d801a14487c10c34ee49c7e", size = 5090957, upload-time = "2025-09-22T04:03:21.436Z" }, + { url = "https://files.pythonhosted.org/packages/a5/b3/15461fd3e5cd4ddcb7938b87fc20b14ab113b92312fc97afe65cd7c85de1/lxml-6.0.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:1db01e5cf14345628e0cbe71067204db658e2fb8e51e7f33631f5f4735fefd8d", size = 4764372, upload-time = "2025-09-22T04:03:23.27Z" }, + { url = "https://files.pythonhosted.org/packages/05/33/f310b987c8bf9e61c4dd8e8035c416bd3230098f5e3cfa69fc4232de7059/lxml-6.0.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:875c6b5ab39ad5291588aed6925fac99d0097af0dd62f33c7b43736043d4a2ec", size = 5634653, upload-time = "2025-09-22T04:03:25.767Z" }, + { url = "https://files.pythonhosted.org/packages/70/ff/51c80e75e0bc9382158133bdcf4e339b5886c6ee2418b5199b3f1a61ed6d/lxml-6.0.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:cdcbed9ad19da81c480dfd6dd161886db6096083c9938ead313d94b30aadf272", size = 5233795, upload-time = "2025-09-22T04:03:27.62Z" }, + { url = "https://files.pythonhosted.org/packages/56/4d/4856e897df0d588789dd844dbed9d91782c4ef0b327f96ce53c807e13128/lxml-6.0.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:80dadc234ebc532e09be1975ff538d154a7fa61ea5031c03d25178855544728f", size = 5257023, upload-time = "2025-09-22T04:03:30.056Z" }, + { url = "https://files.pythonhosted.org/packages/0f/85/86766dfebfa87bea0ab78e9ff7a4b4b45225df4b4d3b8cc3c03c5cd68464/lxml-6.0.2-cp314-cp314t-win32.whl", hash = "sha256:da08e7bb297b04e893d91087df19638dc7a6bb858a954b0cc2b9f5053c922312", size = 3911420, upload-time = "2025-09-22T04:03:32.198Z" }, + { url = "https://files.pythonhosted.org/packages/fe/1a/b248b355834c8e32614650b8008c69ffeb0ceb149c793961dd8c0b991bb3/lxml-6.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:252a22982dca42f6155125ac76d3432e548a7625d56f5a273ee78a5057216eca", size = 4406837, upload-time = "2025-09-22T04:03:34.027Z" }, + { url = "https://files.pythonhosted.org/packages/92/aa/df863bcc39c5e0946263454aba394de8a9084dbaff8ad143846b0d844739/lxml-6.0.2-cp314-cp314t-win_arm64.whl", hash = "sha256:bb4c1847b303835d89d785a18801a883436cdfd5dc3d62947f9c49e24f0f5a2c", size = 3822205, upload-time = "2025-09-22T04:03:36.249Z" }, +] + [[package]] name = "mako" version = "1.3.10" @@ -1314,15 +1405,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/87/fb/99f81ac72ae23375f22b7afdb7642aba97c00a713c217124420147681a2f/mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59", size = 78509, upload-time = "2025-04-10T12:50:53.297Z" }, ] -[[package]] -name = "markdown" -version = "3.10.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2b/f4/69fa6ed85ae003c2378ffa8f6d2e3234662abd02c10d216c0ba96081a238/markdown-3.10.2.tar.gz", hash = "sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950", size = 368805, upload-time = "2026-02-09T14:57:26.942Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36", size = 108180, upload-time = "2026-02-09T14:57:25.787Z" }, -] - [[package]] name = "markdown-it-py" version = "4.0.0" @@ -1550,15 +1632,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/28/fa/b2ba8229b9381e8f6381c1dcae6f4159a7f72349e414ed19cfbbd1817173/MouseInfo-0.1.3.tar.gz", hash = "sha256:2c62fb8885062b8e520a3cce0a297c657adcc08c60952eb05bc8256ef6f7f6e7", size = 10850, upload-time = "2020-03-27T21:20:10.136Z" } -[[package]] -name = "mpmath" -version = "1.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, -] - [[package]] name = "mycdp" version = "1.3.2" @@ -1628,15 +1701,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" }, ] -[[package]] -name = "networkx" -version = "3.6.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6a/51/63fe664f3908c97be9d2e4f1158eb633317598cfa6e1fc14af5383f17512/networkx-3.6.1.tar.gz", hash = "sha256:26b7c357accc0c8cde558ad486283728b65b6a95d85ee1cd66bafab4c8168509", size = 2517025, upload-time = "2025-12-08T17:02:39.908Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl", hash = "sha256:d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762", size = 2068504, upload-time = "2025-12-08T17:02:38.159Z" }, -] - [[package]] name = "numpy" version = "2.4.2" @@ -1698,140 +1762,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/32/0a/2ec5deea6dcd158f254a7b372fb09cfba5719419c8d66343bab35237b3fb/numpy-2.4.2-cp314-cp314t-win_arm64.whl", hash = "sha256:1f92f53998a17265194018d1cc321b2e96e900ca52d54c7c77837b71b9465181", size = 10565379, upload-time = "2026-01-31T23:12:51.345Z" }, ] -[[package]] -name = "nvidia-cublas-cu12" -version = "12.8.4.1" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921, upload-time = "2025-03-07T01:44:31.254Z" }, -] - -[[package]] -name = "nvidia-cuda-cupti-cu12" -version = "12.8.90" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621, upload-time = "2025-03-07T01:40:21.213Z" }, -] - -[[package]] -name = "nvidia-cuda-nvrtc-cu12" -version = "12.8.93" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029, upload-time = "2025-03-07T01:42:13.562Z" }, -] - -[[package]] -name = "nvidia-cuda-runtime-cu12" -version = "12.8.90" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765, upload-time = "2025-03-07T01:40:01.615Z" }, -] - -[[package]] -name = "nvidia-cudnn-cu12" -version = "9.10.2.21" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nvidia-cublas-cu12" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467, upload-time = "2025-06-06T21:54:08.597Z" }, -] - -[[package]] -name = "nvidia-cufft-cu12" -version = "11.3.3.83" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nvidia-nvjitlink-cu12" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695, upload-time = "2025-03-07T01:45:27.821Z" }, -] - -[[package]] -name = "nvidia-cufile-cu12" -version = "1.13.1.3" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834, upload-time = "2025-03-07T01:45:50.723Z" }, -] - -[[package]] -name = "nvidia-curand-cu12" -version = "10.3.9.90" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976, upload-time = "2025-03-07T01:46:23.323Z" }, -] - -[[package]] -name = "nvidia-cusolver-cu12" -version = "11.7.3.90" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nvidia-cublas-cu12" }, - { name = "nvidia-cusparse-cu12" }, - { name = "nvidia-nvjitlink-cu12" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905, upload-time = "2025-03-07T01:47:16.273Z" }, -] - -[[package]] -name = "nvidia-cusparse-cu12" -version = "12.5.8.93" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nvidia-nvjitlink-cu12" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466, upload-time = "2025-03-07T01:48:13.779Z" }, -] - -[[package]] -name = "nvidia-cusparselt-cu12" -version = "0.7.1" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691, upload-time = "2025-02-26T00:15:44.104Z" }, -] - -[[package]] -name = "nvidia-nccl-cu12" -version = "2.27.5" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6e/89/f7a07dc961b60645dbbf42e80f2bc85ade7feb9a491b11a1e973aa00071f/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457", size = 322348229, upload-time = "2025-06-26T04:11:28.385Z" }, -] - -[[package]] -name = "nvidia-nvjitlink-cu12" -version = "12.8.93" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836, upload-time = "2025-03-07T01:49:55.661Z" }, -] - -[[package]] -name = "nvidia-nvshmem-cu12" -version = "3.4.5" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/09/6ea3ea725f82e1e76684f0708bbedd871fc96da89945adeba65c3835a64c/nvidia_nvshmem_cu12-3.4.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:042f2500f24c021db8a06c5eec2539027d57460e1c1a762055a6554f72c369bd", size = 139103095, upload-time = "2025-09-06T00:32:31.266Z" }, -] - -[[package]] -name = "nvidia-nvtx-cu12" -version = "12.8.90" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954, upload-time = "2025-03-07T01:42:44.131Z" }, -] - [[package]] name = "opentelemetry-api" version = "1.40.0" @@ -2314,6 +2244,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" }, ] +[[package]] +name = "pydantic-settings" +version = "2.13.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/6d/fffca34caecc4a3f97bda81b2098da5e8ab7efc9a66e819074a11955d87e/pydantic_settings-2.13.1.tar.gz", hash = "sha256:b4c11847b15237fb0171e1462bf540e294affb9b86db4d9aa5c01730bdbe4025", size = 223826, upload-time = "2026-02-19T13:45:08.055Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/4b/ccc026168948fec4f7555b9164c724cf4125eac006e176541483d2c959be/pydantic_settings-2.13.1-py3-none-any.whl", hash = "sha256:d56fd801823dbeae7f0975e1f8c8e25c258eb75d278ea7abb5d9cebb01b56237", size = 58929, upload-time = "2026-02-19T13:45:06.034Z" }, +] + [[package]] name = "pydeck" version = "0.9.1" @@ -2512,6 +2456,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, ] +[[package]] +name = "python-docx" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "lxml" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a9/f7/eddfe33871520adab45aaa1a71f0402a2252050c14c7e3009446c8f4701c/python_docx-1.2.0.tar.gz", hash = "sha256:7bc9d7b7d8a69c9c02ca09216118c86552704edc23bac179283f2e38f86220ce", size = 5723256, upload-time = "2025-06-16T20:46:27.921Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/00/1e03a4989fa5795da308cd774f05b704ace555a70f9bf9d3be057b680bcf/python_docx-1.2.0-py3-none-any.whl", hash = "sha256:3fd478f3250fbbbfd3b94fe1e985955737c145627498896a8a6bf81f4baf66c7", size = 252987, upload-time = "2025-06-16T20:46:22.506Z" }, +] + [[package]] name = "python-dotenv" version = "1.2.2" @@ -2521,6 +2478,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" }, ] +[[package]] +name = "python-jose" +version = "3.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ecdsa" }, + { name = "pyasn1" }, + { name = "rsa" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c6/77/3a1c9039db7124eb039772b935f2244fbb73fc8ee65b9acf2375da1c07bf/python_jose-3.5.0.tar.gz", hash = "sha256:fb4eaa44dbeb1c26dcc69e4bd7ec54a1cb8dd64d3b4d81ef08d90ff453f2b01b", size = 92726, upload-time = "2025-05-28T17:31:54.288Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/c3/0bd11992072e6a1c513b16500a5d07f91a24017c5909b02c72c62d7ad024/python_jose-3.5.0-py2.py3-none-any.whl", hash = "sha256:abd1202f23d34dfad2c3d28cb8617b90acf34132c7afd60abd0b0b7d3cb55771", size = 34624, upload-time = "2025-05-28T17:31:52.802Z" }, +] + +[package.optional-dependencies] +cryptography = [ + { name = "cryptography" }, +] + [[package]] name = "python-logging-loki" version = "0.3.1" @@ -2534,6 +2510,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e9/ca/1f5660fbda815ed04839d657cab77605337e32c224c03c780cd383c7bcd6/python_logging_loki-0.3.1-py3-none-any.whl", hash = "sha256:8a9131db037fbea3d390089c4c32dbe7ed233944905079615a9fb6f669b0f4e6", size = 7004, upload-time = "2019-11-28T22:34:36.635Z" }, ] +[[package]] +name = "python-multipart" +version = "0.0.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/01/979e98d542a70714b0cb2b6728ed0b7c46792b695e3eaec3e20711271ca3/python_multipart-0.0.22.tar.gz", hash = "sha256:7340bef99a7e0032613f56dc36027b959fd3b30a787ed62d310e951f7c3a3a58", size = 37612, upload-time = "2026-01-25T10:15:56.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl", hash = "sha256:2b2cd894c83d21bf49d702499531c7bafd057d730c201782048f7945d82de155", size = 24579, upload-time = "2026-01-25T10:15:54.811Z" }, +] + [[package]] name = "python-xlib" version = "0.33" @@ -2681,6 +2666,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" }, ] +[[package]] +name = "reportlab" +version = "4.4.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "charset-normalizer" }, + { name = "pillow" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/48/57/28bfbf0a775b618b6e4d854ef8dd3f5c8988e5d614d8898703502a35f61c/reportlab-4.4.10.tar.gz", hash = "sha256:5cbbb34ac3546039d0086deb2938cdec06b12da3cdb836e813258eb33cd28487", size = 3714962, upload-time = "2026-02-12T10:45:21.325Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/2e/e1798b8b248e1517e74c6cdf10dd6edd485044e7edf46b5f11ffcc5a0add/reportlab-4.4.10-py3-none-any.whl", hash = "sha256:5abc815746ae2bc44e7ff25db96814f921349ca814c992c7eac3c26029bf7c24", size = 1955400, upload-time = "2026-02-12T10:45:18.828Z" }, +] + [[package]] name = "requests" version = "2.32.5" @@ -2836,6 +2834,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fe/4e/cd76eca6db6115604b7626668e891c9dd03330384082e33662fb0f113614/ruff-0.15.5-py3-none-win_arm64.whl", hash = "sha256:b498d1c60d2fe5c10c45ec3f698901065772730b411f164ae270bb6bfcc4740b", size = 10965572, upload-time = "2026-03-05T20:06:16.984Z" }, ] +[[package]] +name = "s3transfer" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/05/04/74127fc843314818edfa81b5540e26dd537353b123a4edc563109d8f17dd/s3transfer-0.16.0.tar.gz", hash = "sha256:8e990f13268025792229cd52fa10cb7163744bf56e719e0b9cb925ab79abf920", size = 153827, upload-time = "2025-12-01T02:30:59.114Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/51/727abb13f44c1fcf6d145979e1535a35794db0f6e450a0cb46aa24732fe2/s3transfer-0.16.0-py3-none-any.whl", hash = "sha256:18e25d66fed509e3868dc1572b3f427ff947dd2c56f844a5bf09481ad3f3b2fe", size = 86830, upload-time = "2025-12-01T02:30:57.729Z" }, +] + [[package]] name = "sbvirtualdisplay" version = "1.4.0" @@ -3154,6 +3164,11 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/46/2c/9664130905f03db57961b8980b05cab624afd114bf2be2576628a9f22da4/sqlalchemy-2.0.48-py3-none-any.whl", hash = "sha256:a66fe406437dd65cacd96a72689a3aaaecaebbcd62d81c5ac1c0fdbeac835096", size = 1940202, upload-time = "2026-03-02T15:52:43.285Z" }, ] +[package.optional-dependencies] +asyncio = [ + { name = "greenlet" }, +] + [[package]] name = "sqlparse" version = "0.5.5" @@ -3205,18 +3220,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/dc/e6/412c1e1f200ca8c32ecf10201839183e261ad61ced3ede34a66f6d4be3cf/streamlit-1.55.0-py3-none-any.whl", hash = "sha256:1e4a16449c6131696180f4ddb40ea8c51834e89c2a43e1b0362bc9b1cfd9b415", size = 9075714, upload-time = "2026-03-03T22:25:59.126Z" }, ] -[[package]] -name = "sympy" -version = "1.14.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mpmath" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" }, -] - [[package]] name = "tabcompleter" version = "1.4.0" @@ -3238,36 +3241,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl", hash = "sha256:6095a360c919085f28c6527de529e76a06ad89b23659fa881ae0649b867a9d55", size = 28926, upload-time = "2026-02-07T10:45:32.24Z" }, ] -[[package]] -name = "tensorboard" -version = "2.20.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "absl-py" }, - { name = "grpcio" }, - { name = "markdown" }, - { name = "numpy" }, - { name = "packaging" }, - { name = "pillow" }, - { name = "protobuf" }, - { name = "setuptools" }, - { name = "tensorboard-data-server" }, - { name = "werkzeug" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/9c/d9/a5db55f88f258ac669a92858b70a714bbbd5acd993820b41ec4a96a4d77f/tensorboard-2.20.0-py3-none-any.whl", hash = "sha256:9dc9f978cb84c0723acf9a345d96c184f0293d18f166bb8d59ee098e6cfaaba6", size = 5525680, upload-time = "2025-07-17T19:20:49.638Z" }, -] - -[[package]] -name = "tensorboard-data-server" -version = "0.7.2" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/13/e503968fefabd4c6b2650af21e110aa8466fe21432cd7c43a84577a89438/tensorboard_data_server-0.7.2-py3-none-any.whl", hash = "sha256:7e0610d205889588983836ec05dc098e80f97b7e7bbff7e994ebb78f578d0ddb", size = 2356, upload-time = "2023-10-23T21:23:32.16Z" }, - { url = "https://files.pythonhosted.org/packages/b7/85/dabeaf902892922777492e1d253bb7e1264cadce3cea932f7ff599e53fea/tensorboard_data_server-0.7.2-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:9fe5d24221b29625dbc7328b0436ca7fc1c23de4acf4d272f1180856e32f9f60", size = 4823598, upload-time = "2023-10-23T21:23:33.714Z" }, - { url = "https://files.pythonhosted.org/packages/73/c6/825dab04195756cf8ff2e12698f22513b3db2f64925bdd41671bfb33aaa5/tensorboard_data_server-0.7.2-py3-none-manylinux_2_31_x86_64.whl", hash = "sha256:ef687163c24185ae9754ed5650eb5bc4d84ff257aabdc33f0cc6f74d8ba54530", size = 6590363, upload-time = "2023-10-23T21:23:35.583Z" }, -] - [[package]] name = "threadpoolctl" version = "3.6.0" @@ -3286,61 +3259,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588, upload-time = "2020-11-01T01:40:20.672Z" }, ] -[[package]] -name = "torch" -version = "2.10.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cuda-bindings", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "filelock" }, - { name = "fsspec" }, - { name = "jinja2" }, - { name = "networkx" }, - { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cufile-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cusparselt-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-nvshmem-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "setuptools" }, - { name = "sympy" }, - { name = "triton", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "typing-extensions" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/d3/54/a2ba279afcca44bbd320d4e73675b282fcee3d81400ea1b53934efca6462/torch-2.10.0-2-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:13ec4add8c3faaed8d13e0574f5cd4a323c11655546f91fbe6afa77b57423574", size = 79498202, upload-time = "2026-02-10T21:44:52.603Z" }, - { url = "https://files.pythonhosted.org/packages/ec/23/2c9fe0c9c27f7f6cb865abcea8a4568f29f00acaeadfc6a37f6801f84cb4/torch-2.10.0-2-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:e521c9f030a3774ed770a9c011751fb47c4d12029a3d6522116e48431f2ff89e", size = 79498254, upload-time = "2026-02-10T21:44:44.095Z" }, - { url = "https://files.pythonhosted.org/packages/cc/af/758e242e9102e9988969b5e621d41f36b8f258bb4a099109b7a4b4b50ea4/torch-2.10.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:5fd4117d89ffd47e3dcc71e71a22efac24828ad781c7e46aaaf56bf7f2796acf", size = 145996088, upload-time = "2026-01-21T16:24:44.171Z" }, - { url = "https://files.pythonhosted.org/packages/23/8e/3c74db5e53bff7ed9e34c8123e6a8bfef718b2450c35eefab85bb4a7e270/torch-2.10.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:787124e7db3b379d4f1ed54dd12ae7c741c16a4d29b49c0226a89bea50923ffb", size = 915711952, upload-time = "2026-01-21T16:23:53.503Z" }, - { url = "https://files.pythonhosted.org/packages/6e/01/624c4324ca01f66ae4c7cd1b74eb16fb52596dce66dbe51eff95ef9e7a4c/torch-2.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:2c66c61f44c5f903046cc696d088e21062644cbe541c7f1c4eaae88b2ad23547", size = 113757972, upload-time = "2026-01-21T16:24:39.516Z" }, - { url = "https://files.pythonhosted.org/packages/c9/5c/dee910b87c4d5c0fcb41b50839ae04df87c1cfc663cf1b5fca7ea565eeaa/torch-2.10.0-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:6d3707a61863d1c4d6ebba7be4ca320f42b869ee657e9b2c21c736bf17000294", size = 79498198, upload-time = "2026-01-21T16:24:34.704Z" }, - { url = "https://files.pythonhosted.org/packages/c9/6f/f2e91e34e3fcba2e3fc8d8f74e7d6c22e74e480bbd1db7bc8900fdf3e95c/torch-2.10.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:5c4d217b14741e40776dd7074d9006fd28b8a97ef5654db959d8635b2fe5f29b", size = 146004247, upload-time = "2026-01-21T16:24:29.335Z" }, - { url = "https://files.pythonhosted.org/packages/98/fb/5160261aeb5e1ee12ee95fe599d0541f7c976c3701d607d8fc29e623229f/torch-2.10.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:6b71486353fce0f9714ca0c9ef1c850a2ae766b409808acd58e9678a3edb7738", size = 915716445, upload-time = "2026-01-21T16:22:45.353Z" }, - { url = "https://files.pythonhosted.org/packages/6a/16/502fb1b41e6d868e8deb5b0e3ae926bbb36dab8ceb0d1b769b266ad7b0c3/torch-2.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:c2ee399c644dc92ef7bc0d4f7e74b5360c37cdbe7c5ba11318dda49ffac2bc57", size = 113757050, upload-time = "2026-01-21T16:24:19.204Z" }, - { url = "https://files.pythonhosted.org/packages/1a/0b/39929b148f4824bc3ad6f9f72a29d4ad865bcf7ebfc2fa67584773e083d2/torch-2.10.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:3202429f58309b9fa96a614885eace4b7995729f44beb54d3e4a47773649d382", size = 79851305, upload-time = "2026-01-21T16:24:09.209Z" }, - { url = "https://files.pythonhosted.org/packages/d8/14/21fbce63bc452381ba5f74a2c0a959fdf5ad5803ccc0c654e752e0dbe91a/torch-2.10.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:aae1b29cd68e50a9397f5ee897b9c24742e9e306f88a807a27d617f07adb3bd8", size = 146005472, upload-time = "2026-01-21T16:22:29.022Z" }, - { url = "https://files.pythonhosted.org/packages/54/fd/b207d1c525cb570ef47f3e9f836b154685011fce11a2f444ba8a4084d042/torch-2.10.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:6021db85958db2f07ec94e1bc77212721ba4920c12a18dc552d2ae36a3eb163f", size = 915612644, upload-time = "2026-01-21T16:21:47.019Z" }, - { url = "https://files.pythonhosted.org/packages/36/53/0197f868c75f1050b199fe58f9bf3bf3aecac9b4e85cc9c964383d745403/torch-2.10.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff43db38af76fda183156153983c9a096fc4c78d0cd1e07b14a2314c7f01c2c8", size = 113997015, upload-time = "2026-01-21T16:23:00.767Z" }, - { url = "https://files.pythonhosted.org/packages/0e/13/e76b4d9c160e89fff48bf16b449ea324bda84745d2ab30294c37c2434c0d/torch-2.10.0-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:cdf2a523d699b70d613243211ecaac14fe9c5df8a0b0a9c02add60fb2a413e0f", size = 79498248, upload-time = "2026-01-21T16:23:09.315Z" }, - { url = "https://files.pythonhosted.org/packages/4f/93/716b5ac0155f1be70ed81bacc21269c3ece8dba0c249b9994094110bfc51/torch-2.10.0-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:bf0d9ff448b0218e0433aeb198805192346c4fd659c852370d5cc245f602a06a", size = 79464992, upload-time = "2026-01-21T16:23:05.162Z" }, - { url = "https://files.pythonhosted.org/packages/69/2b/51e663ff190c9d16d4a8271203b71bc73a16aa7619b9f271a69b9d4a936b/torch-2.10.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:233aed0659a2503b831d8a67e9da66a62c996204c0bba4f4c442ccc0c68a3f60", size = 146018567, upload-time = "2026-01-21T16:22:23.393Z" }, - { url = "https://files.pythonhosted.org/packages/5e/cd/4b95ef7f293b927c283db0b136c42be91c8ec6845c44de0238c8c23bdc80/torch-2.10.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:682497e16bdfa6efeec8cde66531bc8d1fbbbb4d8788ec6173c089ed3cc2bfe5", size = 915721646, upload-time = "2026-01-21T16:21:16.983Z" }, - { url = "https://files.pythonhosted.org/packages/56/97/078a007208f8056d88ae43198833469e61a0a355abc0b070edd2c085eb9a/torch-2.10.0-cp314-cp314-win_amd64.whl", hash = "sha256:6528f13d2a8593a1a412ea07a99812495bec07e9224c28b2a25c0a30c7da025c", size = 113752373, upload-time = "2026-01-21T16:22:13.471Z" }, - { url = "https://files.pythonhosted.org/packages/d8/94/71994e7d0d5238393df9732fdab607e37e2b56d26a746cb59fdb415f8966/torch-2.10.0-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:f5ab4ba32383061be0fb74bda772d470140a12c1c3b58a0cfbf3dae94d164c28", size = 79850324, upload-time = "2026-01-21T16:22:09.494Z" }, - { url = "https://files.pythonhosted.org/packages/e2/65/1a05346b418ea8ccd10360eef4b3e0ce688fba544e76edec26913a8d0ee0/torch-2.10.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:716b01a176c2a5659c98f6b01bf868244abdd896526f1c692712ab36dbaf9b63", size = 146006482, upload-time = "2026-01-21T16:22:18.42Z" }, - { url = "https://files.pythonhosted.org/packages/1d/b9/5f6f9d9e859fc3235f60578fa64f52c9c6e9b4327f0fe0defb6de5c0de31/torch-2.10.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:d8f5912ba938233f86361e891789595ff35ca4b4e2ac8fe3670895e5976731d6", size = 915613050, upload-time = "2026-01-21T16:20:49.035Z" }, - { url = "https://files.pythonhosted.org/packages/66/4d/35352043ee0eaffdeff154fad67cd4a31dbed7ff8e3be1cc4549717d6d51/torch-2.10.0-cp314-cp314t-win_amd64.whl", hash = "sha256:71283a373f0ee2c89e0f0d5f446039bdabe8dbc3c9ccf35f0f784908b0acd185", size = 113995816, upload-time = "2026-01-21T16:22:05.312Z" }, -] - [[package]] name = "tornado" version = "6.5.4" @@ -3403,18 +3321,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/19/eb640a397bba49ba49ef9dbe2e7e5c04202ba045b6ce2ec36e9cadc51e04/trio_websocket-0.12.2-py3-none-any.whl", hash = "sha256:df605665f1db533f4a386c94525870851096a223adcb97f72a07e8b4beba45b6", size = 21221, upload-time = "2025-02-25T05:16:57.545Z" }, ] -[[package]] -name = "triton" -version = "3.6.0" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/a8/cdf8b3e4c98132f965f88c2313a4b493266832ad47fb52f23d14d4f86bb5/triton-3.6.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:74caf5e34b66d9f3a429af689c1c7128daba1d8208df60e81106b115c00d6fca", size = 188266850, upload-time = "2026-01-20T16:00:43.041Z" }, - { url = "https://files.pythonhosted.org/packages/f9/0b/37d991d8c130ce81a8728ae3c25b6e60935838e9be1b58791f5997b24a54/triton-3.6.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10c7f76c6e72d2ef08df639e3d0d30729112f47a56b0c81672edc05ee5116ac9", size = 188289450, upload-time = "2026-01-20T16:00:49.136Z" }, - { url = "https://files.pythonhosted.org/packages/35/f8/9c66bfc55361ec6d0e4040a0337fb5924ceb23de4648b8a81ae9d33b2b38/triton-3.6.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d002e07d7180fd65e622134fbd980c9a3d4211fb85224b56a0a0efbd422ab72f", size = 188400296, upload-time = "2026-01-20T16:00:56.042Z" }, - { url = "https://files.pythonhosted.org/packages/df/3d/9e7eee57b37c80cec63322c0231bb6da3cfe535a91d7a4d64896fcb89357/triton-3.6.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a17a5d5985f0ac494ed8a8e54568f092f7057ef60e1b0fa09d3fd1512064e803", size = 188273063, upload-time = "2026-01-20T16:01:07.278Z" }, - { url = "https://files.pythonhosted.org/packages/f6/56/6113c23ff46c00aae423333eb58b3e60bdfe9179d542781955a5e1514cb3/triton-3.6.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:46bd1c1af4b6704e554cad2eeb3b0a6513a980d470ccfa63189737340c7746a7", size = 188397994, upload-time = "2026-01-20T16:01:14.236Z" }, -] - [[package]] name = "typing-extensions" version = "4.15.0" @@ -3463,21 +3369,28 @@ version = "0.1.0" source = { editable = "." } dependencies = [ { name = "anthropic" }, + { name = "asyncpg" }, { name = "beautifulsoup4" }, + { name = "boto3" }, { name = "celery", extra = ["redis"] }, { name = "fastapi" }, { name = "flask" }, { name = "flask-cors" }, + { name = "httpx" }, { name = "pydantic" }, + { name = "pydantic-settings" }, + { name = "python-docx" }, { name = "python-dotenv" }, + { name = "python-jose", extra = ["cryptography"] }, { name = "python-logging-loki" }, + { name = "python-multipart" }, { name = "pyyaml" }, { name = "redis" }, + { name = "reportlab" }, { name = "requests" }, { name = "seleniumbase" }, + { name = "sqlalchemy", extra = ["asyncio"] }, { name = "streamlit" }, - { name = "tensorboard" }, - { name = "torch" }, { name = "tqdm" }, { name = "uvicorn", extra = ["standard"] }, ] @@ -3498,22 +3411,29 @@ dev = [ [package.metadata] requires-dist = [ { name = "anthropic" }, + { name = "asyncpg" }, { name = "beautifulsoup4" }, + { name = "boto3" }, { name = "celery", extras = ["redis"] }, { name = "fastapi" }, { name = "flask" }, { name = "flask-cors" }, + { name = "httpx" }, { name = "mlflow", marker = "extra == 'mlflow'" }, { name = "pydantic" }, + { name = "pydantic-settings" }, + { name = "python-docx" }, { name = "python-dotenv" }, + { name = "python-jose", extras = ["cryptography"] }, { name = "python-logging-loki" }, + { name = "python-multipart" }, { name = "pyyaml" }, { name = "redis" }, + { name = "reportlab" }, { name = "requests" }, { name = "seleniumbase" }, + { name = "sqlalchemy", extras = ["asyncio"] }, { name = "streamlit" }, - { name = "tensorboard" }, - { name = "torch" }, { name = "tqdm" }, { name = "uvicorn", extras = ["standard"] }, ]