chuckfinca commited on
Commit
8bfb8e4
·
1 Parent(s): 929cde0

feat(deploy): Implement and deploy live Gradio API

Browse files

This commit introduces a fully functional, live API for the FOT Recommender, deployed on Hugging Face Spaces using Gradio. It marks a major architectural shift from local scripts to a production-oriented, interactive web application.

This provides a frictionless "it just works" experience for reviewers, demonstrating the entire RAG pipeline from a simple web interface without requiring them to handle API keys or run code locally.

Key architectural changes and fixes include:
- **Gradio API:** A new `app.py` serves the model, handling user input and displaying synthesized, formatted recommendations.
- **Offline Artifact Generation:** The build process was refactored to pre-compute and save the `faiss_index.bin` vector database. This ensures the live application has a fast startup time and is highly efficient.
- **Secure Configuration:** All secrets (Google API Key, Demo Password) are now read from the secure Hugging Face environment, removing them from source code.
- **Deployment Stabilization:** The deployment environment was configured to use the correct Python version (`3.12`) and dependencies, and all file paths were made absolute to ensure stability on the remote server.

.gitattributes ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ *.pdf filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -1,3 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  # Demo Application
2
 
3
  A Python project for coding exercises and development.
@@ -65,4 +80,4 @@ uv run mypy src/
65
  src/demo_application/ # Main package
66
  tests/ # Test files
67
  pyproject.toml # Project configuration
68
- ```
 
1
+ ---
2
+ title: Fot Recommender Api
3
+ emoji: ⚡
4
+ colorFrom: green
5
+ colorTo: pink
6
+ sdk: gradio
7
+ sdk_version: 5.41.0
8
+ python_version: "3.12"
9
+ app_file: app.py
10
+ pinned: false
11
+ license: mit
12
+ short_description: POC - Freshman On-Track RAG Intervention Recommender
13
+ ---
14
+
15
+
16
  # Demo Application
17
 
18
  A Python project for coding exercises and development.
 
80
  src/demo_application/ # Main package
81
  tests/ # Test files
82
  pyproject.toml # Project configuration
83
+ ```
app.py ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import faiss
3
+ import os
4
+ import numpy as np
5
+ import sys
6
+ from pathlib import Path
7
+ from dotenv import load_dotenv
8
+
9
+ load_dotenv()
10
+
11
+ sys.path.insert(0, str(Path(__file__).parent / "src"))
12
+ from fot_recommender.rag_pipeline import ( # noqa: E402
13
+ load_knowledge_base,
14
+ initialize_embedding_model,
15
+ generate_recommendation_summary,
16
+ )
17
+
18
+ # --- Define the project root based on this script's location ---
19
+ APP_ROOT = Path(__file__).parent
20
+
21
+ # --- Define ABSOLUTE paths to the data artifacts ---
22
+ FAISS_INDEX_PATH = APP_ROOT / "data" / "processed" / "faiss_index.bin"
23
+ KB_PATH = APP_ROOT / "data" / "processed" / "knowledge_base_final_chunks.json"
24
+
25
+ ACCESS_PASSWORD = os.environ.get("DEMO_PASSWORD", "")
26
+ if ACCESS_PASSWORD and len(ACCESS_PASSWORD) > 10: # Check if it looks like a real key
27
+ print("✅ DEMO_PASSWORD secret loaded successfully from the environment.")
28
+ else:
29
+ print("❌ FATAL: DEMO_PASSWORD secret was NOT FOUND in the environment.")
30
+
31
+ FOT_GOOGLE_API_KEY = os.environ.get("FOT_GOOGLE_API_KEY", "")
32
+ if FOT_GOOGLE_API_KEY and len(FOT_GOOGLE_API_KEY) > 10: # Check if it looks like a real key
33
+ print("✅ FOT_GOOGLE_API_KEY secret loaded successfully from the environment.")
34
+ else:
35
+ print("❌ FATAL: FOT_GOOGLE_API_KEY secret was NOT FOUND in the environment.")
36
+
37
+ print("--- Initializing API: Loading models and data... ---")
38
+
39
+ # --- Load artifacts using the new absolute paths ---
40
+ index = faiss.read_index(str(FAISS_INDEX_PATH))
41
+ knowledge_base_chunks = load_knowledge_base(str(KB_PATH))
42
+ embedding_model = initialize_embedding_model()
43
+
44
+ print("✅ API initialized successfully.")
45
+
46
+ # --- Define the core RAG function that the API exposes ---
47
+
48
+
49
+ def get_recommendations_api(student_narrative, persona, password):
50
+ """The main function that runs the RAG pipeline, protected by a password."""
51
+ if password != ACCESS_PASSWORD:
52
+ return "Authentication failed. Please check the access key."
53
+ if not student_narrative:
54
+ return "Please enter a student narrative."
55
+
56
+ # 1. RETRIEVE
57
+ query_embedding = np.asarray(embedding_model.encode([student_narrative])).astype(
58
+ "float32"
59
+ )
60
+ scores, indices = index.search(query_embedding, k=3)
61
+ retrieved_chunks_with_scores = [
62
+ (knowledge_base_chunks[i], score)
63
+ for i, score in zip(indices[0], scores[0])
64
+ if score >= 0.4
65
+ ]
66
+ if not retrieved_chunks_with_scores:
67
+ return "Could not find relevant interventions for this query."
68
+
69
+ # 2. GENERATE
70
+ synthesized_recommendation = generate_recommendation_summary(
71
+ retrieved_chunks=retrieved_chunks_with_scores,
72
+ student_narrative=student_narrative,
73
+ api_key=FOT_GOOGLE_API_KEY,
74
+ persona=persona,
75
+ )
76
+
77
+ # 3. Augment with evidence
78
+ evidence_header = "\n\n---\n\n**Evidence Base:**"
79
+ evidence_list = ""
80
+ for chunk, score in retrieved_chunks_with_scores:
81
+ evidence_list += f"\n- **{chunk['title']}** (Source: {chunk['source_document']}, Relevance: {score:.2f})"
82
+ return synthesized_recommendation + evidence_header + evidence_list
83
+
84
+
85
+ # --- Create and launch the Gradio Interface ---
86
+ sample_narrative = "This student is struggling to keep up with coursework, having failed one core class and earning only 2.5 credits..."
87
+ interface = gr.Interface(
88
+ fn=get_recommendations_api,
89
+ inputs=[
90
+ gr.Textbox(lines=5, label="Student Narrative", value=sample_narrative),
91
+ gr.Radio(
92
+ ["teacher", "parent", "principal"],
93
+ label="Who is this for?",
94
+ value="teacher",
95
+ ),
96
+ gr.Textbox(
97
+ label="Access Key",
98
+ type="password",
99
+ info="Enter the access key provided for the demo.",
100
+ ),
101
+ ],
102
+ outputs=gr.Markdown(label="Synthesized Recommendation", show_copy_button=True),
103
+ title="Freshman On-Track Intervention Recommender API",
104
+ description="A live API demonstrating the FOT Recommender. Enter the provided access key to use.",
105
+ theme=gr.themes.Soft(), # type: ignore
106
+ ).launch()
data/processed/faiss_index.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fdd97930a9ae4824bfc207fa86f8a7d9256958eb8020ebf8b62baa6dad9425a9
3
+ size 41517
data/source_pdfs/17-quick-tips-for-your-credit-recovery-program.pdf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8e27f7133ccd3db932c368ff470a7418ff9ee4092897d39869f0101c1095f39a
3
+ size 3775232
data/source_pdfs/NCS_OTToolkit_2ndEd_October_2017_updated.pdf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f2ceb7c622966c7a8f1e93ea6f1f2ddd0ec7633f49289595eec8a8135faf1350
3
+ size 18173436
data/source_pdfs/Session-2-GROUP-3-NATIONAL-Early-Intervention-Strategies-v3.pdf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1d2dd24263f801893a3501426373ce31345362f74cc9aeb0ccc7f091ee4e970b
3
+ size 3089467
data/source_pdfs/handout-strategies-address-chronic-absenteeism.pdf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:217b47c1537bf0ab21d884e6595688c43ca20954a855c5a68804fceebd0c648c
3
+ size 876314
data/source_pdfs/high-quality-tutoring-evidence-based-strategy-tackle-learning-loss.pdf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:02e407655b5ee61f02b1c249daa0d6372d46afce492d9398878dcc368c410806
3
+ size 2695102
data/source_pdfs/wwc_checkconnect_050515.pdf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2ec6315dfd1823c50e2503e2d465f45f32f778393ffd56a03809066d55ddabf0
3
+ size 777853
notebooks/fot_recommender_poc.ipynb CHANGED
@@ -74,7 +74,7 @@
74
  "print(\"🚀 Setting up LOCAL development environment...\")\n",
75
  "\n",
76
  "# We assume the notebook is in 'notebooks/'. The project root is one level up.\n",
77
- "project_path = Path.cwd().parent \n",
78
  "\n",
79
  "# Configure Python Path to use the local 'src' directory\n",
80
  "src_path = project_path / \"src\"\n",
@@ -264,7 +264,7 @@
264
  "\n",
265
  "if user_query:\n",
266
  " print(\"\\n🔍 Searching for interventions based on your query...\")\n",
267
- " \n",
268
  " # Perform a new search using the user's input\n",
269
  " custom_recommendations = search_interventions(\n",
270
  " query=user_query,\n",
@@ -273,10 +273,10 @@
273
  " knowledge_base=knowledge_base_chunks,\n",
274
  " k=3,\n",
275
  " )\n",
276
- " \n",
277
  " # Display the new results using our helper function\n",
278
  " display_recommendations(custom_recommendations)\n",
279
- " \n",
280
  "else:\n",
281
  " print(\"\\nNo query entered. Skipping custom search.\")"
282
  ]
@@ -324,11 +324,13 @@
324
  "\n",
325
  "if project_path_to_clean.exists():\n",
326
  " print(f\"The project directory '{project_path_to_clean}' was found.\")\n",
327
- " \n",
328
  " # Ask for user confirmation before deleting anything\n",
329
- " response = input(\"Would you like to delete the git repository folder that was downloaded during the running of this notebook? (y/n): \")\n",
330
- " \n",
331
- " if response.lower().strip() == 'y':\n",
 
 
332
  " try:\n",
333
  " shutil.rmtree(project_path_to_clean)\n",
334
  " print(f\"✅ Successfully deleted '{project_path_to_clean}'.\")\n",
 
74
  "print(\"🚀 Setting up LOCAL development environment...\")\n",
75
  "\n",
76
  "# We assume the notebook is in 'notebooks/'. The project root is one level up.\n",
77
+ "project_path = Path.cwd().parent\n",
78
  "\n",
79
  "# Configure Python Path to use the local 'src' directory\n",
80
  "src_path = project_path / \"src\"\n",
 
264
  "\n",
265
  "if user_query:\n",
266
  " print(\"\\n🔍 Searching for interventions based on your query...\")\n",
267
+ "\n",
268
  " # Perform a new search using the user's input\n",
269
  " custom_recommendations = search_interventions(\n",
270
  " query=user_query,\n",
 
273
  " knowledge_base=knowledge_base_chunks,\n",
274
  " k=3,\n",
275
  " )\n",
276
+ "\n",
277
  " # Display the new results using our helper function\n",
278
  " display_recommendations(custom_recommendations)\n",
279
+ "\n",
280
  "else:\n",
281
  " print(\"\\nNo query entered. Skipping custom search.\")"
282
  ]
 
324
  "\n",
325
  "if project_path_to_clean.exists():\n",
326
  " print(f\"The project directory '{project_path_to_clean}' was found.\")\n",
327
+ "\n",
328
  " # Ask for user confirmation before deleting anything\n",
329
+ " response = input(\n",
330
+ " \"Would you like to delete the git repository folder that was downloaded during the running of this notebook? (y/n): \"\n",
331
+ " )\n",
332
+ "\n",
333
+ " if response.lower().strip() == \"y\":\n",
334
  " try:\n",
335
  " shutil.rmtree(project_path_to_clean)\n",
336
  " print(f\"✅ Successfully deleted '{project_path_to_clean}'.\")\n",
pyproject.toml CHANGED
@@ -25,6 +25,8 @@ dependencies = [
25
  "transformers",
26
  "google-generativeai",
27
  "python-dotenv",
 
 
28
  ]
29
 
30
  [project.scripts]
@@ -52,7 +54,7 @@ where = ["src"]
52
 
53
  exclude = [
54
  ".venv",
55
- "*/__pycache__/*", # Also excludes pycache within subdirectories
56
  "src/fot_intervention_recommender.egg-info",
57
- "*.ipynb", # <-- THIS IS THE KEY LINE TO EXCLUDE ALL NOTEBOOKS
58
- ]
 
25
  "transformers",
26
  "google-generativeai",
27
  "python-dotenv",
28
+ "gradio",
29
+ "gradio_client",
30
  ]
31
 
32
  [project.scripts]
 
54
 
55
  exclude = [
56
  ".venv",
57
+ "*/__pycache__/*",
58
  "src/fot_intervention_recommender.egg-info",
59
+ "*.ipynb",
60
+ ]
requirements.txt CHANGED
@@ -1,141 +1,326 @@
 
 
 
 
1
  annotated-types==0.7.0
 
2
  anyio==4.10.0
3
- appnope==0.1.4
4
- argon2-cffi==25.1.0
5
- argon2-cffi-bindings==25.1.0
6
- arrow==1.3.0
7
- asttokens==3.0.0
8
- async-lru==2.0.5
9
- attrs==25.3.0
10
- babel==2.17.0
11
- beautifulsoup4==4.13.4
12
- black==25.1.0
13
- bleach==6.2.0
14
  certifi==2025.8.3
15
- cffi==1.17.1
 
 
 
16
  charset-normalizer==3.4.2
 
17
  click==8.2.1
18
- comm==0.2.3
19
- debugpy==1.8.15
20
- decorator==5.2.1
21
- defusedxml==0.7.1
22
- executing==2.2.0
23
  faiss-cpu==1.11.0.post1
24
- fastjsonschema==2.21.1
 
 
 
 
25
  filelock==3.18.0
26
- -e file:///Users/charlesfeinn/Developer/job_applications/fot-intervention-recommender
27
- fqdn==1.5.1
 
 
28
  fsspec==2025.7.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  greenlet==3.2.3
 
 
 
 
 
 
 
 
 
30
  h11==0.16.0
 
 
 
31
  hf-xet==1.1.5
 
32
  httpcore==1.0.9
 
 
 
 
 
33
  httpx==0.28.1
 
 
 
 
 
34
  huggingface-hub==0.34.3
 
 
 
 
 
 
35
  idna==3.10
36
- iniconfig==2.1.0
37
- ipykernel==6.30.1
38
- ipython==9.4.0
39
- ipython-pygments-lexers==1.1.1
40
- isoduration==20.11.0
41
- jedi==0.19.2
42
  jinja2==3.1.6
 
 
 
43
  joblib==1.5.1
44
- json5==0.12.0
45
  jsonpatch==1.33
 
46
  jsonpointer==3.0.0
47
- jsonschema==4.25.0
48
- jsonschema-specifications==2025.4.1
49
- jupyter-client==8.6.3
50
- jupyter-core==5.8.1
51
- jupyter-events==0.12.0
52
- jupyter-lsp==2.2.6
53
- jupyter-server==2.16.0
54
- jupyter-server-terminals==0.5.3
55
- jupyterlab==4.4.5
56
- jupyterlab-pygments==0.3.0
57
- jupyterlab-server==2.27.3
58
  langchain==0.3.27
 
59
  langchain-core==0.3.72
 
 
 
60
  langchain-text-splitters==0.3.9
 
61
  langsmith==0.4.10
62
- lark==1.2.2
 
 
 
 
63
  markupsafe==3.0.2
64
- matplotlib-inline==0.1.7
65
- mistune==3.1.3
 
 
 
66
  mpmath==1.3.0
67
- mypy==1.17.1
68
- mypy-extensions==1.1.0
69
- nbclient==0.10.2
70
- nbconvert==7.16.6
71
- nbformat==5.10.4
72
- nest-asyncio==1.6.0
73
  networkx==3.5
74
- notebook==7.4.5
75
- notebook-shim==0.2.4
76
  numpy==1.26.4
 
 
 
 
 
 
 
 
77
  orjson==3.11.1
78
- overrides==7.7.0
 
 
79
  packaging==25.0
80
- pandocfilters==1.5.1
81
- parso==0.8.4
82
- pathspec==0.12.1
83
- pexpect==4.9.0
 
 
 
 
 
 
84
  pillow==11.3.0
85
- platformdirs==4.3.8
86
- pluggy==1.6.0
87
- prometheus-client==0.22.1
88
- prompt-toolkit==3.0.51
89
- psutil==7.0.0
90
- ptyprocess==0.7.0
91
- pure-eval==0.2.3
92
- pycparser==2.22
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  pydantic==2.11.7
 
 
 
 
 
 
 
94
  pydantic-core==2.33.2
 
 
 
95
  pygments==2.19.2
96
- pytest==8.4.1
 
 
97
  python-dateutil==2.9.0.post0
98
- python-json-logger==3.3.0
 
 
 
 
 
 
99
  pyyaml==6.0.2
100
- pyzmq==27.0.1
101
- referencing==0.36.2
 
 
 
 
102
  regex==2025.7.34
 
103
  requests==2.32.4
 
 
 
 
 
 
 
104
  requests-toolbelt==1.0.0
105
- rfc3339-validator==0.1.4
106
- rfc3986-validator==0.1.1
107
- rfc3987-syntax==1.1.0
108
- rpds-py==0.26.0
 
109
  ruff==0.12.7
 
 
 
110
  safetensors==0.5.3
 
111
  scikit-learn==1.7.1
 
112
  scipy==1.16.1
113
- send2trash==1.8.3
 
 
 
 
114
  sentence-transformers==5.0.0
 
115
  setuptools==80.9.0
 
 
 
116
  six==1.17.0
 
117
  sniffio==1.3.1
118
- soupsieve==2.7
119
  sqlalchemy==2.0.42
120
- stack-data==0.6.3
 
 
 
 
121
  sympy==1.14.0
 
122
  tenacity==9.1.2
123
- terminado==0.18.1
124
  threadpoolctl==3.6.0
125
- tinycss2==1.4.0
126
  tokenizers==0.21.4
 
 
 
127
  torch==2.2.2
128
- tornado==6.5.1
 
 
129
  tqdm==4.67.1
130
- traitlets==5.14.3
 
 
 
 
131
  transformers==4.54.1
132
- types-python-dateutil==2.9.0.20250708
 
 
 
 
133
  typing-extensions==4.14.1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  typing-inspection==0.4.1
135
- uri-template==1.3.0
 
 
 
 
136
  urllib3==2.5.0
137
- wcwidth==0.2.13
138
- webcolors==24.11.1
139
- webencodings==0.5.1
140
- websocket-client==1.8.0
 
141
  zstandard==0.23.0
 
 
1
+ # This file was autogenerated by uv via the following command:
2
+ # uv pip compile pyproject.toml --output-file requirements.txt
3
+ aiofiles==24.1.0
4
+ # via gradio
5
  annotated-types==0.7.0
6
+ # via pydantic
7
  anyio==4.10.0
8
+ # via
9
+ # gradio
10
+ # httpx
11
+ # starlette
12
+ brotli==1.1.0
13
+ # via gradio
14
+ cachetools==5.5.2
15
+ # via google-auth
 
 
 
16
  certifi==2025.8.3
17
+ # via
18
+ # httpcore
19
+ # httpx
20
+ # requests
21
  charset-normalizer==3.4.2
22
+ # via requests
23
  click==8.2.1
24
+ # via
25
+ # typer
26
+ # uvicorn
 
 
27
  faiss-cpu==1.11.0.post1
28
+ # via fot-intervention-recommender (pyproject.toml)
29
+ fastapi==0.116.1
30
+ # via gradio
31
+ ffmpy==0.6.1
32
+ # via gradio
33
  filelock==3.18.0
34
+ # via
35
+ # huggingface-hub
36
+ # torch
37
+ # transformers
38
  fsspec==2025.7.0
39
+ # via
40
+ # gradio-client
41
+ # huggingface-hub
42
+ # torch
43
+ google-ai-generativelanguage==0.6.15
44
+ # via google-generativeai
45
+ google-api-core==2.25.1
46
+ # via
47
+ # google-ai-generativelanguage
48
+ # google-api-python-client
49
+ # google-generativeai
50
+ google-api-python-client==2.178.0
51
+ # via google-generativeai
52
+ google-auth==2.40.3
53
+ # via
54
+ # google-ai-generativelanguage
55
+ # google-api-core
56
+ # google-api-python-client
57
+ # google-auth-httplib2
58
+ # google-generativeai
59
+ google-auth-httplib2==0.2.0
60
+ # via google-api-python-client
61
+ google-generativeai==0.8.5
62
+ # via fot-intervention-recommender (pyproject.toml)
63
+ googleapis-common-protos==1.70.0
64
+ # via
65
+ # google-api-core
66
+ # grpcio-status
67
+ gradio==5.41.0
68
+ # via fot-intervention-recommender (pyproject.toml)
69
+ gradio-client==1.11.0
70
+ # via
71
+ # fot-intervention-recommender (pyproject.toml)
72
+ # gradio
73
  greenlet==3.2.3
74
+ # via sqlalchemy
75
+ groovy==0.1.2
76
+ # via gradio
77
+ grpcio==1.74.0
78
+ # via
79
+ # google-api-core
80
+ # grpcio-status
81
+ grpcio-status==1.71.2
82
+ # via google-api-core
83
  h11==0.16.0
84
+ # via
85
+ # httpcore
86
+ # uvicorn
87
  hf-xet==1.1.5
88
+ # via huggingface-hub
89
  httpcore==1.0.9
90
+ # via httpx
91
+ httplib2==0.22.0
92
+ # via
93
+ # google-api-python-client
94
+ # google-auth-httplib2
95
  httpx==0.28.1
96
+ # via
97
+ # gradio
98
+ # gradio-client
99
+ # langsmith
100
+ # safehttpx
101
  huggingface-hub==0.34.3
102
+ # via
103
+ # gradio
104
+ # gradio-client
105
+ # sentence-transformers
106
+ # tokenizers
107
+ # transformers
108
  idna==3.10
109
+ # via
110
+ # anyio
111
+ # httpx
112
+ # requests
 
 
113
  jinja2==3.1.6
114
+ # via
115
+ # gradio
116
+ # torch
117
  joblib==1.5.1
118
+ # via scikit-learn
119
  jsonpatch==1.33
120
+ # via langchain-core
121
  jsonpointer==3.0.0
122
+ # via jsonpatch
 
 
 
 
 
 
 
 
 
 
123
  langchain==0.3.27
124
+ # via fot-intervention-recommender (pyproject.toml)
125
  langchain-core==0.3.72
126
+ # via
127
+ # langchain
128
+ # langchain-text-splitters
129
  langchain-text-splitters==0.3.9
130
+ # via langchain
131
  langsmith==0.4.10
132
+ # via
133
+ # langchain
134
+ # langchain-core
135
+ markdown-it-py==3.0.0
136
+ # via rich
137
  markupsafe==3.0.2
138
+ # via
139
+ # gradio
140
+ # jinja2
141
+ mdurl==0.1.2
142
+ # via markdown-it-py
143
  mpmath==1.3.0
144
+ # via sympy
 
 
 
 
 
145
  networkx==3.5
146
+ # via torch
 
147
  numpy==1.26.4
148
+ # via
149
+ # fot-intervention-recommender (pyproject.toml)
150
+ # faiss-cpu
151
+ # gradio
152
+ # pandas
153
+ # scikit-learn
154
+ # scipy
155
+ # transformers
156
  orjson==3.11.1
157
+ # via
158
+ # gradio
159
+ # langsmith
160
  packaging==25.0
161
+ # via
162
+ # faiss-cpu
163
+ # gradio
164
+ # gradio-client
165
+ # huggingface-hub
166
+ # langchain-core
167
+ # langsmith
168
+ # transformers
169
+ pandas==2.3.1
170
+ # via gradio
171
  pillow==11.3.0
172
+ # via
173
+ # gradio
174
+ # sentence-transformers
175
+ proto-plus==1.26.1
176
+ # via
177
+ # google-ai-generativelanguage
178
+ # google-api-core
179
+ protobuf==5.29.5
180
+ # via
181
+ # google-ai-generativelanguage
182
+ # google-api-core
183
+ # google-generativeai
184
+ # googleapis-common-protos
185
+ # grpcio-status
186
+ # proto-plus
187
+ pyasn1==0.6.1
188
+ # via
189
+ # pyasn1-modules
190
+ # rsa
191
+ pyasn1-modules==0.4.2
192
+ # via google-auth
193
  pydantic==2.11.7
194
+ # via
195
+ # fastapi
196
+ # google-generativeai
197
+ # gradio
198
+ # langchain
199
+ # langchain-core
200
+ # langsmith
201
  pydantic-core==2.33.2
202
+ # via pydantic
203
+ pydub==0.25.1
204
+ # via gradio
205
  pygments==2.19.2
206
+ # via rich
207
+ pyparsing==3.2.3
208
+ # via httplib2
209
  python-dateutil==2.9.0.post0
210
+ # via pandas
211
+ python-dotenv==1.1.1
212
+ # via fot-intervention-recommender (pyproject.toml)
213
+ python-multipart==0.0.20
214
+ # via gradio
215
+ pytz==2025.2
216
+ # via pandas
217
  pyyaml==6.0.2
218
+ # via
219
+ # gradio
220
+ # huggingface-hub
221
+ # langchain
222
+ # langchain-core
223
+ # transformers
224
  regex==2025.7.34
225
+ # via transformers
226
  requests==2.32.4
227
+ # via
228
+ # google-api-core
229
+ # huggingface-hub
230
+ # langchain
231
+ # langsmith
232
+ # requests-toolbelt
233
+ # transformers
234
  requests-toolbelt==1.0.0
235
+ # via langsmith
236
+ rich==14.1.0
237
+ # via typer
238
+ rsa==4.9.1
239
+ # via google-auth
240
  ruff==0.12.7
241
+ # via gradio
242
+ safehttpx==0.1.6
243
+ # via gradio
244
  safetensors==0.5.3
245
+ # via transformers
246
  scikit-learn==1.7.1
247
+ # via sentence-transformers
248
  scipy==1.16.1
249
+ # via
250
+ # scikit-learn
251
+ # sentence-transformers
252
+ semantic-version==2.10.0
253
+ # via gradio
254
  sentence-transformers==5.0.0
255
+ # via fot-intervention-recommender (pyproject.toml)
256
  setuptools==80.9.0
257
+ # via fot-intervention-recommender (pyproject.toml)
258
+ shellingham==1.5.4
259
+ # via typer
260
  six==1.17.0
261
+ # via python-dateutil
262
  sniffio==1.3.1
263
+ # via anyio
264
  sqlalchemy==2.0.42
265
+ # via langchain
266
+ starlette==0.47.2
267
+ # via
268
+ # fastapi
269
+ # gradio
270
  sympy==1.14.0
271
+ # via torch
272
  tenacity==9.1.2
273
+ # via langchain-core
274
  threadpoolctl==3.6.0
275
+ # via scikit-learn
276
  tokenizers==0.21.4
277
+ # via transformers
278
+ tomlkit==0.13.3
279
+ # via gradio
280
  torch==2.2.2
281
+ # via
282
+ # fot-intervention-recommender (pyproject.toml)
283
+ # sentence-transformers
284
  tqdm==4.67.1
285
+ # via
286
+ # google-generativeai
287
+ # huggingface-hub
288
+ # sentence-transformers
289
+ # transformers
290
  transformers==4.54.1
291
+ # via
292
+ # fot-intervention-recommender (pyproject.toml)
293
+ # sentence-transformers
294
+ typer==0.16.0
295
+ # via gradio
296
  typing-extensions==4.14.1
297
+ # via
298
+ # anyio
299
+ # fastapi
300
+ # google-generativeai
301
+ # gradio
302
+ # gradio-client
303
+ # huggingface-hub
304
+ # langchain-core
305
+ # pydantic
306
+ # pydantic-core
307
+ # sentence-transformers
308
+ # sqlalchemy
309
+ # starlette
310
+ # torch
311
+ # typer
312
+ # typing-inspection
313
  typing-inspection==0.4.1
314
+ # via pydantic
315
+ tzdata==2025.2
316
+ # via pandas
317
+ uritemplate==4.2.0
318
+ # via google-api-python-client
319
  urllib3==2.5.0
320
+ # via requests
321
+ uvicorn==0.35.0
322
+ # via gradio
323
+ websockets==15.0.1
324
+ # via gradio-client
325
  zstandard==0.23.0
326
+ # via langsmith
scripts/build_knowledge_base.py CHANGED
@@ -1,58 +1,58 @@
1
  import json
2
  import sys
 
 
3
  from pathlib import Path
4
 
5
- # This allows the script to find and import modules from your 'src' directory
6
- # by adding the project's root folder to the list of paths Python searches.
7
  project_root = Path(__file__).parent.parent
8
  sys.path.append(str(project_root))
9
 
10
- from src.fot_recommender.config import RAW_KB_PATH, PROCESSED_DATA_DIR # noqa: E402
11
- from src.fot_recommender.semantic_chunker import chunk_by_concept # noqa: E402
 
 
 
 
12
 
13
 
14
  def build():
15
  """
16
- This script performs the knowledge base build process.
17
- 1. Loads the raw, manually curated knowledge base.
18
- 2. Uses the semantic chunker to group entries by concept.
19
- 3. Saves the final, consolidated chunks to the file that the main
20
- RAG pipeline expects ('knowledge_base_final_chunks.json').
21
  """
22
- print("--- Building Final Knowledge Base ---")
23
 
24
- # Define the path for the output file
25
  final_chunks_path = PROCESSED_DATA_DIR / "knowledge_base_final_chunks.json"
26
-
27
- # 1. Load the raw knowledge base file
28
  print(f"Loading raw knowledge base from: {RAW_KB_PATH}")
29
- try:
30
- with open(RAW_KB_PATH, "r", encoding="utf-8") as f:
31
- raw_kb = json.load(f)
32
- except FileNotFoundError:
33
- print(f"ERROR: Raw knowledge base file not found at {RAW_KB_PATH}. Halting.")
34
- return
35
-
36
- print(f"Loaded {len(raw_kb)} raw entries.")
37
 
38
- # 2. Process and chunk the knowledge base using the existing chunker
39
- print("Applying semantic chunking to consolidate related content...")
40
  final_chunks = chunk_by_concept(raw_kb)
41
- print(f"Created {len(final_chunks)} final semantic chunks.")
42
-
43
- # 3. Save the final chunked file
44
- print(f"Saving final chunked knowledge base to: {final_chunks_path}")
45
-
46
- # Ensure the 'processed' directory exists before trying to write to it
47
  PROCESSED_DATA_DIR.mkdir(parents=True, exist_ok=True)
48
-
49
  with open(final_chunks_path, "w", encoding="utf-8") as f:
50
- # We use indent=4 to make the final JSON file human-readable,
51
- # which is extremely helpful for debugging and verification.
52
  json.dump(final_chunks, f, indent=4)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
 
54
- print("\n Success! The final knowledge base is built and ready.")
55
- print("You can now run the main application.")
56
 
57
 
58
  if __name__ == "__main__":
 
1
  import json
2
  import sys
3
+ import faiss
4
+ import numpy as np
5
  from pathlib import Path
6
 
 
 
7
  project_root = Path(__file__).parent.parent
8
  sys.path.append(str(project_root))
9
 
10
+ from src.fot_recommender.config import PROCESSED_DATA_DIR, RAW_KB_PATH # noqa: E402
11
+ from src.fot_recommender.semantic_chunker import chunk_by_concept # noqa: E402
12
+ from src.fot_recommender.rag_pipeline import ( # noqa: E402
13
+ initialize_embedding_model,
14
+ create_embeddings,
15
+ )
16
 
17
 
18
  def build():
19
  """
20
+ Builds the entire knowledge base artifact set needed by the application:
21
+ 1. The processed, semantically chunked JSON file.
22
+ 2. The Facebook AI Similarity Search (FAISS) vector index file (`faiss_index.bin`).
 
 
23
  """
24
+ print("--- Building Final Knowledge Base and FAISS Index ---")
25
 
26
+ # --- Create Final Chunks ---
27
  final_chunks_path = PROCESSED_DATA_DIR / "knowledge_base_final_chunks.json"
 
 
28
  print(f"Loading raw knowledge base from: {RAW_KB_PATH}")
29
+ with open(RAW_KB_PATH, "r", encoding="utf-8") as f:
30
+ raw_kb = json.load(f)
 
 
 
 
 
 
31
 
 
 
32
  final_chunks = chunk_by_concept(raw_kb)
 
 
 
 
 
 
33
  PROCESSED_DATA_DIR.mkdir(parents=True, exist_ok=True)
 
34
  with open(final_chunks_path, "w", encoding="utf-8") as f:
 
 
35
  json.dump(final_chunks, f, indent=4)
36
+ print(f"✅ Saved {len(final_chunks)} semantic chunks to {final_chunks_path}")
37
+
38
+ # --- Create and Save FAISS Index ---
39
+ faiss_index_path = PROCESSED_DATA_DIR / "faiss_index.bin"
40
+ print("\n--- Creating FAISS Index ---")
41
+
42
+ model = initialize_embedding_model()
43
+ embeddings = create_embeddings(final_chunks, model)
44
+
45
+ # Explicitly set dtype for FAISS
46
+ embeddings = np.asarray(embeddings).astype("float32")
47
+
48
+ dimension = embeddings.shape[1]
49
+ index = faiss.IndexFlatIP(dimension)
50
+ index.add(embeddings) # type: ignore
51
+
52
+ faiss.write_index(index, str(faiss_index_path))
53
+ print(f"✅ Saved FAISS index with {index.ntotal} vectors to {faiss_index_path}")
54
 
55
+ print("\n🎉 Success! All artifacts are built and ready for the application.")
 
56
 
57
 
58
  if __name__ == "__main__":
src/fot_recommender/main.py CHANGED
@@ -1,3 +1,7 @@
 
 
 
 
1
  from fot_recommender.config import PROCESSED_DATA_DIR
2
  from fot_recommender.rag_pipeline import (
3
  load_knowledge_base,
@@ -5,7 +9,7 @@ from fot_recommender.rag_pipeline import (
5
  create_embeddings,
6
  create_vector_db,
7
  search_interventions,
8
- generate_recommendation_summary
9
  )
10
 
11
  # --- Sample Student Profile from Project Description ---
@@ -36,9 +40,9 @@ def main():
36
  4. Sets up a FAISS vector database.
37
  5. Tests the retrieval system with the sample student profile.
38
  """
39
- print("--- FOT Intervention Recommender: Phase 2 ---")
40
 
41
- # --- Load the final knowledge base created in Phase 1 ---
42
  final_chunks_path = PROCESSED_DATA_DIR / "knowledge_base_final_chunks.json"
43
  knowledge_base_chunks = load_knowledge_base(str(final_chunks_path))
44
 
@@ -49,18 +53,18 @@ def main():
49
  print(f"Successfully loaded {len(knowledge_base_chunks)} processed chunks.")
50
  print("-" * 50)
51
 
52
- # --- Phase 2.1: Vector Embedding Setup ---
53
  embedding_model = initialize_embedding_model()
54
 
55
- # --- Phase 2.2: Create Embeddings for Knowledge Base ---
56
  embeddings = create_embeddings(knowledge_base_chunks, embedding_model)
57
 
58
- # --- Phase 2.3: Set up FAISS Vector Database ---
59
  vector_db = create_vector_db(embeddings)
60
 
61
  print("-" * 50)
62
 
63
- # --- Phase 2.4: Test Retrieval with Sample Student Profile ---
64
  student_query = sample_student_profile["narrative_summary_for_embedding"]
65
 
66
  # Find the top 3 most relevant interventions
@@ -78,21 +82,31 @@ def main():
78
  return
79
 
80
  # --- 4. Generate Synthesized Recommendation (for 'teacher' persona) ---
 
 
 
 
 
81
  synthesized_recommendation = generate_recommendation_summary(
82
- top_interventions, student_query, persona="teacher"
 
 
 
83
  )
84
 
85
  # --- 5. Display Final Output ---
86
- print("\n" + "="*50)
87
  print(" FINAL SYNTHESIZED RECOMMENDATION FOR EDUCATOR")
88
- print("="*50 + "\n")
89
  print(synthesized_recommendation)
90
-
91
- print("\n" + "-"*50)
92
  print("Evidence retrieved from the following sources:")
93
  for chunk, score in top_interventions:
94
- print(f"- {chunk['title']} (Source: {chunk['source_document']}, Relevance: {score:.2f})")
95
-
 
 
96
  print("\n\n✅ Full RAG process complete!")
97
 
98
 
 
1
+ import os
2
+
3
+ from dotenv.main import load_dotenv
4
+
5
  from fot_recommender.config import PROCESSED_DATA_DIR
6
  from fot_recommender.rag_pipeline import (
7
  load_knowledge_base,
 
9
  create_embeddings,
10
  create_vector_db,
11
  search_interventions,
12
+ generate_recommendation_summary,
13
  )
14
 
15
  # --- Sample Student Profile from Project Description ---
 
40
  4. Sets up a FAISS vector database.
41
  5. Tests the retrieval system with the sample student profile.
42
  """
43
+ print("--- FOT Intervention Recommender ---")
44
 
45
+ # --- Load the final knowledge base ---
46
  final_chunks_path = PROCESSED_DATA_DIR / "knowledge_base_final_chunks.json"
47
  knowledge_base_chunks = load_knowledge_base(str(final_chunks_path))
48
 
 
53
  print(f"Successfully loaded {len(knowledge_base_chunks)} processed chunks.")
54
  print("-" * 50)
55
 
56
+ # --- Vector Embedding Setup ---
57
  embedding_model = initialize_embedding_model()
58
 
59
+ # --- Create Embeddings for Knowledge Base ---
60
  embeddings = create_embeddings(knowledge_base_chunks, embedding_model)
61
 
62
+ # --- Set up FAISS Vector Database ---
63
  vector_db = create_vector_db(embeddings)
64
 
65
  print("-" * 50)
66
 
67
+ # --- Test Retrieval with Sample Student Profile ---
68
  student_query = sample_student_profile["narrative_summary_for_embedding"]
69
 
70
  # Find the top 3 most relevant interventions
 
82
  return
83
 
84
  # --- 4. Generate Synthesized Recommendation (for 'teacher' persona) ---
85
+ load_dotenv()
86
+ api_key = os.getenv("FOT_GOOGLE_API_KEY")
87
+ if not api_key:
88
+ return "ERROR: FOT_GOOGLE_API_KEY not found. Please create a .env file and add your key."
89
+
90
  synthesized_recommendation = generate_recommendation_summary(
91
+ top_interventions,
92
+ student_query,
93
+ api_key=api_key,
94
+ persona="teacher"
95
  )
96
 
97
  # --- 5. Display Final Output ---
98
+ print("\n" + "=" * 50)
99
  print(" FINAL SYNTHESIZED RECOMMENDATION FOR EDUCATOR")
100
+ print("=" * 50 + "\n")
101
  print(synthesized_recommendation)
102
+
103
+ print("\n" + "-" * 50)
104
  print("Evidence retrieved from the following sources:")
105
  for chunk, score in top_interventions:
106
+ print(
107
+ f"- {chunk['title']} (Source: {chunk['source_document']}, Relevance: {score:.2f})"
108
+ )
109
+
110
  print("\n\n✅ Full RAG process complete!")
111
 
112
 
src/fot_recommender/rag_pipeline.py CHANGED
@@ -2,8 +2,7 @@ import faiss # type: ignore
2
  import json
3
  import numpy as np
4
  import google.generativeai as genai
5
- import os
6
- from dotenv import load_dotenv
7
  from sentence_transformers import SentenceTransformer
8
  from typing import List, Dict, Any, Tuple
9
  from fot_recommender.prompts import PROMPT_TEMPLATES
@@ -108,17 +107,13 @@ def search_interventions(
108
  def generate_recommendation_summary(
109
  retrieved_chunks: List[Tuple[Dict[str, Any], float]],
110
  student_narrative: str,
 
111
  persona: str = "teacher",
112
  ) -> str:
113
  """
114
  Generates a synthesized recommendation using the Google Gemini API,
115
  tailored to a specific persona.
116
  """
117
- load_dotenv()
118
- api_key = os.getenv("GOOGLE_API_KEY")
119
- if not api_key:
120
- return "ERROR: GOOGLE_API_KEY not found. Please create a .env file and add your key."
121
-
122
  genai.configure(api_key=api_key) # type: ignore
123
 
124
  if persona not in PROMPT_TEMPLATES:
 
2
  import json
3
  import numpy as np
4
  import google.generativeai as genai
5
+
 
6
  from sentence_transformers import SentenceTransformer
7
  from typing import List, Dict, Any, Tuple
8
  from fot_recommender.prompts import PROMPT_TEMPLATES
 
107
  def generate_recommendation_summary(
108
  retrieved_chunks: List[Tuple[Dict[str, Any], float]],
109
  student_narrative: str,
110
+ api_key: str,
111
  persona: str = "teacher",
112
  ) -> str:
113
  """
114
  Generates a synthesized recommendation using the Google Gemini API,
115
  tailored to a specific persona.
116
  """
 
 
 
 
 
117
  genai.configure(api_key=api_key) # type: ignore
118
 
119
  if persona not in PROMPT_TEMPLATES:
uv.lock CHANGED
@@ -7,6 +7,15 @@ resolution-markers = [
7
  "python_full_version < '3.13'",
8
  ]
9
 
 
 
 
 
 
 
 
 
 
10
  [[package]]
11
  name = "annotated-types"
12
  version = "0.7.0"
@@ -151,6 +160,62 @@ wheels = [
151
  { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" },
152
  ]
153
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
  [[package]]
155
  name = "babel"
156
  version = "2.17.0"
@@ -214,6 +279,44 @@ css = [
214
  { name = "tinycss2" },
215
  ]
216
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
217
  [[package]]
218
  name = "cachetools"
219
  version = "5.5.2"
@@ -402,6 +505,20 @@ wheels = [
402
  { url = "https://files.pythonhosted.org/packages/18/50/acc117b601da14f1a79f7deda3fad49509265d6b14c2221687cabc378dad/faiss_cpu-1.11.0.post1-cp313-cp313-win_arm64.whl", hash = "sha256:9cebb720cd57afdbe9dd7ed8a689c65dc5cf1bad475c5aa6fa0d0daea890beb6", size = 7852193, upload-time = "2025-07-15T09:14:43.113Z" },
403
  ]
404
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
405
  [[package]]
406
  name = "fastjsonschema"
407
  version = "2.21.1"
@@ -411,6 +528,15 @@ wheels = [
411
  { url = "https://files.pythonhosted.org/packages/90/2b/0817a2b257fe88725c25589d89aec060581aabf668707a8d03b2e9e0cb2a/fastjsonschema-2.21.1-py3-none-any.whl", hash = "sha256:c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667", size = 23924, upload-time = "2024-12-02T10:55:07.599Z" },
412
  ]
413
 
 
 
 
 
 
 
 
 
 
414
  [[package]]
415
  name = "filelock"
416
  version = "3.18.0"
@@ -427,6 +553,8 @@ source = { editable = "." }
427
  dependencies = [
428
  { name = "faiss-cpu" },
429
  { name = "google-generativeai" },
 
 
430
  { name = "langchain" },
431
  { name = "numpy" },
432
  { name = "python-dotenv" },
@@ -451,6 +579,8 @@ requires-dist = [
451
  { name = "black", marker = "extra == 'dev'", specifier = ">=25.1.0" },
452
  { name = "faiss-cpu" },
453
  { name = "google-generativeai" },
 
 
454
  { name = "jupyterlab", marker = "extra == 'dev'", specifier = ">=4.0" },
455
  { name = "langchain" },
456
  { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.16.1" },
@@ -594,6 +724,64 @@ wheels = [
594
  { url = "https://files.pythonhosted.org/packages/86/f1/62a193f0227cf15a920390abe675f386dec35f7ae3ffe6da582d3ade42c7/googleapis_common_protos-1.70.0-py3-none-any.whl", hash = "sha256:b8bfcca8c25a2bb253e0e0b0adaf8c00773e5e6af6fd92397576680b807e0fd8", size = 294530, upload-time = "2025-04-14T10:17:01.271Z" },
595
  ]
596
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
597
  [[package]]
598
  name = "greenlet"
599
  version = "3.2.3"
@@ -627,6 +815,15 @@ wheels = [
627
  { url = "https://files.pythonhosted.org/packages/5c/4f/aab73ecaa6b3086a4c89863d94cf26fa84cbff63f52ce9bc4342b3087a06/greenlet-3.2.3-cp314-cp314-win_amd64.whl", hash = "sha256:8c47aae8fbbfcf82cc13327ae802ba13c9c36753b67e760023fd116bc124a62a", size = 301236, upload-time = "2025-06-05T16:15:20.111Z" },
628
  ]
629
 
 
 
 
 
 
 
 
 
 
630
  [[package]]
631
  name = "grpcio"
632
  version = "1.74.0"
@@ -1172,6 +1369,18 @@ wheels = [
1172
  { url = "https://files.pythonhosted.org/packages/2d/00/d90b10b962b4277f5e64a78b6609968859ff86889f5b898c1a778c06ec00/lark-1.2.2-py3-none-any.whl", hash = "sha256:c2276486b02f0f1b90be155f2c8ba4a8e194d42775786db622faccd652d8e80c", size = 111036, upload-time = "2024-08-13T19:48:58.603Z" },
1173
  ]
1174
 
 
 
 
 
 
 
 
 
 
 
 
 
1175
  [[package]]
1176
  name = "markupsafe"
1177
  version = "3.0.2"
@@ -1222,6 +1431,15 @@ wheels = [
1222
  { url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899, upload-time = "2024-04-15T13:44:43.265Z" },
1223
  ]
1224
 
 
 
 
 
 
 
 
 
 
1225
  [[package]]
1226
  name = "mistune"
1227
  version = "3.1.3"
@@ -1572,6 +1790,40 @@ wheels = [
1572
  { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
1573
  ]
1574
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1575
  [[package]]
1576
  name = "pandocfilters"
1577
  version = "1.5.1"
@@ -1862,6 +2114,15 @@ wheels = [
1862
  { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" },
1863
  ]
1864
 
 
 
 
 
 
 
 
 
 
1865
  [[package]]
1866
  name = "pygments"
1867
  version = "2.19.2"
@@ -1926,6 +2187,24 @@ wheels = [
1926
  { url = "https://files.pythonhosted.org/packages/08/20/0f2523b9e50a8052bc6a8b732dfc8568abbdc42010aef03a2d750bdab3b2/python_json_logger-3.3.0-py3-none-any.whl", hash = "sha256:dd980fae8cffb24c13caf6e158d3d61c0d6d22342f932cb6e9deedab3d35eec7", size = 15163, upload-time = "2025-03-07T07:08:25.627Z" },
1927
  ]
1928
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1929
  [[package]]
1930
  name = "pywin32"
1931
  version = "311"
@@ -2146,6 +2425,19 @@ wheels = [
2146
  { url = "https://files.pythonhosted.org/packages/7e/71/44ce230e1b7fadd372515a97e32a83011f906ddded8d03e3c6aafbdedbb7/rfc3987_syntax-1.1.0-py3-none-any.whl", hash = "sha256:6c3d97604e4c5ce9f714898e05401a0445a641cfa276432b0a648c80856f6a3f", size = 8046, upload-time = "2025-07-18T01:05:03.843Z" },
2147
  ]
2148
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2149
  [[package]]
2150
  name = "rpds-py"
2151
  version = "0.26.0"
@@ -2259,6 +2551,18 @@ wheels = [
2259
  { url = "https://files.pythonhosted.org/packages/4c/9b/0b8aa09817b63e78d94b4977f18b1fcaead3165a5ee49251c5d5c245bb2d/ruff-0.12.7-py3-none-win_arm64.whl", hash = "sha256:dfce05101dbd11833a0776716d5d1578641b7fddb537fe7fa956ab85d1769b69", size = 11982083, upload-time = "2025-07-29T22:32:33.881Z" },
2260
  ]
2261
 
 
 
 
 
 
 
 
 
 
 
 
 
2262
  [[package]]
2263
  name = "safetensors"
2264
  version = "0.5.3"
@@ -2366,6 +2670,15 @@ wheels = [
2366
  { url = "https://files.pythonhosted.org/packages/6e/6c/a76329897a7cae4937d403e623aa6aaea616a0bb5b36588f0b9d1c9a3739/scipy-1.16.1-cp314-cp314t-win_amd64.whl", hash = "sha256:c0c804d60492a0aad7f5b2bb1862f4548b990049e27e828391ff2bf6f7199998", size = 39427705, upload-time = "2025-07-27T16:31:53.96Z" },
2367
  ]
2368
 
 
 
 
 
 
 
 
 
 
2369
  [[package]]
2370
  name = "send2trash"
2371
  version = "1.8.3"
@@ -2403,6 +2716,15 @@ wheels = [
2403
  { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" },
2404
  ]
2405
 
 
 
 
 
 
 
 
 
 
2406
  [[package]]
2407
  name = "six"
2408
  version = "1.17.0"
@@ -2473,6 +2795,19 @@ wheels = [
2473
  { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" },
2474
  ]
2475
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2476
  [[package]]
2477
  name = "sympy"
2478
  version = "1.14.0"
@@ -2554,6 +2889,15 @@ wheels = [
2554
  { url = "https://files.pythonhosted.org/packages/41/f2/fd673d979185f5dcbac4be7d09461cbb99751554ffb6718d0013af8604cb/tokenizers-0.21.4-cp39-abi3-win_amd64.whl", hash = "sha256:475d807a5c3eb72c59ad9b5fcdb254f6e17f53dfcbb9903233b0dfa9c943b597", size = 2507568, upload-time = "2025-07-28T15:48:55.456Z" },
2555
  ]
2556
 
 
 
 
 
 
 
 
 
 
2557
  [[package]]
2558
  name = "torch"
2559
  version = "2.2.2"
@@ -2646,6 +2990,21 @@ wheels = [
2646
  { url = "https://files.pythonhosted.org/packages/cf/18/eb7578f84ef5a080d4e5ca9bc4f7c68e7aa9c1e464f1b3d3001e4c642fce/transformers-4.54.1-py3-none-any.whl", hash = "sha256:c89965a4f62a0d07009d45927a9c6372848a02ab9ead9c318c3d082708bab529", size = 11176397, upload-time = "2025-07-29T15:57:19.692Z" },
2647
  ]
2648
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2649
  [[package]]
2650
  name = "types-python-dateutil"
2651
  version = "2.9.0.20250708"
@@ -2676,6 +3035,15 @@ wheels = [
2676
  { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" },
2677
  ]
2678
 
 
 
 
 
 
 
 
 
 
2679
  [[package]]
2680
  name = "uri-template"
2681
  version = "1.3.0"
@@ -2703,6 +3071,19 @@ wheels = [
2703
  { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" },
2704
  ]
2705
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2706
  [[package]]
2707
  name = "wcwidth"
2708
  version = "0.2.13"
@@ -2739,6 +3120,37 @@ wheels = [
2739
  { url = "https://files.pythonhosted.org/packages/5a/84/44687a29792a70e111c5c477230a72c4b957d88d16141199bf9acb7537a3/websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", size = 58826, upload-time = "2024-04-23T22:16:14.422Z" },
2740
  ]
2741
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2742
  [[package]]
2743
  name = "zstandard"
2744
  version = "0.23.0"
 
7
  "python_full_version < '3.13'",
8
  ]
9
 
10
+ [[package]]
11
+ name = "aiofiles"
12
+ version = "24.1.0"
13
+ source = { registry = "https://pypi.org/simple" }
14
+ sdist = { url = "https://files.pythonhosted.org/packages/0b/03/a88171e277e8caa88a4c77808c20ebb04ba74cc4681bf1e9416c862de237/aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c", size = 30247, upload-time = "2024-06-24T11:02:03.584Z" }
15
+ wheels = [
16
+ { url = "https://files.pythonhosted.org/packages/a5/45/30bb92d442636f570cb5651bc661f52b610e2eec3f891a5dc3a4c3667db0/aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5", size = 15896, upload-time = "2024-06-24T11:02:01.529Z" },
17
+ ]
18
+
19
  [[package]]
20
  name = "annotated-types"
21
  version = "0.7.0"
 
160
  { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" },
161
  ]
162
 
163
+ [[package]]
164
+ name = "audioop-lts"
165
+ version = "0.2.2"
166
+ source = { registry = "https://pypi.org/simple" }
167
+ sdist = { url = "https://files.pythonhosted.org/packages/38/53/946db57842a50b2da2e0c1e34bd37f36f5aadba1a929a3971c5d7841dbca/audioop_lts-0.2.2.tar.gz", hash = "sha256:64d0c62d88e67b98a1a5e71987b7aa7b5bcffc7dcee65b635823dbdd0a8dbbd0", size = 30686, upload-time = "2025-08-05T16:43:17.409Z" }
168
+ wheels = [
169
+ { url = "https://files.pythonhosted.org/packages/de/d4/94d277ca941de5a507b07f0b592f199c22454eeaec8f008a286b3fbbacd6/audioop_lts-0.2.2-cp313-abi3-macosx_10_13_universal2.whl", hash = "sha256:fd3d4602dc64914d462924a08c1a9816435a2155d74f325853c1f1ac3b2d9800", size = 46523, upload-time = "2025-08-05T16:42:20.836Z" },
170
+ { url = "https://files.pythonhosted.org/packages/f8/5a/656d1c2da4b555920ce4177167bfeb8623d98765594af59702c8873f60ec/audioop_lts-0.2.2-cp313-abi3-macosx_10_13_x86_64.whl", hash = "sha256:550c114a8df0aafe9a05442a1162dfc8fec37e9af1d625ae6060fed6e756f303", size = 27455, upload-time = "2025-08-05T16:42:22.283Z" },
171
+ { url = "https://files.pythonhosted.org/packages/1b/83/ea581e364ce7b0d41456fb79d6ee0ad482beda61faf0cab20cbd4c63a541/audioop_lts-0.2.2-cp313-abi3-macosx_11_0_arm64.whl", hash = "sha256:9a13dc409f2564de15dd68be65b462ba0dde01b19663720c68c1140c782d1d75", size = 26997, upload-time = "2025-08-05T16:42:23.849Z" },
172
+ { url = "https://files.pythonhosted.org/packages/b8/3b/e8964210b5e216e5041593b7d33e97ee65967f17c282e8510d19c666dab4/audioop_lts-0.2.2-cp313-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:51c916108c56aa6e426ce611946f901badac950ee2ddaf302b7ed35d9958970d", size = 85844, upload-time = "2025-08-05T16:42:25.208Z" },
173
+ { url = "https://files.pythonhosted.org/packages/c7/2e/0a1c52faf10d51def20531a59ce4c706cb7952323b11709e10de324d6493/audioop_lts-0.2.2-cp313-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:47eba38322370347b1c47024defbd36374a211e8dd5b0dcbce7b34fdb6f8847b", size = 85056, upload-time = "2025-08-05T16:42:26.559Z" },
174
+ { url = "https://files.pythonhosted.org/packages/75/e8/cd95eef479656cb75ab05dfece8c1f8c395d17a7c651d88f8e6e291a63ab/audioop_lts-0.2.2-cp313-abi3-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba7c3a7e5f23e215cb271516197030c32aef2e754252c4c70a50aaff7031a2c8", size = 93892, upload-time = "2025-08-05T16:42:27.902Z" },
175
+ { url = "https://files.pythonhosted.org/packages/5c/1e/a0c42570b74f83efa5cca34905b3eef03f7ab09fe5637015df538a7f3345/audioop_lts-0.2.2-cp313-abi3-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:def246fe9e180626731b26e89816e79aae2276f825420a07b4a647abaa84becc", size = 96660, upload-time = "2025-08-05T16:42:28.9Z" },
176
+ { url = "https://files.pythonhosted.org/packages/50/d5/8a0ae607ca07dbb34027bac8db805498ee7bfecc05fd2c148cc1ed7646e7/audioop_lts-0.2.2-cp313-abi3-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e160bf9df356d841bb6c180eeeea1834085464626dc1b68fa4e1d59070affdc3", size = 79143, upload-time = "2025-08-05T16:42:29.929Z" },
177
+ { url = "https://files.pythonhosted.org/packages/12/17/0d28c46179e7910bfb0bb62760ccb33edb5de973052cb2230b662c14ca2e/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4b4cd51a57b698b2d06cb9993b7ac8dfe89a3b2878e96bc7948e9f19ff51dba6", size = 84313, upload-time = "2025-08-05T16:42:30.949Z" },
178
+ { url = "https://files.pythonhosted.org/packages/84/ba/bd5d3806641564f2024e97ca98ea8f8811d4e01d9b9f9831474bc9e14f9e/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_ppc64le.whl", hash = "sha256:4a53aa7c16a60a6857e6b0b165261436396ef7293f8b5c9c828a3a203147ed4a", size = 93044, upload-time = "2025-08-05T16:42:31.959Z" },
179
+ { url = "https://files.pythonhosted.org/packages/f9/5e/435ce8d5642f1f7679540d1e73c1c42d933331c0976eb397d1717d7f01a3/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_riscv64.whl", hash = "sha256:3fc38008969796f0f689f1453722a0f463da1b8a6fbee11987830bfbb664f623", size = 78766, upload-time = "2025-08-05T16:42:33.302Z" },
180
+ { url = "https://files.pythonhosted.org/packages/ae/3b/b909e76b606cbfd53875693ec8c156e93e15a1366a012f0b7e4fb52d3c34/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_s390x.whl", hash = "sha256:15ab25dd3e620790f40e9ead897f91e79c0d3ce65fe193c8ed6c26cffdd24be7", size = 87640, upload-time = "2025-08-05T16:42:34.854Z" },
181
+ { url = "https://files.pythonhosted.org/packages/30/e7/8f1603b4572d79b775f2140d7952f200f5e6c62904585d08a01f0a70393a/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:03f061a1915538fd96272bac9551841859dbb2e3bf73ebe4a23ef043766f5449", size = 86052, upload-time = "2025-08-05T16:42:35.839Z" },
182
+ { url = "https://files.pythonhosted.org/packages/b5/96/c37846df657ccdda62ba1ae2b6534fa90e2e1b1742ca8dcf8ebd38c53801/audioop_lts-0.2.2-cp313-abi3-win32.whl", hash = "sha256:3bcddaaf6cc5935a300a8387c99f7a7fbbe212a11568ec6cf6e4bc458c048636", size = 26185, upload-time = "2025-08-05T16:42:37.04Z" },
183
+ { url = "https://files.pythonhosted.org/packages/34/a5/9d78fdb5b844a83da8a71226c7bdae7cc638861085fff7a1d707cb4823fa/audioop_lts-0.2.2-cp313-abi3-win_amd64.whl", hash = "sha256:a2c2a947fae7d1062ef08c4e369e0ba2086049a5e598fda41122535557012e9e", size = 30503, upload-time = "2025-08-05T16:42:38.427Z" },
184
+ { url = "https://files.pythonhosted.org/packages/34/25/20d8fde083123e90c61b51afb547bb0ea7e77bab50d98c0ab243d02a0e43/audioop_lts-0.2.2-cp313-abi3-win_arm64.whl", hash = "sha256:5f93a5db13927a37d2d09637ccca4b2b6b48c19cd9eda7b17a2e9f77edee6a6f", size = 24173, upload-time = "2025-08-05T16:42:39.704Z" },
185
+ { url = "https://files.pythonhosted.org/packages/58/a7/0a764f77b5c4ac58dc13c01a580f5d32ae8c74c92020b961556a43e26d02/audioop_lts-0.2.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:73f80bf4cd5d2ca7814da30a120de1f9408ee0619cc75da87d0641273d202a09", size = 47096, upload-time = "2025-08-05T16:42:40.684Z" },
186
+ { url = "https://files.pythonhosted.org/packages/aa/ed/ebebedde1a18848b085ad0fa54b66ceb95f1f94a3fc04f1cd1b5ccb0ed42/audioop_lts-0.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:106753a83a25ee4d6f473f2be6b0966fc1c9af7e0017192f5531a3e7463dce58", size = 27748, upload-time = "2025-08-05T16:42:41.992Z" },
187
+ { url = "https://files.pythonhosted.org/packages/cb/6e/11ca8c21af79f15dbb1c7f8017952ee8c810c438ce4e2b25638dfef2b02c/audioop_lts-0.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fbdd522624141e40948ab3e8cdae6e04c748d78710e9f0f8d4dae2750831de19", size = 27329, upload-time = "2025-08-05T16:42:42.987Z" },
188
+ { url = "https://files.pythonhosted.org/packages/84/52/0022f93d56d85eec5da6b9da6a958a1ef09e80c39f2cc0a590c6af81dcbb/audioop_lts-0.2.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:143fad0311e8209ece30a8dbddab3b65ab419cbe8c0dde6e8828da25999be911", size = 92407, upload-time = "2025-08-05T16:42:44.336Z" },
189
+ { url = "https://files.pythonhosted.org/packages/87/1d/48a889855e67be8718adbc7a01f3c01d5743c325453a5e81cf3717664aad/audioop_lts-0.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dfbbc74ec68a0fd08cfec1f4b5e8cca3d3cd7de5501b01c4b5d209995033cde9", size = 91811, upload-time = "2025-08-05T16:42:45.325Z" },
190
+ { url = "https://files.pythonhosted.org/packages/98/a6/94b7213190e8077547ffae75e13ed05edc488653c85aa5c41472c297d295/audioop_lts-0.2.2-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cfcac6aa6f42397471e4943e0feb2244549db5c5d01efcd02725b96af417f3fe", size = 100470, upload-time = "2025-08-05T16:42:46.468Z" },
191
+ { url = "https://files.pythonhosted.org/packages/e9/e9/78450d7cb921ede0cfc33426d3a8023a3bda755883c95c868ee36db8d48d/audioop_lts-0.2.2-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:752d76472d9804ac60f0078c79cdae8b956f293177acd2316cd1e15149aee132", size = 103878, upload-time = "2025-08-05T16:42:47.576Z" },
192
+ { url = "https://files.pythonhosted.org/packages/4f/e2/cd5439aad4f3e34ae1ee852025dc6aa8f67a82b97641e390bf7bd9891d3e/audioop_lts-0.2.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:83c381767e2cc10e93e40281a04852facc4cd9334550e0f392f72d1c0a9c5753", size = 84867, upload-time = "2025-08-05T16:42:49.003Z" },
193
+ { url = "https://files.pythonhosted.org/packages/68/4b/9d853e9076c43ebba0d411e8d2aa19061083349ac695a7d082540bad64d0/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c0022283e9556e0f3643b7c3c03f05063ca72b3063291834cca43234f20c60bb", size = 90001, upload-time = "2025-08-05T16:42:50.038Z" },
194
+ { url = "https://files.pythonhosted.org/packages/58/26/4bae7f9d2f116ed5593989d0e521d679b0d583973d203384679323d8fa85/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:a2d4f1513d63c795e82948e1305f31a6d530626e5f9f2605408b300ae6095093", size = 99046, upload-time = "2025-08-05T16:42:51.111Z" },
195
+ { url = "https://files.pythonhosted.org/packages/b2/67/a9f4fb3e250dda9e9046f8866e9fa7d52664f8985e445c6b4ad6dfb55641/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:c9c8e68d8b4a56fda8c025e538e639f8c5953f5073886b596c93ec9b620055e7", size = 84788, upload-time = "2025-08-05T16:42:52.198Z" },
196
+ { url = "https://files.pythonhosted.org/packages/70/f7/3de86562db0121956148bcb0fe5b506615e3bcf6e63c4357a612b910765a/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:96f19de485a2925314f5020e85911fb447ff5fbef56e8c7c6927851b95533a1c", size = 94472, upload-time = "2025-08-05T16:42:53.59Z" },
197
+ { url = "https://files.pythonhosted.org/packages/f1/32/fd772bf9078ae1001207d2df1eef3da05bea611a87dd0e8217989b2848fa/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e541c3ef484852ef36545f66209444c48b28661e864ccadb29daddb6a4b8e5f5", size = 92279, upload-time = "2025-08-05T16:42:54.632Z" },
198
+ { url = "https://files.pythonhosted.org/packages/4f/41/affea7181592ab0ab560044632571a38edaf9130b84928177823fbf3176a/audioop_lts-0.2.2-cp313-cp313t-win32.whl", hash = "sha256:d5e73fa573e273e4f2e5ff96f9043858a5e9311e94ffefd88a3186a910c70917", size = 26568, upload-time = "2025-08-05T16:42:55.627Z" },
199
+ { url = "https://files.pythonhosted.org/packages/28/2b/0372842877016641db8fc54d5c88596b542eec2f8f6c20a36fb6612bf9ee/audioop_lts-0.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9191d68659eda01e448188f60364c7763a7ca6653ed3f87ebb165822153a8547", size = 30942, upload-time = "2025-08-05T16:42:56.674Z" },
200
+ { url = "https://files.pythonhosted.org/packages/ee/ca/baf2b9cc7e96c179bb4a54f30fcd83e6ecb340031bde68f486403f943768/audioop_lts-0.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:c174e322bb5783c099aaf87faeb240c8d210686b04bd61dfd05a8e5a83d88969", size = 24603, upload-time = "2025-08-05T16:42:57.571Z" },
201
+ { url = "https://files.pythonhosted.org/packages/5c/73/413b5a2804091e2c7d5def1d618e4837f1cb82464e230f827226278556b7/audioop_lts-0.2.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:f9ee9b52f5f857fbaf9d605a360884f034c92c1c23021fb90b2e39b8e64bede6", size = 47104, upload-time = "2025-08-05T16:42:58.518Z" },
202
+ { url = "https://files.pythonhosted.org/packages/ae/8c/daa3308dc6593944410c2c68306a5e217f5c05b70a12e70228e7dd42dc5c/audioop_lts-0.2.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:49ee1a41738a23e98d98b937a0638357a2477bc99e61b0f768a8f654f45d9b7a", size = 27754, upload-time = "2025-08-05T16:43:00.132Z" },
203
+ { url = "https://files.pythonhosted.org/packages/4e/86/c2e0f627168fcf61781a8f72cab06b228fe1da4b9fa4ab39cfb791b5836b/audioop_lts-0.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5b00be98ccd0fc123dcfad31d50030d25fcf31488cde9e61692029cd7394733b", size = 27332, upload-time = "2025-08-05T16:43:01.666Z" },
204
+ { url = "https://files.pythonhosted.org/packages/c7/bd/35dce665255434f54e5307de39e31912a6f902d4572da7c37582809de14f/audioop_lts-0.2.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a6d2e0f9f7a69403e388894d4ca5ada5c47230716a03f2847cfc7bd1ecb589d6", size = 92396, upload-time = "2025-08-05T16:43:02.991Z" },
205
+ { url = "https://files.pythonhosted.org/packages/2d/d2/deeb9f51def1437b3afa35aeb729d577c04bcd89394cb56f9239a9f50b6f/audioop_lts-0.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f9b0b8a03ef474f56d1a842af1a2e01398b8f7654009823c6d9e0ecff4d5cfbf", size = 91811, upload-time = "2025-08-05T16:43:04.096Z" },
206
+ { url = "https://files.pythonhosted.org/packages/76/3b/09f8b35b227cee28cc8231e296a82759ed80c1a08e349811d69773c48426/audioop_lts-0.2.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2b267b70747d82125f1a021506565bdc5609a2b24bcb4773c16d79d2bb260bbd", size = 100483, upload-time = "2025-08-05T16:43:05.085Z" },
207
+ { url = "https://files.pythonhosted.org/packages/0b/15/05b48a935cf3b130c248bfdbdea71ce6437f5394ee8533e0edd7cfd93d5e/audioop_lts-0.2.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0337d658f9b81f4cd0fdb1f47635070cc084871a3d4646d9de74fdf4e7c3d24a", size = 103885, upload-time = "2025-08-05T16:43:06.197Z" },
208
+ { url = "https://files.pythonhosted.org/packages/83/80/186b7fce6d35b68d3d739f228dc31d60b3412105854edb975aa155a58339/audioop_lts-0.2.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:167d3b62586faef8b6b2275c3218796b12621a60e43f7e9d5845d627b9c9b80e", size = 84899, upload-time = "2025-08-05T16:43:07.291Z" },
209
+ { url = "https://files.pythonhosted.org/packages/49/89/c78cc5ac6cb5828f17514fb12966e299c850bc885e80f8ad94e38d450886/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0d9385e96f9f6da847f4d571ce3cb15b5091140edf3db97276872647ce37efd7", size = 89998, upload-time = "2025-08-05T16:43:08.335Z" },
210
+ { url = "https://files.pythonhosted.org/packages/4c/4b/6401888d0c010e586c2ca50fce4c903d70a6bb55928b16cfbdfd957a13da/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:48159d96962674eccdca9a3df280e864e8ac75e40a577cc97c5c42667ffabfc5", size = 99046, upload-time = "2025-08-05T16:43:09.367Z" },
211
+ { url = "https://files.pythonhosted.org/packages/de/f8/c874ca9bb447dae0e2ef2e231f6c4c2b0c39e31ae684d2420b0f9e97ee68/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8fefe5868cd082db1186f2837d64cfbfa78b548ea0d0543e9b28935ccce81ce9", size = 84843, upload-time = "2025-08-05T16:43:10.749Z" },
212
+ { url = "https://files.pythonhosted.org/packages/3e/c0/0323e66f3daebc13fd46b36b30c3be47e3fc4257eae44f1e77eb828c703f/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:58cf54380c3884fb49fdd37dfb7a772632b6701d28edd3e2904743c5e1773602", size = 94490, upload-time = "2025-08-05T16:43:12.131Z" },
213
+ { url = "https://files.pythonhosted.org/packages/98/6b/acc7734ac02d95ab791c10c3f17ffa3584ccb9ac5c18fd771c638ed6d1f5/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:088327f00488cdeed296edd9215ca159f3a5a5034741465789cad403fcf4bec0", size = 92297, upload-time = "2025-08-05T16:43:13.139Z" },
214
+ { url = "https://files.pythonhosted.org/packages/13/c3/c3dc3f564ce6877ecd2a05f8d751b9b27a8c320c2533a98b0c86349778d0/audioop_lts-0.2.2-cp314-cp314t-win32.whl", hash = "sha256:068aa17a38b4e0e7de771c62c60bbca2455924b67a8814f3b0dee92b5820c0b3", size = 27331, upload-time = "2025-08-05T16:43:14.19Z" },
215
+ { url = "https://files.pythonhosted.org/packages/72/bb/b4608537e9ffcb86449091939d52d24a055216a36a8bf66b936af8c3e7ac/audioop_lts-0.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:a5bf613e96f49712073de86f20dbdd4014ca18efd4d34ed18c75bd808337851b", size = 31697, upload-time = "2025-08-05T16:43:15.193Z" },
216
+ { url = "https://files.pythonhosted.org/packages/f6/22/91616fe707a5c5510de2cac9b046a30defe7007ba8a0c04f9c08f27df312/audioop_lts-0.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:b492c3b040153e68b9fdaff5913305aaaba5bb433d8a7f73d5cf6a64ed3cc1dd", size = 25206, upload-time = "2025-08-05T16:43:16.444Z" },
217
+ ]
218
+
219
  [[package]]
220
  name = "babel"
221
  version = "2.17.0"
 
279
  { name = "tinycss2" },
280
  ]
281
 
282
+ [[package]]
283
+ name = "brotli"
284
+ version = "1.1.0"
285
+ source = { registry = "https://pypi.org/simple" }
286
+ sdist = { url = "https://files.pythonhosted.org/packages/2f/c2/f9e977608bdf958650638c3f1e28f85a1b075f075ebbe77db8555463787b/Brotli-1.1.0.tar.gz", hash = "sha256:81de08ac11bcb85841e440c13611c00b67d3bf82698314928d0b676362546724", size = 7372270, upload-time = "2023-09-07T14:05:41.643Z" }
287
+ wheels = [
288
+ { url = "https://files.pythonhosted.org/packages/5c/d0/5373ae13b93fe00095a58efcbce837fd470ca39f703a235d2a999baadfbc/Brotli-1.1.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:32d95b80260d79926f5fab3c41701dbb818fde1c9da590e77e571eefd14abe28", size = 815693, upload-time = "2024-10-18T12:32:23.824Z" },
289
+ { url = "https://files.pythonhosted.org/packages/8e/48/f6e1cdf86751300c288c1459724bfa6917a80e30dbfc326f92cea5d3683a/Brotli-1.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b760c65308ff1e462f65d69c12e4ae085cff3b332d894637f6273a12a482d09f", size = 422489, upload-time = "2024-10-18T12:32:25.641Z" },
290
+ { url = "https://files.pythonhosted.org/packages/06/88/564958cedce636d0f1bed313381dfc4b4e3d3f6015a63dae6146e1b8c65c/Brotli-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:316cc9b17edf613ac76b1f1f305d2a748f1b976b033b049a6ecdfd5612c70409", size = 873081, upload-time = "2023-09-07T14:03:57.967Z" },
291
+ { url = "https://files.pythonhosted.org/packages/58/79/b7026a8bb65da9a6bb7d14329fd2bd48d2b7f86d7329d5cc8ddc6a90526f/Brotli-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:caf9ee9a5775f3111642d33b86237b05808dafcd6268faa492250e9b78046eb2", size = 446244, upload-time = "2023-09-07T14:03:59.319Z" },
292
+ { url = "https://files.pythonhosted.org/packages/e5/18/c18c32ecea41b6c0004e15606e274006366fe19436b6adccc1ae7b2e50c2/Brotli-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70051525001750221daa10907c77830bc889cb6d865cc0b813d9db7fefc21451", size = 2906505, upload-time = "2023-09-07T14:04:01.327Z" },
293
+ { url = "https://files.pythonhosted.org/packages/08/c8/69ec0496b1ada7569b62d85893d928e865df29b90736558d6c98c2031208/Brotli-1.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7f4bf76817c14aa98cc6697ac02f3972cb8c3da93e9ef16b9c66573a68014f91", size = 2944152, upload-time = "2023-09-07T14:04:03.033Z" },
294
+ { url = "https://files.pythonhosted.org/packages/ab/fb/0517cea182219d6768113a38167ef6d4eb157a033178cc938033a552ed6d/Brotli-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0c5516f0aed654134a2fc936325cc2e642f8a0e096d075209672eb321cff408", size = 2919252, upload-time = "2023-09-07T14:04:04.675Z" },
295
+ { url = "https://files.pythonhosted.org/packages/c7/53/73a3431662e33ae61a5c80b1b9d2d18f58dfa910ae8dd696e57d39f1a2f5/Brotli-1.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c3020404e0b5eefd7c9485ccf8393cfb75ec38ce75586e046573c9dc29967a0", size = 2845955, upload-time = "2023-09-07T14:04:06.585Z" },
296
+ { url = "https://files.pythonhosted.org/packages/55/ac/bd280708d9c5ebdbf9de01459e625a3e3803cce0784f47d633562cf40e83/Brotli-1.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:4ed11165dd45ce798d99a136808a794a748d5dc38511303239d4e2363c0695dc", size = 2914304, upload-time = "2023-09-07T14:04:08.668Z" },
297
+ { url = "https://files.pythonhosted.org/packages/76/58/5c391b41ecfc4527d2cc3350719b02e87cb424ef8ba2023fb662f9bf743c/Brotli-1.1.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:4093c631e96fdd49e0377a9c167bfd75b6d0bad2ace734c6eb20b348bc3ea180", size = 2814452, upload-time = "2023-09-07T14:04:10.736Z" },
298
+ { url = "https://files.pythonhosted.org/packages/c7/4e/91b8256dfe99c407f174924b65a01f5305e303f486cc7a2e8a5d43c8bec3/Brotli-1.1.0-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e4c4629ddad63006efa0ef968c8e4751c5868ff0b1c5c40f76524e894c50248", size = 2938751, upload-time = "2023-09-07T14:04:12.875Z" },
299
+ { url = "https://files.pythonhosted.org/packages/5a/a6/e2a39a5d3b412938362bbbeba5af904092bf3f95b867b4a3eb856104074e/Brotli-1.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:861bf317735688269936f755fa136a99d1ed526883859f86e41a5d43c61d8966", size = 2933757, upload-time = "2023-09-07T14:04:14.551Z" },
300
+ { url = "https://files.pythonhosted.org/packages/13/f0/358354786280a509482e0e77c1a5459e439766597d280f28cb097642fc26/Brotli-1.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:87a3044c3a35055527ac75e419dfa9f4f3667a1e887ee80360589eb8c90aabb9", size = 2936146, upload-time = "2024-10-18T12:32:27.257Z" },
301
+ { url = "https://files.pythonhosted.org/packages/80/f7/daf538c1060d3a88266b80ecc1d1c98b79553b3f117a485653f17070ea2a/Brotli-1.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c5529b34c1c9d937168297f2c1fde7ebe9ebdd5e121297ff9c043bdb2ae3d6fb", size = 2848055, upload-time = "2024-10-18T12:32:29.376Z" },
302
+ { url = "https://files.pythonhosted.org/packages/ad/cf/0eaa0585c4077d3c2d1edf322d8e97aabf317941d3a72d7b3ad8bce004b0/Brotli-1.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ca63e1890ede90b2e4454f9a65135a4d387a4585ff8282bb72964fab893f2111", size = 3035102, upload-time = "2024-10-18T12:32:31.371Z" },
303
+ { url = "https://files.pythonhosted.org/packages/d8/63/1c1585b2aa554fe6dbce30f0c18bdbc877fa9a1bf5ff17677d9cca0ac122/Brotli-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e79e6520141d792237c70bcd7a3b122d00f2613769ae0cb61c52e89fd3443839", size = 2930029, upload-time = "2024-10-18T12:32:33.293Z" },
304
+ { url = "https://files.pythonhosted.org/packages/5f/3b/4e3fd1893eb3bbfef8e5a80d4508bec17a57bb92d586c85c12d28666bb13/Brotli-1.1.0-cp312-cp312-win32.whl", hash = "sha256:5f4d5ea15c9382135076d2fb28dde923352fe02951e66935a9efaac8f10e81b0", size = 333276, upload-time = "2023-09-07T14:04:16.49Z" },
305
+ { url = "https://files.pythonhosted.org/packages/3d/d5/942051b45a9e883b5b6e98c041698b1eb2012d25e5948c58d6bf85b1bb43/Brotli-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:906bc3a79de8c4ae5b86d3d75a8b77e44404b0f4261714306e3ad248d8ab0951", size = 357255, upload-time = "2023-09-07T14:04:17.83Z" },
306
+ { url = "https://files.pythonhosted.org/packages/0a/9f/fb37bb8ffc52a8da37b1c03c459a8cd55df7a57bdccd8831d500e994a0ca/Brotli-1.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8bf32b98b75c13ec7cf774164172683d6e7891088f6316e54425fde1efc276d5", size = 815681, upload-time = "2024-10-18T12:32:34.942Z" },
307
+ { url = "https://files.pythonhosted.org/packages/06/b3/dbd332a988586fefb0aa49c779f59f47cae76855c2d00f450364bb574cac/Brotli-1.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7bc37c4d6b87fb1017ea28c9508b36bbcb0c3d18b4260fcdf08b200c74a6aee8", size = 422475, upload-time = "2024-10-18T12:32:36.485Z" },
308
+ { url = "https://files.pythonhosted.org/packages/bb/80/6aaddc2f63dbcf2d93c2d204e49c11a9ec93a8c7c63261e2b4bd35198283/Brotli-1.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c0ef38c7a7014ffac184db9e04debe495d317cc9c6fb10071f7fefd93100a4f", size = 2906173, upload-time = "2024-10-18T12:32:37.978Z" },
309
+ { url = "https://files.pythonhosted.org/packages/ea/1d/e6ca79c96ff5b641df6097d299347507d39a9604bde8915e76bf026d6c77/Brotli-1.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91d7cc2a76b5567591d12c01f019dd7afce6ba8cba6571187e21e2fc418ae648", size = 2943803, upload-time = "2024-10-18T12:32:39.606Z" },
310
+ { url = "https://files.pythonhosted.org/packages/ac/a3/d98d2472e0130b7dd3acdbb7f390d478123dbf62b7d32bda5c830a96116d/Brotli-1.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a93dde851926f4f2678e704fadeb39e16c35d8baebd5252c9fd94ce8ce68c4a0", size = 2918946, upload-time = "2024-10-18T12:32:41.679Z" },
311
+ { url = "https://files.pythonhosted.org/packages/c4/a5/c69e6d272aee3e1423ed005d8915a7eaa0384c7de503da987f2d224d0721/Brotli-1.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f0db75f47be8b8abc8d9e31bc7aad0547ca26f24a54e6fd10231d623f183d089", size = 2845707, upload-time = "2024-10-18T12:32:43.478Z" },
312
+ { url = "https://files.pythonhosted.org/packages/58/9f/4149d38b52725afa39067350696c09526de0125ebfbaab5acc5af28b42ea/Brotli-1.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6967ced6730aed543b8673008b5a391c3b1076d834ca438bbd70635c73775368", size = 2936231, upload-time = "2024-10-18T12:32:45.224Z" },
313
+ { url = "https://files.pythonhosted.org/packages/5a/5a/145de884285611838a16bebfdb060c231c52b8f84dfbe52b852a15780386/Brotli-1.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7eedaa5d036d9336c95915035fb57422054014ebdeb6f3b42eac809928e40d0c", size = 2848157, upload-time = "2024-10-18T12:32:46.894Z" },
314
+ { url = "https://files.pythonhosted.org/packages/50/ae/408b6bfb8525dadebd3b3dd5b19d631da4f7d46420321db44cd99dcf2f2c/Brotli-1.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d487f5432bf35b60ed625d7e1b448e2dc855422e87469e3f450aa5552b0eb284", size = 3035122, upload-time = "2024-10-18T12:32:48.844Z" },
315
+ { url = "https://files.pythonhosted.org/packages/af/85/a94e5cfaa0ca449d8f91c3d6f78313ebf919a0dbd55a100c711c6e9655bc/Brotli-1.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:832436e59afb93e1836081a20f324cb185836c617659b07b129141a8426973c7", size = 2930206, upload-time = "2024-10-18T12:32:51.198Z" },
316
+ { url = "https://files.pythonhosted.org/packages/c2/f0/a61d9262cd01351df22e57ad7c34f66794709acab13f34be2675f45bf89d/Brotli-1.1.0-cp313-cp313-win32.whl", hash = "sha256:43395e90523f9c23a3d5bdf004733246fba087f2948f87ab28015f12359ca6a0", size = 333804, upload-time = "2024-10-18T12:32:52.661Z" },
317
+ { url = "https://files.pythonhosted.org/packages/7e/c1/ec214e9c94000d1c1974ec67ced1c970c148aa6b8d8373066123fc3dbf06/Brotli-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:9011560a466d2eb3f5a6e4929cf4a09be405c64154e12df0dd72713f6500e32b", size = 358517, upload-time = "2024-10-18T12:32:54.066Z" },
318
+ ]
319
+
320
  [[package]]
321
  name = "cachetools"
322
  version = "5.5.2"
 
505
  { url = "https://files.pythonhosted.org/packages/18/50/acc117b601da14f1a79f7deda3fad49509265d6b14c2221687cabc378dad/faiss_cpu-1.11.0.post1-cp313-cp313-win_arm64.whl", hash = "sha256:9cebb720cd57afdbe9dd7ed8a689c65dc5cf1bad475c5aa6fa0d0daea890beb6", size = 7852193, upload-time = "2025-07-15T09:14:43.113Z" },
506
  ]
507
 
508
+ [[package]]
509
+ name = "fastapi"
510
+ version = "0.116.1"
511
+ source = { registry = "https://pypi.org/simple" }
512
+ dependencies = [
513
+ { name = "pydantic" },
514
+ { name = "starlette" },
515
+ { name = "typing-extensions" },
516
+ ]
517
+ sdist = { url = "https://files.pythonhosted.org/packages/78/d7/6c8b3bfe33eeffa208183ec037fee0cce9f7f024089ab1c5d12ef04bd27c/fastapi-0.116.1.tar.gz", hash = "sha256:ed52cbf946abfd70c5a0dccb24673f0670deeb517a88b3544d03c2a6bf283143", size = 296485, upload-time = "2025-07-11T16:22:32.057Z" }
518
+ wheels = [
519
+ { url = "https://files.pythonhosted.org/packages/e5/47/d63c60f59a59467fda0f93f46335c9d18526d7071f025cb5b89d5353ea42/fastapi-0.116.1-py3-none-any.whl", hash = "sha256:c46ac7c312df840f0c9e220f7964bada936781bc4e2e6eb71f1c4d7553786565", size = 95631, upload-time = "2025-07-11T16:22:30.485Z" },
520
+ ]
521
+
522
  [[package]]
523
  name = "fastjsonschema"
524
  version = "2.21.1"
 
528
  { url = "https://files.pythonhosted.org/packages/90/2b/0817a2b257fe88725c25589d89aec060581aabf668707a8d03b2e9e0cb2a/fastjsonschema-2.21.1-py3-none-any.whl", hash = "sha256:c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667", size = 23924, upload-time = "2024-12-02T10:55:07.599Z" },
529
  ]
530
 
531
+ [[package]]
532
+ name = "ffmpy"
533
+ version = "0.6.1"
534
+ source = { registry = "https://pypi.org/simple" }
535
+ sdist = { url = "https://files.pythonhosted.org/packages/0b/f6/67cadf1686030be511004e75fa1c1397f8f193cd4d15d4788edef7c28621/ffmpy-0.6.1.tar.gz", hash = "sha256:b5830fd05f72bace05b8fb28724d54a7a63c5119d7f74ca36a75df33f749142d", size = 4958, upload-time = "2025-07-22T12:08:22.276Z" }
536
+ wheels = [
537
+ { url = "https://files.pythonhosted.org/packages/74/d4/1806897b31c480efc4e97c22506ac46c716084f573aef780bb7fb7a16e8a/ffmpy-0.6.1-py3-none-any.whl", hash = "sha256:69a37e2d7d6feb840e233d5640f3499a8b0a8657336774c86e4c52a3219222d4", size = 5512, upload-time = "2025-07-22T12:08:21.176Z" },
538
+ ]
539
+
540
  [[package]]
541
  name = "filelock"
542
  version = "3.18.0"
 
553
  dependencies = [
554
  { name = "faiss-cpu" },
555
  { name = "google-generativeai" },
556
+ { name = "gradio" },
557
+ { name = "gradio-client" },
558
  { name = "langchain" },
559
  { name = "numpy" },
560
  { name = "python-dotenv" },
 
579
  { name = "black", marker = "extra == 'dev'", specifier = ">=25.1.0" },
580
  { name = "faiss-cpu" },
581
  { name = "google-generativeai" },
582
+ { name = "gradio" },
583
+ { name = "gradio-client" },
584
  { name = "jupyterlab", marker = "extra == 'dev'", specifier = ">=4.0" },
585
  { name = "langchain" },
586
  { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.16.1" },
 
724
  { url = "https://files.pythonhosted.org/packages/86/f1/62a193f0227cf15a920390abe675f386dec35f7ae3ffe6da582d3ade42c7/googleapis_common_protos-1.70.0-py3-none-any.whl", hash = "sha256:b8bfcca8c25a2bb253e0e0b0adaf8c00773e5e6af6fd92397576680b807e0fd8", size = 294530, upload-time = "2025-04-14T10:17:01.271Z" },
725
  ]
726
 
727
+ [[package]]
728
+ name = "gradio"
729
+ version = "5.41.1"
730
+ source = { registry = "https://pypi.org/simple" }
731
+ dependencies = [
732
+ { name = "aiofiles" },
733
+ { name = "anyio" },
734
+ { name = "audioop-lts", marker = "python_full_version >= '3.13'" },
735
+ { name = "brotli" },
736
+ { name = "fastapi" },
737
+ { name = "ffmpy" },
738
+ { name = "gradio-client" },
739
+ { name = "groovy" },
740
+ { name = "httpx" },
741
+ { name = "huggingface-hub" },
742
+ { name = "jinja2" },
743
+ { name = "markupsafe" },
744
+ { name = "numpy" },
745
+ { name = "orjson" },
746
+ { name = "packaging" },
747
+ { name = "pandas" },
748
+ { name = "pillow" },
749
+ { name = "pydantic" },
750
+ { name = "pydub" },
751
+ { name = "python-multipart" },
752
+ { name = "pyyaml" },
753
+ { name = "ruff", marker = "sys_platform != 'emscripten'" },
754
+ { name = "safehttpx" },
755
+ { name = "semantic-version" },
756
+ { name = "starlette", marker = "sys_platform != 'emscripten'" },
757
+ { name = "tomlkit" },
758
+ { name = "typer", marker = "sys_platform != 'emscripten'" },
759
+ { name = "typing-extensions" },
760
+ { name = "urllib3", marker = "sys_platform == 'emscripten'" },
761
+ { name = "uvicorn", marker = "sys_platform != 'emscripten'" },
762
+ ]
763
+ sdist = { url = "https://files.pythonhosted.org/packages/50/42/dbfff7c0ff7d28c1b2fb1f48a6c79af386dc8cd2c81a5f2c8d6f84aaf082/gradio-5.41.1.tar.gz", hash = "sha256:c7b9ba816d7b720ed9ee44170c9df0039c7015e85ea4adb1644568ada4a8fa92", size = 71656024, upload-time = "2025-08-06T21:04:30.485Z" }
764
+ wheels = [
765
+ { url = "https://files.pythonhosted.org/packages/64/91/fa9a873b88254ef287d87c781f30eaa9439b864a32f0dda67452fd13857d/gradio-5.41.1-py3-none-any.whl", hash = "sha256:4e1cfef903cbe642587ebe3183daea42c39cba4f622888fc09353a6d9a04ebfa", size = 59678266, upload-time = "2025-08-06T21:04:23.501Z" },
766
+ ]
767
+
768
+ [[package]]
769
+ name = "gradio-client"
770
+ version = "1.11.0"
771
+ source = { registry = "https://pypi.org/simple" }
772
+ dependencies = [
773
+ { name = "fsspec" },
774
+ { name = "httpx" },
775
+ { name = "huggingface-hub" },
776
+ { name = "packaging" },
777
+ { name = "typing-extensions" },
778
+ { name = "websockets" },
779
+ ]
780
+ sdist = { url = "https://files.pythonhosted.org/packages/6b/98/60c699708bad11b5f28bfb1deaf979c4a8fcc31ec292c6a71dfd1eb14cdb/gradio_client-1.11.0.tar.gz", hash = "sha256:377c31d8082173663b230dad341614b127b2460fe24d5fd72ed456fb3f0b3a9e", size = 322444, upload-time = "2025-07-17T02:02:45.968Z" }
781
+ wheels = [
782
+ { url = "https://files.pythonhosted.org/packages/e0/38/7f50ae95de8fa419276742230f57a34e8c0f47231da0ad54479dd0088972/gradio_client-1.11.0-py3-none-any.whl", hash = "sha256:afb714aea50224f6f04679fe2ce79c1be75011012d0dc3b3ee575610a0dc8eb2", size = 324452, upload-time = "2025-07-17T02:02:44.542Z" },
783
+ ]
784
+
785
  [[package]]
786
  name = "greenlet"
787
  version = "3.2.3"
 
815
  { url = "https://files.pythonhosted.org/packages/5c/4f/aab73ecaa6b3086a4c89863d94cf26fa84cbff63f52ce9bc4342b3087a06/greenlet-3.2.3-cp314-cp314-win_amd64.whl", hash = "sha256:8c47aae8fbbfcf82cc13327ae802ba13c9c36753b67e760023fd116bc124a62a", size = 301236, upload-time = "2025-06-05T16:15:20.111Z" },
816
  ]
817
 
818
+ [[package]]
819
+ name = "groovy"
820
+ version = "0.1.2"
821
+ source = { registry = "https://pypi.org/simple" }
822
+ sdist = { url = "https://files.pythonhosted.org/packages/52/36/bbdede67400277bef33d3ec0e6a31750da972c469f75966b4930c753218f/groovy-0.1.2.tar.gz", hash = "sha256:25c1dc09b3f9d7e292458aa762c6beb96ea037071bf5e917fc81fb78d2231083", size = 17325, upload-time = "2025-02-28T20:24:56.068Z" }
823
+ wheels = [
824
+ { url = "https://files.pythonhosted.org/packages/28/27/3d6dcadc8a3214d8522c1e7f6a19554e33659be44546d44a2f7572ac7d2a/groovy-0.1.2-py3-none-any.whl", hash = "sha256:7f7975bab18c729a257a8b1ae9dcd70b7cafb1720481beae47719af57c35fa64", size = 14090, upload-time = "2025-02-28T20:24:55.152Z" },
825
+ ]
826
+
827
  [[package]]
828
  name = "grpcio"
829
  version = "1.74.0"
 
1369
  { url = "https://files.pythonhosted.org/packages/2d/00/d90b10b962b4277f5e64a78b6609968859ff86889f5b898c1a778c06ec00/lark-1.2.2-py3-none-any.whl", hash = "sha256:c2276486b02f0f1b90be155f2c8ba4a8e194d42775786db622faccd652d8e80c", size = 111036, upload-time = "2024-08-13T19:48:58.603Z" },
1370
  ]
1371
 
1372
+ [[package]]
1373
+ name = "markdown-it-py"
1374
+ version = "3.0.0"
1375
+ source = { registry = "https://pypi.org/simple" }
1376
+ dependencies = [
1377
+ { name = "mdurl" },
1378
+ ]
1379
+ sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" }
1380
+ wheels = [
1381
+ { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" },
1382
+ ]
1383
+
1384
  [[package]]
1385
  name = "markupsafe"
1386
  version = "3.0.2"
 
1431
  { url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899, upload-time = "2024-04-15T13:44:43.265Z" },
1432
  ]
1433
 
1434
+ [[package]]
1435
+ name = "mdurl"
1436
+ version = "0.1.2"
1437
+ source = { registry = "https://pypi.org/simple" }
1438
+ sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
1439
+ wheels = [
1440
+ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
1441
+ ]
1442
+
1443
  [[package]]
1444
  name = "mistune"
1445
  version = "3.1.3"
 
1790
  { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
1791
  ]
1792
 
1793
+ [[package]]
1794
+ name = "pandas"
1795
+ version = "2.3.1"
1796
+ source = { registry = "https://pypi.org/simple" }
1797
+ dependencies = [
1798
+ { name = "numpy" },
1799
+ { name = "python-dateutil" },
1800
+ { name = "pytz" },
1801
+ { name = "tzdata" },
1802
+ ]
1803
+ sdist = { url = "https://files.pythonhosted.org/packages/d1/6f/75aa71f8a14267117adeeed5d21b204770189c0a0025acbdc03c337b28fc/pandas-2.3.1.tar.gz", hash = "sha256:0a95b9ac964fe83ce317827f80304d37388ea77616b1425f0ae41c9d2d0d7bb2", size = 4487493, upload-time = "2025-07-07T19:20:04.079Z" }
1804
+ wheels = [
1805
+ { url = "https://files.pythonhosted.org/packages/46/de/b8445e0f5d217a99fe0eeb2f4988070908979bec3587c0633e5428ab596c/pandas-2.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:689968e841136f9e542020698ee1c4fbe9caa2ed2213ae2388dc7b81721510d3", size = 11588172, upload-time = "2025-07-07T19:18:52.054Z" },
1806
+ { url = "https://files.pythonhosted.org/packages/1e/e0/801cdb3564e65a5ac041ab99ea6f1d802a6c325bb6e58c79c06a3f1cd010/pandas-2.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:025e92411c16cbe5bb2a4abc99732a6b132f439b8aab23a59fa593eb00704232", size = 10717365, upload-time = "2025-07-07T19:18:54.785Z" },
1807
+ { url = "https://files.pythonhosted.org/packages/51/a5/c76a8311833c24ae61a376dbf360eb1b1c9247a5d9c1e8b356563b31b80c/pandas-2.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b7ff55f31c4fcb3e316e8f7fa194566b286d6ac430afec0d461163312c5841e", size = 11280411, upload-time = "2025-07-07T19:18:57.045Z" },
1808
+ { url = "https://files.pythonhosted.org/packages/da/01/e383018feba0a1ead6cf5fe8728e5d767fee02f06a3d800e82c489e5daaf/pandas-2.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7dcb79bf373a47d2a40cf7232928eb7540155abbc460925c2c96d2d30b006eb4", size = 11988013, upload-time = "2025-07-07T19:18:59.771Z" },
1809
+ { url = "https://files.pythonhosted.org/packages/5b/14/cec7760d7c9507f11c97d64f29022e12a6cc4fc03ac694535e89f88ad2ec/pandas-2.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:56a342b231e8862c96bdb6ab97170e203ce511f4d0429589c8ede1ee8ece48b8", size = 12767210, upload-time = "2025-07-07T19:19:02.944Z" },
1810
+ { url = "https://files.pythonhosted.org/packages/50/b9/6e2d2c6728ed29fb3d4d4d302504fb66f1a543e37eb2e43f352a86365cdf/pandas-2.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ca7ed14832bce68baef331f4d7f294411bed8efd032f8109d690df45e00c4679", size = 13440571, upload-time = "2025-07-07T19:19:06.82Z" },
1811
+ { url = "https://files.pythonhosted.org/packages/80/a5/3a92893e7399a691bad7664d977cb5e7c81cf666c81f89ea76ba2bff483d/pandas-2.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:ac942bfd0aca577bef61f2bc8da8147c4ef6879965ef883d8e8d5d2dc3e744b8", size = 10987601, upload-time = "2025-07-07T19:19:09.589Z" },
1812
+ { url = "https://files.pythonhosted.org/packages/32/ed/ff0a67a2c5505e1854e6715586ac6693dd860fbf52ef9f81edee200266e7/pandas-2.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9026bd4a80108fac2239294a15ef9003c4ee191a0f64b90f170b40cfb7cf2d22", size = 11531393, upload-time = "2025-07-07T19:19:12.245Z" },
1813
+ { url = "https://files.pythonhosted.org/packages/c7/db/d8f24a7cc9fb0972adab0cc80b6817e8bef888cfd0024eeb5a21c0bb5c4a/pandas-2.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6de8547d4fdb12421e2d047a2c446c623ff4c11f47fddb6b9169eb98ffba485a", size = 10668750, upload-time = "2025-07-07T19:19:14.612Z" },
1814
+ { url = "https://files.pythonhosted.org/packages/0f/b0/80f6ec783313f1e2356b28b4fd8d2148c378370045da918c73145e6aab50/pandas-2.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:782647ddc63c83133b2506912cc6b108140a38a37292102aaa19c81c83db2928", size = 11342004, upload-time = "2025-07-07T19:19:16.857Z" },
1815
+ { url = "https://files.pythonhosted.org/packages/e9/e2/20a317688435470872885e7fc8f95109ae9683dec7c50be29b56911515a5/pandas-2.3.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ba6aff74075311fc88504b1db890187a3cd0f887a5b10f5525f8e2ef55bfdb9", size = 12050869, upload-time = "2025-07-07T19:19:19.265Z" },
1816
+ { url = "https://files.pythonhosted.org/packages/55/79/20d746b0a96c67203a5bee5fb4e00ac49c3e8009a39e1f78de264ecc5729/pandas-2.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e5635178b387bd2ba4ac040f82bc2ef6e6b500483975c4ebacd34bec945fda12", size = 12750218, upload-time = "2025-07-07T19:19:21.547Z" },
1817
+ { url = "https://files.pythonhosted.org/packages/7c/0f/145c8b41e48dbf03dd18fdd7f24f8ba95b8254a97a3379048378f33e7838/pandas-2.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6f3bf5ec947526106399a9e1d26d40ee2b259c66422efdf4de63c848492d91bb", size = 13416763, upload-time = "2025-07-07T19:19:23.939Z" },
1818
+ { url = "https://files.pythonhosted.org/packages/b2/c0/54415af59db5cdd86a3d3bf79863e8cc3fa9ed265f0745254061ac09d5f2/pandas-2.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:1c78cf43c8fde236342a1cb2c34bcff89564a7bfed7e474ed2fffa6aed03a956", size = 10987482, upload-time = "2025-07-07T19:19:42.699Z" },
1819
+ { url = "https://files.pythonhosted.org/packages/48/64/2fd2e400073a1230e13b8cd604c9bc95d9e3b962e5d44088ead2e8f0cfec/pandas-2.3.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8dfc17328e8da77be3cf9f47509e5637ba8f137148ed0e9b5241e1baf526e20a", size = 12029159, upload-time = "2025-07-07T19:19:26.362Z" },
1820
+ { url = "https://files.pythonhosted.org/packages/d8/0a/d84fd79b0293b7ef88c760d7dca69828d867c89b6d9bc52d6a27e4d87316/pandas-2.3.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:ec6c851509364c59a5344458ab935e6451b31b818be467eb24b0fe89bd05b6b9", size = 11393287, upload-time = "2025-07-07T19:19:29.157Z" },
1821
+ { url = "https://files.pythonhosted.org/packages/50/ae/ff885d2b6e88f3c7520bb74ba319268b42f05d7e583b5dded9837da2723f/pandas-2.3.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:911580460fc4884d9b05254b38a6bfadddfcc6aaef856fb5859e7ca202e45275", size = 11309381, upload-time = "2025-07-07T19:19:31.436Z" },
1822
+ { url = "https://files.pythonhosted.org/packages/85/86/1fa345fc17caf5d7780d2699985c03dbe186c68fee00b526813939062bb0/pandas-2.3.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f4d6feeba91744872a600e6edbbd5b033005b431d5ae8379abee5bcfa479fab", size = 11883998, upload-time = "2025-07-07T19:19:34.267Z" },
1823
+ { url = "https://files.pythonhosted.org/packages/81/aa/e58541a49b5e6310d89474333e994ee57fea97c8aaa8fc7f00b873059bbf/pandas-2.3.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:fe37e757f462d31a9cd7580236a82f353f5713a80e059a29753cf938c6775d96", size = 12704705, upload-time = "2025-07-07T19:19:36.856Z" },
1824
+ { url = "https://files.pythonhosted.org/packages/d5/f9/07086f5b0f2a19872554abeea7658200824f5835c58a106fa8f2ae96a46c/pandas-2.3.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5db9637dbc24b631ff3707269ae4559bce4b7fd75c1c4d7e13f40edc42df4444", size = 13189044, upload-time = "2025-07-07T19:19:39.999Z" },
1825
+ ]
1826
+
1827
  [[package]]
1828
  name = "pandocfilters"
1829
  version = "1.5.1"
 
2114
  { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" },
2115
  ]
2116
 
2117
+ [[package]]
2118
+ name = "pydub"
2119
+ version = "0.25.1"
2120
+ source = { registry = "https://pypi.org/simple" }
2121
+ sdist = { url = "https://files.pythonhosted.org/packages/fe/9a/e6bca0eed82db26562c73b5076539a4a08d3cffd19c3cc5913a3e61145fd/pydub-0.25.1.tar.gz", hash = "sha256:980a33ce9949cab2a569606b65674d748ecbca4f0796887fd6f46173a7b0d30f", size = 38326, upload-time = "2021-03-10T02:09:54.659Z" }
2122
+ wheels = [
2123
+ { url = "https://files.pythonhosted.org/packages/a6/53/d78dc063216e62fc55f6b2eebb447f6a4b0a59f55c8406376f76bf959b08/pydub-0.25.1-py2.py3-none-any.whl", hash = "sha256:65617e33033874b59d87db603aa1ed450633288aefead953b30bded59cb599a6", size = 32327, upload-time = "2021-03-10T02:09:53.503Z" },
2124
+ ]
2125
+
2126
  [[package]]
2127
  name = "pygments"
2128
  version = "2.19.2"
 
2187
  { url = "https://files.pythonhosted.org/packages/08/20/0f2523b9e50a8052bc6a8b732dfc8568abbdc42010aef03a2d750bdab3b2/python_json_logger-3.3.0-py3-none-any.whl", hash = "sha256:dd980fae8cffb24c13caf6e158d3d61c0d6d22342f932cb6e9deedab3d35eec7", size = 15163, upload-time = "2025-03-07T07:08:25.627Z" },
2188
  ]
2189
 
2190
+ [[package]]
2191
+ name = "python-multipart"
2192
+ version = "0.0.20"
2193
+ source = { registry = "https://pypi.org/simple" }
2194
+ sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158, upload-time = "2024-12-16T19:45:46.972Z" }
2195
+ wheels = [
2196
+ { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" },
2197
+ ]
2198
+
2199
+ [[package]]
2200
+ name = "pytz"
2201
+ version = "2025.2"
2202
+ source = { registry = "https://pypi.org/simple" }
2203
+ sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" }
2204
+ wheels = [
2205
+ { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" },
2206
+ ]
2207
+
2208
  [[package]]
2209
  name = "pywin32"
2210
  version = "311"
 
2425
  { url = "https://files.pythonhosted.org/packages/7e/71/44ce230e1b7fadd372515a97e32a83011f906ddded8d03e3c6aafbdedbb7/rfc3987_syntax-1.1.0-py3-none-any.whl", hash = "sha256:6c3d97604e4c5ce9f714898e05401a0445a641cfa276432b0a648c80856f6a3f", size = 8046, upload-time = "2025-07-18T01:05:03.843Z" },
2426
  ]
2427
 
2428
+ [[package]]
2429
+ name = "rich"
2430
+ version = "14.1.0"
2431
+ source = { registry = "https://pypi.org/simple" }
2432
+ dependencies = [
2433
+ { name = "markdown-it-py" },
2434
+ { name = "pygments" },
2435
+ ]
2436
+ sdist = { url = "https://files.pythonhosted.org/packages/fe/75/af448d8e52bf1d8fa6a9d089ca6c07ff4453d86c65c145d0a300bb073b9b/rich-14.1.0.tar.gz", hash = "sha256:e497a48b844b0320d45007cdebfeaeed8db2a4f4bcf49f15e455cfc4af11eaa8", size = 224441, upload-time = "2025-07-25T07:32:58.125Z" }
2437
+ wheels = [
2438
+ { url = "https://files.pythonhosted.org/packages/e3/30/3c4d035596d3cf444529e0b2953ad0466f6049528a879d27534700580395/rich-14.1.0-py3-none-any.whl", hash = "sha256:536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f", size = 243368, upload-time = "2025-07-25T07:32:56.73Z" },
2439
+ ]
2440
+
2441
  [[package]]
2442
  name = "rpds-py"
2443
  version = "0.26.0"
 
2551
  { url = "https://files.pythonhosted.org/packages/4c/9b/0b8aa09817b63e78d94b4977f18b1fcaead3165a5ee49251c5d5c245bb2d/ruff-0.12.7-py3-none-win_arm64.whl", hash = "sha256:dfce05101dbd11833a0776716d5d1578641b7fddb537fe7fa956ab85d1769b69", size = 11982083, upload-time = "2025-07-29T22:32:33.881Z" },
2552
  ]
2553
 
2554
+ [[package]]
2555
+ name = "safehttpx"
2556
+ version = "0.1.6"
2557
+ source = { registry = "https://pypi.org/simple" }
2558
+ dependencies = [
2559
+ { name = "httpx" },
2560
+ ]
2561
+ sdist = { url = "https://files.pythonhosted.org/packages/67/4c/19db75e6405692b2a96af8f06d1258f8aa7290bdc35ac966f03e207f6d7f/safehttpx-0.1.6.tar.gz", hash = "sha256:b356bfc82cee3a24c395b94a2dbeabbed60aff1aa5fa3b5fe97c4f2456ebce42", size = 9987, upload-time = "2024-12-02T18:44:10.226Z" }
2562
+ wheels = [
2563
+ { url = "https://files.pythonhosted.org/packages/4d/c0/1108ad9f01567f66b3154063605b350b69c3c9366732e09e45f9fd0d1deb/safehttpx-0.1.6-py3-none-any.whl", hash = "sha256:407cff0b410b071623087c63dd2080c3b44dc076888d8c5823c00d1e58cb381c", size = 8692, upload-time = "2024-12-02T18:44:08.555Z" },
2564
+ ]
2565
+
2566
  [[package]]
2567
  name = "safetensors"
2568
  version = "0.5.3"
 
2670
  { url = "https://files.pythonhosted.org/packages/6e/6c/a76329897a7cae4937d403e623aa6aaea616a0bb5b36588f0b9d1c9a3739/scipy-1.16.1-cp314-cp314t-win_amd64.whl", hash = "sha256:c0c804d60492a0aad7f5b2bb1862f4548b990049e27e828391ff2bf6f7199998", size = 39427705, upload-time = "2025-07-27T16:31:53.96Z" },
2671
  ]
2672
 
2673
+ [[package]]
2674
+ name = "semantic-version"
2675
+ version = "2.10.0"
2676
+ source = { registry = "https://pypi.org/simple" }
2677
+ sdist = { url = "https://files.pythonhosted.org/packages/7d/31/f2289ce78b9b473d582568c234e104d2a342fd658cc288a7553d83bb8595/semantic_version-2.10.0.tar.gz", hash = "sha256:bdabb6d336998cbb378d4b9db3a4b56a1e3235701dc05ea2690d9a997ed5041c", size = 52289, upload-time = "2022-05-26T13:35:23.454Z" }
2678
+ wheels = [
2679
+ { url = "https://files.pythonhosted.org/packages/6a/23/8146aad7d88f4fcb3a6218f41a60f6c2d4e3a72de72da1825dc7c8f7877c/semantic_version-2.10.0-py2.py3-none-any.whl", hash = "sha256:de78a3b8e0feda74cabc54aab2da702113e33ac9d9eb9d2389bcf1f58b7d9177", size = 15552, upload-time = "2022-05-26T13:35:21.206Z" },
2680
+ ]
2681
+
2682
  [[package]]
2683
  name = "send2trash"
2684
  version = "1.8.3"
 
2716
  { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" },
2717
  ]
2718
 
2719
+ [[package]]
2720
+ name = "shellingham"
2721
+ version = "1.5.4"
2722
+ source = { registry = "https://pypi.org/simple" }
2723
+ sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" }
2724
+ wheels = [
2725
+ { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" },
2726
+ ]
2727
+
2728
  [[package]]
2729
  name = "six"
2730
  version = "1.17.0"
 
2795
  { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" },
2796
  ]
2797
 
2798
+ [[package]]
2799
+ name = "starlette"
2800
+ version = "0.47.2"
2801
+ source = { registry = "https://pypi.org/simple" }
2802
+ dependencies = [
2803
+ { name = "anyio" },
2804
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
2805
+ ]
2806
+ sdist = { url = "https://files.pythonhosted.org/packages/04/57/d062573f391d062710d4088fa1369428c38d51460ab6fedff920efef932e/starlette-0.47.2.tar.gz", hash = "sha256:6ae9aa5db235e4846decc1e7b79c4f346adf41e9777aebeb49dfd09bbd7023d8", size = 2583948, upload-time = "2025-07-20T17:31:58.522Z" }
2807
+ wheels = [
2808
+ { url = "https://files.pythonhosted.org/packages/f7/1f/b876b1f83aef204198a42dc101613fefccb32258e5428b5f9259677864b4/starlette-0.47.2-py3-none-any.whl", hash = "sha256:c5847e96134e5c5371ee9fac6fdf1a67336d5815e09eb2a01fdb57a351ef915b", size = 72984, upload-time = "2025-07-20T17:31:56.738Z" },
2809
+ ]
2810
+
2811
  [[package]]
2812
  name = "sympy"
2813
  version = "1.14.0"
 
2889
  { url = "https://files.pythonhosted.org/packages/41/f2/fd673d979185f5dcbac4be7d09461cbb99751554ffb6718d0013af8604cb/tokenizers-0.21.4-cp39-abi3-win_amd64.whl", hash = "sha256:475d807a5c3eb72c59ad9b5fcdb254f6e17f53dfcbb9903233b0dfa9c943b597", size = 2507568, upload-time = "2025-07-28T15:48:55.456Z" },
2890
  ]
2891
 
2892
+ [[package]]
2893
+ name = "tomlkit"
2894
+ version = "0.13.3"
2895
+ source = { registry = "https://pypi.org/simple" }
2896
+ sdist = { url = "https://files.pythonhosted.org/packages/cc/18/0bbf3884e9eaa38819ebe46a7bd25dcd56b67434402b66a58c4b8e552575/tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1", size = 185207, upload-time = "2025-06-05T07:13:44.947Z" }
2897
+ wheels = [
2898
+ { url = "https://files.pythonhosted.org/packages/bd/75/8539d011f6be8e29f339c42e633aae3cb73bffa95dd0f9adec09b9c58e85/tomlkit-0.13.3-py3-none-any.whl", hash = "sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0", size = 38901, upload-time = "2025-06-05T07:13:43.546Z" },
2899
+ ]
2900
+
2901
  [[package]]
2902
  name = "torch"
2903
  version = "2.2.2"
 
2990
  { url = "https://files.pythonhosted.org/packages/cf/18/eb7578f84ef5a080d4e5ca9bc4f7c68e7aa9c1e464f1b3d3001e4c642fce/transformers-4.54.1-py3-none-any.whl", hash = "sha256:c89965a4f62a0d07009d45927a9c6372848a02ab9ead9c318c3d082708bab529", size = 11176397, upload-time = "2025-07-29T15:57:19.692Z" },
2991
  ]
2992
 
2993
+ [[package]]
2994
+ name = "typer"
2995
+ version = "0.16.0"
2996
+ source = { registry = "https://pypi.org/simple" }
2997
+ dependencies = [
2998
+ { name = "click" },
2999
+ { name = "rich" },
3000
+ { name = "shellingham" },
3001
+ { name = "typing-extensions" },
3002
+ ]
3003
+ sdist = { url = "https://files.pythonhosted.org/packages/c5/8c/7d682431efca5fd290017663ea4588bf6f2c6aad085c7f108c5dbc316e70/typer-0.16.0.tar.gz", hash = "sha256:af377ffaee1dbe37ae9440cb4e8f11686ea5ce4e9bae01b84ae7c63b87f1dd3b", size = 102625, upload-time = "2025-05-26T14:30:31.824Z" }
3004
+ wheels = [
3005
+ { url = "https://files.pythonhosted.org/packages/76/42/3efaf858001d2c2913de7f354563e3a3a2f0decae3efe98427125a8f441e/typer-0.16.0-py3-none-any.whl", hash = "sha256:1f79bed11d4d02d4310e3c1b7ba594183bcedb0ac73b27a9e5f28f6fb5b98855", size = 46317, upload-time = "2025-05-26T14:30:30.523Z" },
3006
+ ]
3007
+
3008
  [[package]]
3009
  name = "types-python-dateutil"
3010
  version = "2.9.0.20250708"
 
3035
  { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" },
3036
  ]
3037
 
3038
+ [[package]]
3039
+ name = "tzdata"
3040
+ version = "2025.2"
3041
+ source = { registry = "https://pypi.org/simple" }
3042
+ sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" }
3043
+ wheels = [
3044
+ { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" },
3045
+ ]
3046
+
3047
  [[package]]
3048
  name = "uri-template"
3049
  version = "1.3.0"
 
3071
  { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" },
3072
  ]
3073
 
3074
+ [[package]]
3075
+ name = "uvicorn"
3076
+ version = "0.35.0"
3077
+ source = { registry = "https://pypi.org/simple" }
3078
+ dependencies = [
3079
+ { name = "click" },
3080
+ { name = "h11" },
3081
+ ]
3082
+ sdist = { url = "https://files.pythonhosted.org/packages/5e/42/e0e305207bb88c6b8d3061399c6a961ffe5fbb7e2aa63c9234df7259e9cd/uvicorn-0.35.0.tar.gz", hash = "sha256:bc662f087f7cf2ce11a1d7fd70b90c9f98ef2e2831556dd078d131b96cc94a01", size = 78473, upload-time = "2025-06-28T16:15:46.058Z" }
3083
+ wheels = [
3084
+ { url = "https://files.pythonhosted.org/packages/d2/e2/dc81b1bd1dcfe91735810265e9d26bc8ec5da45b4c0f6237e286819194c3/uvicorn-0.35.0-py3-none-any.whl", hash = "sha256:197535216b25ff9b785e29a0b79199f55222193d47f820816e7da751e9bc8d4a", size = 66406, upload-time = "2025-06-28T16:15:44.816Z" },
3085
+ ]
3086
+
3087
  [[package]]
3088
  name = "wcwidth"
3089
  version = "0.2.13"
 
3120
  { url = "https://files.pythonhosted.org/packages/5a/84/44687a29792a70e111c5c477230a72c4b957d88d16141199bf9acb7537a3/websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", size = 58826, upload-time = "2024-04-23T22:16:14.422Z" },
3121
  ]
3122
 
3123
+ [[package]]
3124
+ name = "websockets"
3125
+ version = "15.0.1"
3126
+ source = { registry = "https://pypi.org/simple" }
3127
+ sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" }
3128
+ wheels = [
3129
+ { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437, upload-time = "2025-03-05T20:02:16.706Z" },
3130
+ { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096, upload-time = "2025-03-05T20:02:18.832Z" },
3131
+ { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332, upload-time = "2025-03-05T20:02:20.187Z" },
3132
+ { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152, upload-time = "2025-03-05T20:02:22.286Z" },
3133
+ { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096, upload-time = "2025-03-05T20:02:24.368Z" },
3134
+ { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523, upload-time = "2025-03-05T20:02:25.669Z" },
3135
+ { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790, upload-time = "2025-03-05T20:02:26.99Z" },
3136
+ { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165, upload-time = "2025-03-05T20:02:30.291Z" },
3137
+ { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160, upload-time = "2025-03-05T20:02:31.634Z" },
3138
+ { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395, upload-time = "2025-03-05T20:02:33.017Z" },
3139
+ { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841, upload-time = "2025-03-05T20:02:34.498Z" },
3140
+ { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" },
3141
+ { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" },
3142
+ { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" },
3143
+ { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" },
3144
+ { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" },
3145
+ { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" },
3146
+ { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" },
3147
+ { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" },
3148
+ { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" },
3149
+ { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" },
3150
+ { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" },
3151
+ { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" },
3152
+ ]
3153
+
3154
  [[package]]
3155
  name = "zstandard"
3156
  version = "0.23.0"