caul-core 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,213 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Models
10
+ .models/
11
+
12
+ # Distribution / packaging
13
+ .Python
14
+ build/
15
+ develop-eggs/
16
+ dist/
17
+ downloads/
18
+ eggs/
19
+ .eggs/
20
+ lib/
21
+ lib64/
22
+ parts/
23
+ sdist/
24
+ var/
25
+ wheels/
26
+ share/python-wheels/
27
+ *.egg-info/
28
+ .installed.cfg
29
+ *.egg
30
+ MANIFEST
31
+
32
+ # PyInstaller
33
+ # Usually these files are written by a python script from a template
34
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
35
+ *.manifest
36
+ *.spec
37
+
38
+ # Installer logs
39
+ pip-log.txt
40
+ pip-delete-this-directory.txt
41
+
42
+ # Unit test / coverage reports
43
+ htmlcov/
44
+ .tox/
45
+ .nox/
46
+ .coverage
47
+ .coverage.*
48
+ .cache
49
+ nosetests.xml
50
+ coverage.xml
51
+ *.cover
52
+ *.py.cover
53
+ .hypothesis/
54
+ .pytest_cache/
55
+ cover/
56
+
57
+ # Translations
58
+ *.mo
59
+ *.pot
60
+
61
+ # Django stuff:
62
+ *.log
63
+ local_settings.py
64
+ db.sqlite3
65
+ db.sqlite3-journal
66
+
67
+ # Flask stuff:
68
+ instance/
69
+ .webassets-cache
70
+
71
+ # Scrapy stuff:
72
+ .scrapy
73
+
74
+ # Sphinx documentation
75
+ docs/_build/
76
+
77
+ # PyBuilder
78
+ .pybuilder/
79
+ target/
80
+
81
+ # Jupyter Notebook
82
+ .ipynb_checkpoints
83
+
84
+ # IPython
85
+ profile_default/
86
+ ipython_config.py
87
+
88
+ # pyenv
89
+ # For a library or package, you might want to ignore these files since the code is
90
+ # intended to run in multiple environments; otherwise, check them in:
91
+ # .python-version
92
+
93
+ # pipenv
94
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
95
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
96
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
97
+ # install all needed dependencies.
98
+ #Pipfile.lock
99
+
100
+ # UV
101
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
102
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
103
+ # commonly ignored for libraries.
104
+ #uv.lock
105
+
106
+ # poetry
107
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
108
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
109
+ # commonly ignored for libraries.
110
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
111
+ #poetry.lock
112
+ #poetry.toml
113
+
114
+ # pdm
115
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
116
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
117
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
118
+ #pdm.lock
119
+ #pdm.toml
120
+ .pdm-python
121
+ .pdm-build/
122
+
123
+ # pixi
124
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
125
+ #pixi.lock
126
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
127
+ # in the .venv directory. It is recommended not to include this directory in version control.
128
+ .pixi
129
+
130
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
131
+ __pypackages__/
132
+
133
+ # Celery stuff
134
+ celerybeat-schedule
135
+ celerybeat.pid
136
+
137
+ # SageMath parsed files
138
+ *.sage.py
139
+
140
+ # Environments
141
+ .env
142
+ .envrc
143
+ .venv
144
+ env/
145
+ venv/
146
+ ENV/
147
+ env.bak/
148
+ venv.bak/
149
+
150
+ # Spyder project settings
151
+ .spyderproject
152
+ .spyproject
153
+
154
+ # Rope project settings
155
+ .ropeproject
156
+
157
+ # mkdocs documentation
158
+ /site
159
+
160
+ # mypy
161
+ .mypy_cache/
162
+ .dmypy.json
163
+ dmypy.json
164
+
165
+ # Pyre type checker
166
+ .pyre/
167
+
168
+ # pytype static type analyzer
169
+ .pytype/
170
+
171
+ # Cython debug symbols
172
+ cython_debug/
173
+
174
+ # PyCharm
175
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
176
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
177
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
178
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
179
+ #.idea/
180
+
181
+ # Abstra
182
+ # Abstra is an AI-powered process automation framework.
183
+ # Ignore directories containing user credentials, local state, and settings.
184
+ # Learn more at https://abstra.io/docs
185
+ .abstra/
186
+
187
+ # Visual Studio Code
188
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
189
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
190
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
191
+ # you could uncomment the following to ignore the entire vscode folder
192
+ # .vscode/
193
+
194
+ # Ruff stuff:
195
+ .ruff_cache/
196
+
197
+ # PyPI configuration file
198
+ .pypirc
199
+
200
+ # Cursor
201
+ # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
202
+ # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
203
+ # refer to https://docs.cursor.com/context/ignore-files
204
+ .cursorignore
205
+ .cursorindexingignore
206
+
207
+ # Marimo
208
+ marimo/_static/
209
+ marimo/_lsp/
210
+ __marimo__/
211
+
212
+ # Others
213
+ *.idea/
@@ -0,0 +1 @@
1
+ 3.13
@@ -0,0 +1,13 @@
1
+ Metadata-Version: 2.4
2
+ Name: caul-core
3
+ Version: 0.1.0
4
+ Summary: core objects for caul ASR
5
+ Author-email: Lion Summerbell <lsummerbell@icij.org>
6
+ Requires-Python: <3.14.0,>=3.11.0
7
+ Requires-Dist: icij-common~=0.8.1
8
+ Requires-Dist: pydantic-extra-types[pycountry]~=2.11
9
+ Description-Content-Type: text/markdown
10
+
11
+ # Core caul objects
12
+
13
+ Separates core configs and objects for separate import without having to pull in heavier `caul` dependencies.
@@ -0,0 +1,3 @@
1
+ # Core caul objects
2
+
3
+ Separates core configs and objects for separate import without having to pull in heavier `caul` dependencies.
File without changes
@@ -0,0 +1,77 @@
1
+ import logging
2
+ from typing import Self
3
+
4
+ from icij_common.pydantic_utils import make_enum_discriminator, tagged_union
5
+ from pydantic import Discriminator, Field
6
+
7
+ from .objects import BaseModel, ASRModel, TorchDevice
8
+ from .config import (
9
+ PreprocessorConfig,
10
+ InferenceRunnerConfig,
11
+ PostprocessorConfig,
12
+ ParakeetPreprocessorConfig,
13
+ ParakeetInferenceRunnerConfig,
14
+ ParakeetPostprocessorConfig,
15
+ FireRedASR2PreprocessorConfig,
16
+ FireRedASR2InferenceRunnerConfig,
17
+ FireRedASR2PostprocessorConfig,
18
+ FasterWhisperPreprocessorConfig,
19
+ FasterWhisperInferenceRunnerConfig,
20
+ FasterWhisperPostprocessorConfig,
21
+ )
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+ PreprocessorConfig_ = tagged_union(
26
+ PreprocessorConfig.__subclasses__(), lambda t: t.model.default.value
27
+ )
28
+
29
+ InferenceRunnerConfig_ = tagged_union(
30
+ InferenceRunnerConfig.__subclasses__(), lambda t: t.model.default.value
31
+ )
32
+
33
+ PostprocessorConfig_ = tagged_union(
34
+ PostprocessorConfig.__subclasses__(), lambda t: t.model.default.value
35
+ )
36
+
37
+ model_discriminator = make_enum_discriminator("model", ASRModel)
38
+
39
+
40
+ class ASRPipelineConfig(BaseModel): # pylint: disable=too-few-public-methods
41
+ device: TorchDevice = TorchDevice.CPU
42
+ preprocessing: PreprocessorConfig_ = Field(
43
+ discriminator=Discriminator(model_discriminator),
44
+ )
45
+ inference: InferenceRunnerConfig_ = Field(
46
+ default_factory=InferenceRunnerConfig,
47
+ discriminator=Discriminator(model_discriminator),
48
+ )
49
+ postprocessing: PostprocessorConfig_ = Field(
50
+ discriminator=Discriminator(model_discriminator),
51
+ )
52
+
53
+ @classmethod
54
+ def parakeet(cls) -> Self:
55
+ return cls(
56
+ preprocessing=ParakeetPreprocessorConfig(),
57
+ inference=ParakeetInferenceRunnerConfig(),
58
+ postprocessing=ParakeetPostprocessorConfig(),
59
+ )
60
+
61
+ @classmethod
62
+ def fireredasr2(cls, tmp_dir_fallback: bool = True) -> Self:
63
+ return cls(
64
+ preprocessing=FireRedASR2PreprocessorConfig(),
65
+ inference=FireRedASR2InferenceRunnerConfig(
66
+ tmp_dir_fallback=tmp_dir_fallback
67
+ ),
68
+ postprocessing=FireRedASR2PostprocessorConfig(),
69
+ )
70
+
71
+ @classmethod
72
+ def faster_whisper(cls) -> Self:
73
+ return cls(
74
+ preprocessing=FasterWhisperPreprocessorConfig(),
75
+ inference=FasterWhisperInferenceRunnerConfig(),
76
+ postprocessing=FasterWhisperPostprocessorConfig(),
77
+ )
@@ -0,0 +1,165 @@
1
+ from abc import ABC
2
+ from typing import ClassVar
3
+
4
+ from icij_common.registrable import RegistrableConfig
5
+ from pydantic import Field
6
+
7
+ from .constants import (
8
+ DEFAULT_SAMPLE_RATE,
9
+ DEFAULT_BATCH_SIZE,
10
+ DEFAULT_MAX_FRAMES,
11
+ DEFAULT_LARGE_FILE_THRESHOLD_BYTES,
12
+ PARAKEET_INFERENCE_MAX_FRAMES,
13
+ PARAKEET_MODEL_REF,
14
+ FIREREDASR2_USE_HALF_DEFAULT,
15
+ FIREREDASR2_BEAM_SIZE_DEFAULT,
16
+ FIREREDASR2_NBEST_DEFAULT,
17
+ FIREREDASR2_DECODE_MAX_LEN_DEFAULT,
18
+ FIREREDASR2_SOFTMAX_SMOOTHING_DEFAULT,
19
+ FIREREDASR2_AED_LENGTH_PENALTY_DEFAULT,
20
+ FIREREDASR2_EOS_PENALTY_DEFAULT,
21
+ FIREREDASR2_RETURN_TIMESTAMP_DEFAULT,
22
+ FIREREDASR2_INFERENCE_MAX_FRAMES,
23
+ FASTER_WHISPER_COMPUTE_TYPE_DEFAULT,
24
+ FASTER_WHISPER_WORD_TIMESTAMPS_DEFAULT,
25
+ FASTER_WHISPER_BEAM_SIZE_DEFAULT,
26
+ FASTER_WHISPER_BEST_OF_DEFAULT,
27
+ FASTER_WHISPER_PATIENCE_DEFAULT,
28
+ FASTER_WHISPER_LENGTH_PENALTY_DEFAULT,
29
+ FASTER_WHISPER_REPETITION_PENALTY_DEFAULT,
30
+ FASTER_WHISPER_NO_REPEAT_NGRAM_SIZE_DEFAULT,
31
+ FASTER_WHISPER_LOG_PROB_THRESHOLD_DEFAULT,
32
+ FASTER_WHISPER_NO_SPEECH_THRESHOLD_DEFAULT,
33
+ FASTER_WHISPER_COMPRESSION_RATIO_THRESHOLD_DEFAULT,
34
+ FASTER_WHISPER_CONDITION_ON_PREVIOUS_TEXT_DEFAULT,
35
+ FASTER_WHISPER_PROMPT_RESET_ON_TEMPERATURE_DEFAULT,
36
+ FASTER_WHISPER_TEMPERATURES_DEFAULT,
37
+ FASTER_WHISPER_SUPPRESS_BLANK_DEFAULT,
38
+ FASTER_WHISPER_LARGE_V3_TURBO_SUPPRESSED_TOKENS,
39
+ FASTER_WHISPER_WITHOUT_TIMESTAMPS_DEFAULT,
40
+ FASTER_WHISPER_MAX_INITIAL_TIMESTAMP_DEFAULT,
41
+ FASTER_WHISPER_PREPEND_PUNCTUATIONS_DEFAULT,
42
+ FASTER_WHISPER_APPEND_PUNCTUATIONS_DEFAULT,
43
+ FASTER_WHISPER_MULTILINGUAL_DEFAULT,
44
+ FASTER_WHISPER_CLIP_TIMESTAMPS_DEFAULT,
45
+ )
46
+ from .objects import BaseModel, ASRModel, FasterWhisperModel
47
+
48
+
49
+ class _BaseConfig(BaseModel, RegistrableConfig, ABC): ...
50
+
51
+
52
+ class PreprocessorConfig(_BaseConfig):
53
+ registry_key: ClassVar[str] = Field(frozen=True, default="model")
54
+ model: ClassVar[ASRModel]
55
+
56
+ max_frames: int = DEFAULT_MAX_FRAMES
57
+ batch_size: int = DEFAULT_BATCH_SIZE
58
+ sample_rate: int = DEFAULT_SAMPLE_RATE
59
+ large_file_threshold_bytes: int = DEFAULT_LARGE_FILE_THRESHOLD_BYTES
60
+
61
+
62
+ class InferenceRunnerConfig(_BaseConfig):
63
+ registry_key: ClassVar[str] = Field(frozen=True, default="model")
64
+ model: ClassVar[ASRModel]
65
+
66
+ tmp_dir_fallback: bool = False
67
+
68
+
69
+ class PostprocessorConfig(_BaseConfig):
70
+ registry_key: ClassVar[str] = Field(frozen=True, default="model")
71
+ model: ClassVar[ASRModel]
72
+
73
+
74
+ # Parakeet
75
+
76
+
77
+ class ParakeetPreprocessorConfig(PreprocessorConfig):
78
+ model: ClassVar[str] = Field(default=ASRModel.PARAKEET)
79
+
80
+ max_frames: int = PARAKEET_INFERENCE_MAX_FRAMES
81
+
82
+
83
+ class ParakeetInferenceRunnerConfig(InferenceRunnerConfig):
84
+ model: ClassVar[str] = Field(frozen=True, default=ASRModel.PARAKEET)
85
+ model_name: str = PARAKEET_MODEL_REF
86
+ return_timestamps: bool = True
87
+
88
+
89
+ class ParakeetPostprocessorConfig(PostprocessorConfig):
90
+ model: ClassVar[str] = Field(frozen=True, default=ASRModel.PARAKEET)
91
+
92
+
93
+ # Faster Whisper
94
+
95
+
96
+ class FasterWhisperPreprocessorConfig(PreprocessorConfig):
97
+ model: ClassVar[str] = Field(default=ASRModel.FASTER_WHISPER)
98
+
99
+
100
+ class FasterWhisperInferenceRunnerConfig(InferenceRunnerConfig):
101
+ model: ClassVar[str] = Field(frozen=True, default=ASRModel.FASTER_WHISPER)
102
+
103
+ whisper_model_name: FasterWhisperModel = FasterWhisperModel.MEDIUM
104
+
105
+ compute_type: str = FASTER_WHISPER_COMPUTE_TYPE_DEFAULT
106
+ word_timestamps: bool = FASTER_WHISPER_WORD_TIMESTAMPS_DEFAULT
107
+ beam_size: int = FASTER_WHISPER_BEAM_SIZE_DEFAULT
108
+ best_of: int = FASTER_WHISPER_BEST_OF_DEFAULT
109
+ patience: int = FASTER_WHISPER_PATIENCE_DEFAULT
110
+ length_penalty: int = FASTER_WHISPER_LENGTH_PENALTY_DEFAULT
111
+ repetition_penalty: int = FASTER_WHISPER_REPETITION_PENALTY_DEFAULT
112
+ no_repeat_ngram_size: int = FASTER_WHISPER_NO_REPEAT_NGRAM_SIZE_DEFAULT
113
+ log_prob_threshold: float = FASTER_WHISPER_LOG_PROB_THRESHOLD_DEFAULT
114
+ no_speech_threshold: float = FASTER_WHISPER_NO_SPEECH_THRESHOLD_DEFAULT
115
+ compression_ratio_threshold: float = (
116
+ FASTER_WHISPER_COMPRESSION_RATIO_THRESHOLD_DEFAULT
117
+ )
118
+ condition_on_previous_text: bool = FASTER_WHISPER_CONDITION_ON_PREVIOUS_TEXT_DEFAULT
119
+ prompt_reset_on_temperature: float = (
120
+ FASTER_WHISPER_PROMPT_RESET_ON_TEMPERATURE_DEFAULT
121
+ )
122
+ temperatures: list[float] = FASTER_WHISPER_TEMPERATURES_DEFAULT
123
+ initial_prompt: str | None = None
124
+ prefix: str | None = None
125
+ suppress_blank: bool = FASTER_WHISPER_SUPPRESS_BLANK_DEFAULT
126
+ suppress_tokens: list[int] = FASTER_WHISPER_LARGE_V3_TURBO_SUPPRESSED_TOKENS
127
+ without_timestamps: bool = FASTER_WHISPER_WITHOUT_TIMESTAMPS_DEFAULT
128
+ max_initial_timestamp: float = FASTER_WHISPER_MAX_INITIAL_TIMESTAMP_DEFAULT
129
+ prepend_punctuations: str = FASTER_WHISPER_PREPEND_PUNCTUATIONS_DEFAULT
130
+ append_punctuations: str = FASTER_WHISPER_APPEND_PUNCTUATIONS_DEFAULT
131
+ multilingual: bool = FASTER_WHISPER_MULTILINGUAL_DEFAULT
132
+ max_new_tokens: int | None = None
133
+ clip_timestamps: list[float] = FASTER_WHISPER_CLIP_TIMESTAMPS_DEFAULT
134
+ hallucination_silence_threshold: float | None = None
135
+ hotwords: str | None = None
136
+
137
+
138
+ class FasterWhisperPostprocessorConfig(PostprocessorConfig):
139
+ model: ClassVar[str] = Field(frozen=True, default=ASRModel.FASTER_WHISPER)
140
+
141
+
142
+ # FireRedASR2s
143
+
144
+
145
+ class FireRedASR2PreprocessorConfig(PreprocessorConfig):
146
+ model: ClassVar[str] = Field(default=ASRModel.FIREREDASR2_AED)
147
+
148
+ max_frames: int = FIREREDASR2_INFERENCE_MAX_FRAMES
149
+
150
+
151
+ class FireRedASR2InferenceRunnerConfig(InferenceRunnerConfig):
152
+ model: ClassVar[str] = Field(frozen=True, default=ASRModel.FIREREDASR2_AED)
153
+
154
+ use_half: bool = FIREREDASR2_USE_HALF_DEFAULT
155
+ beam_size: int = FIREREDASR2_BEAM_SIZE_DEFAULT
156
+ nbest: int = FIREREDASR2_NBEST_DEFAULT
157
+ decode_max_len: int = FIREREDASR2_DECODE_MAX_LEN_DEFAULT
158
+ softmax_smoothing: float = FIREREDASR2_SOFTMAX_SMOOTHING_DEFAULT
159
+ aed_length_penalty: float = FIREREDASR2_AED_LENGTH_PENALTY_DEFAULT
160
+ eos_penalty: float = FIREREDASR2_EOS_PENALTY_DEFAULT
161
+ return_timestamp: bool = FIREREDASR2_RETURN_TIMESTAMP_DEFAULT
162
+
163
+
164
+ class FireRedASR2PostprocessorConfig(PostprocessorConfig):
165
+ model: ClassVar[str] = Field(frozen=True, default=ASRModel.FIREREDASR2_AED)
@@ -0,0 +1,178 @@
1
+ DEFAULT_SAMPLE_RATE = 16000
2
+ DEFAULT_BATCH_SIZE = 32
3
+ DEFAULT_MAX_FRAMES = 25 * 60 * DEFAULT_SAMPLE_RATE # twenty-five minutes
4
+ DEFAULT_LARGE_FILE_THRESHOLD_BYTES = 30 * 1024 * 1024 # 30mb
5
+
6
+ # Parakeet
7
+
8
+ PARAKEET_MODEL_REF = "nvidia/parakeet-tdt-0.6b-v3"
9
+ PARAKEET_INFERENCE_MAX_DURATION_S = (
10
+ 20 * 60 # actually 24, but we want to give ourselves some room to avoid CUDA OOMs
11
+ )
12
+ PARAKEET_INFERENCE_MAX_FRAMES = PARAKEET_INFERENCE_MAX_DURATION_S * DEFAULT_SAMPLE_RATE
13
+
14
+
15
+ # Faster Whisper (SYSTRAN/faster-whisper)
16
+
17
+ FASTER_WHISPER_COMPUTE_TYPE_DEFAULT = "float32"
18
+ FASTER_WHISPER_WORD_TIMESTAMPS_DEFAULT = True
19
+ FASTER_WHISPER_BEAM_SIZE_DEFAULT = 5
20
+ FASTER_WHISPER_BEST_OF_DEFAULT = 5
21
+ FASTER_WHISPER_PATIENCE_DEFAULT = 1
22
+ FASTER_WHISPER_LENGTH_PENALTY_DEFAULT = 1
23
+ FASTER_WHISPER_REPETITION_PENALTY_DEFAULT = 1
24
+ FASTER_WHISPER_NO_REPEAT_NGRAM_SIZE_DEFAULT = 0
25
+ FASTER_WHISPER_LOG_PROB_THRESHOLD_DEFAULT = -1.0
26
+ FASTER_WHISPER_NO_SPEECH_THRESHOLD_DEFAULT = 0.6
27
+ FASTER_WHISPER_COMPRESSION_RATIO_THRESHOLD_DEFAULT = 2.4
28
+ FASTER_WHISPER_CONDITION_ON_PREVIOUS_TEXT_DEFAULT = False
29
+ FASTER_WHISPER_PROMPT_RESET_ON_TEMPERATURE_DEFAULT = 0.5
30
+ FASTER_WHISPER_TEMPERATURES_DEFAULT = [0.0]
31
+ FASTER_WHISPER_SUPPRESS_BLANK_DEFAULT = True
32
+ FASTER_WHISPER_WITHOUT_TIMESTAMPS_DEFAULT = True
33
+ FASTER_WHISPER_MAX_INITIAL_TIMESTAMP_DEFAULT = 0.0
34
+ FASTER_WHISPER_PREPEND_PUNCTUATIONS_DEFAULT = "\"'‘’“¿([{—-"
35
+ FASTER_WHISPER_APPEND_PUNCTUATIONS_DEFAULT = "\"'’”.。,,!!??::””)]、結}"
36
+ FASTER_WHISPER_MULTILINGUAL_DEFAULT = False
37
+ FASTER_WHISPER_CLIP_TIMESTAMPS_DEFAULT = []
38
+ FASTER_WHISPER_LARGE_V3_TURBO_SUPPRESSED_TOKENS = [
39
+ 1,
40
+ 2,
41
+ 7,
42
+ 8,
43
+ 9,
44
+ 10,
45
+ 14,
46
+ 25,
47
+ 26,
48
+ 27,
49
+ 28,
50
+ 29,
51
+ 31,
52
+ 58,
53
+ 59,
54
+ 60,
55
+ 61,
56
+ 62,
57
+ 63,
58
+ 90,
59
+ 91,
60
+ 92,
61
+ 93,
62
+ 359,
63
+ 503,
64
+ 522,
65
+ 542,
66
+ 873,
67
+ 893,
68
+ 902,
69
+ 918,
70
+ 922,
71
+ 931,
72
+ 1350,
73
+ 1853,
74
+ 1982,
75
+ 2460,
76
+ 2627,
77
+ 3246,
78
+ 3253,
79
+ 3268,
80
+ 3536,
81
+ 3846,
82
+ 3961,
83
+ 4183,
84
+ 4667,
85
+ 6585,
86
+ 6647,
87
+ 7273,
88
+ 9061,
89
+ 9383,
90
+ 10428,
91
+ 10929,
92
+ 11938,
93
+ 12033,
94
+ 12331,
95
+ 12562,
96
+ 13793,
97
+ 14157,
98
+ 14635,
99
+ 15265,
100
+ 15618,
101
+ 16553,
102
+ 16604,
103
+ 18362,
104
+ 18956,
105
+ 20075,
106
+ 21675,
107
+ 22520,
108
+ 26130,
109
+ 26161,
110
+ 26435,
111
+ 28279,
112
+ 29464,
113
+ 31650,
114
+ 32302,
115
+ 32470,
116
+ 36865,
117
+ 42863,
118
+ 47425,
119
+ 49870,
120
+ 50254,
121
+ 50258,
122
+ 50359,
123
+ 50360,
124
+ 50361,
125
+ 50362,
126
+ 50363,
127
+ ]
128
+
129
+ # FireRedASR2s
130
+
131
+ FIREREDASR2_MODEL_HUB_PREFIX = "FireRedTeam/FireRed"
132
+ FIREREDASR2_INFERENCE_MAX_DURATION_S = 60
133
+ FIREREDASR2_INFERENCE_MAX_FRAMES = (
134
+ FIREREDASR2_INFERENCE_MAX_DURATION_S * DEFAULT_SAMPLE_RATE
135
+ )
136
+ FIREREDASR2_USE_HALF_DEFAULT = False
137
+ FIREREDASR2_BEAM_SIZE_DEFAULT = 3
138
+ FIREREDASR2_NBEST_DEFAULT = 1
139
+ FIREREDASR2_DECODE_MAX_LEN_DEFAULT = 0
140
+ FIREREDASR2_SOFTMAX_SMOOTHING_DEFAULT = 1.25
141
+ FIREREDASR2_AED_LENGTH_PENALTY_DEFAULT = 0.6
142
+ FIREREDASR2_EOS_PENALTY_DEFAULT = 1.0
143
+ FIREREDASR2_RETURN_TIMESTAMP_DEFAULT = True
144
+
145
+ # Languages
146
+ PARAKEET_TDT_0_6B_V3_LANGUAGES = {
147
+ "bg",
148
+ "hr",
149
+ "cs",
150
+ "da",
151
+ "nl",
152
+ "en",
153
+ "et",
154
+ "fi",
155
+ "fr",
156
+ "de",
157
+ "el",
158
+ "hu",
159
+ "it",
160
+ "lv",
161
+ "lt",
162
+ "mt",
163
+ "pl",
164
+ "pt",
165
+ "ro",
166
+ "sk",
167
+ "sl",
168
+ "es",
169
+ "sv",
170
+ "ru",
171
+ "uk",
172
+ }
173
+ FIREREDASR2_LANGUAGES = {"zh"}
174
+
175
+
176
+ # Silero
177
+
178
+ SILERO_VAD_MODEL = "silero_vad"
@@ -0,0 +1,246 @@
1
+ import datetime
2
+ import math
3
+ from dataclasses import dataclass
4
+ from enum import StrEnum, unique
5
+ from pathlib import Path
6
+ from typing import Self, TYPE_CHECKING
7
+
8
+ import uuid
9
+
10
+ import langcodes
11
+ from icij_common.pydantic_utils import icij_config, merge_configs, no_enum_values_config
12
+ from pydantic import BaseModel as _BaseModel, Field, GetCoreSchemaHandler, TypeAdapter
13
+ from pydantic_core import core_schema
14
+ from pydantic_extra_types.language_code import LanguageAlpha2
15
+
16
+ from .constants import PARAKEET_TDT_0_6B_V3_LANGUAGES, FIREREDASR2_LANGUAGES
17
+
18
+ if TYPE_CHECKING:
19
+ import torch
20
+
21
+
22
+ # Enums
23
+
24
+
25
+ class FireRedASR2ModelRef(StrEnum):
26
+ ASR2 = "ASR2"
27
+
28
+
29
+ class FireRedASR2ModelTag(StrEnum):
30
+ AED = "aed"
31
+ LLM = "llm"
32
+
33
+
34
+ class VadModelRef(StrEnum):
35
+ SILERO_MODEL = "snakers4/silero-vad"
36
+ PYANNOTE_MODEL = "pyannote/segmentation-3.0"
37
+
38
+
39
+ class TorchDevice(StrEnum):
40
+ CPU = "cpu"
41
+ GPU = "cuda"
42
+ MPS = "mps"
43
+
44
+
45
+ @unique
46
+ class FasterWhisperModel(StrEnum):
47
+ TINY = "tiny"
48
+ BASE = "base"
49
+ SMALL = "small"
50
+ MEDIUM = "medium"
51
+ LARGE = "large"
52
+ LARGE_V3 = "large-v3"
53
+ DISTIL_LARGE_V3 = "distil-large-v3"
54
+
55
+ @property
56
+ def to_repo_id(self) -> str:
57
+ match self:
58
+ case FasterWhisperModel.TINY:
59
+ return "Systran/faster-whisper-tiny"
60
+ case FasterWhisperModel.BASE:
61
+ return "Systran/faster-whisper-base"
62
+ case FasterWhisperModel.SMALL:
63
+ return "Systran/faster-whisper-small"
64
+ case FasterWhisperModel.MEDIUM:
65
+ return "Systran/faster-whisper-medium"
66
+ case FasterWhisperModel.LARGE:
67
+ return "Systran/faster-whisper-large-v3"
68
+ case FasterWhisperModel.LARGE_V3:
69
+ return "Systran/faster-whisper-large-v3"
70
+ case FasterWhisperModel.DISTIL_LARGE_V3:
71
+ return "Systran/faster-distil-whisper-large-v3"
72
+ case _:
73
+ raise NotImplementedError(f"invalid faster whisper model {self}")
74
+
75
+
76
+ # Models
77
+
78
+
79
+ class BaseModel(_BaseModel):
80
+ model_config = merge_configs(icij_config(), no_enum_values_config())
81
+
82
+
83
+ class IETFLanguage(str):
84
+ @classmethod
85
+ def __get_pydantic_core_schema__(cls, source, handler: GetCoreSchemaHandler):
86
+ return core_schema.no_info_plain_validator_function(cls.validate)
87
+
88
+ @classmethod
89
+ def validate(cls, v):
90
+ tag = langcodes.get(str(v))
91
+ if not tag.is_valid():
92
+ raise ValueError(f"Invalid IETF language: {v}")
93
+ return cls(v)
94
+
95
+
96
+ ASRLanguage = IETFLanguage | LanguageAlpha2
97
+ _LANGUAGE_TYPE_ADAPTER = TypeAdapter(ASRLanguage)
98
+
99
+ _VALIDATED_PARAKEET_LANGUAGES = {
100
+ _LANGUAGE_TYPE_ADAPTER.validate_python(lang)
101
+ for lang in PARAKEET_TDT_0_6B_V3_LANGUAGES
102
+ }
103
+
104
+ _VALIDATED_FIREREDASR2_LANGUAGES = {
105
+ _LANGUAGE_TYPE_ADAPTER.validate_python(lang) for lang in FIREREDASR2_LANGUAGES
106
+ }
107
+
108
+
109
+ class ASRModel(StrEnum):
110
+ PARAKEET = "parakeet"
111
+ FASTER_WHISPER = "faster_whisper"
112
+ FIREREDASR2_AED = "fireredasr2_aed"
113
+
114
+ def supported_languages(self) -> set[ASRLanguage]:
115
+ match self:
116
+ case ASRModel.PARAKEET:
117
+ return _VALIDATED_PARAKEET_LANGUAGES
118
+ case ASRModel.FASTER_WHISPER:
119
+ return set()
120
+ case ASRModel.FIREREDASR2_AED:
121
+ return _VALIDATED_FIREREDASR2_LANGUAGES
122
+ case _:
123
+ msg = f"model {self} should expose supported languages"
124
+ raise NotImplementedError(msg)
125
+
126
+
127
+ class ASRResult(BaseModel):
128
+ """Base result class for ASR models"""
129
+
130
+ input_ordering: int = -1
131
+ transcription: list[tuple] = Field(default_factory=list)
132
+ score: float = 1.0
133
+
134
+ @property
135
+ def duration(self) -> float:
136
+ if not self.transcription:
137
+ return 0.0
138
+ total = sum(end - start for start, end, _ in self.transcription)
139
+ return total
140
+
141
+ @classmethod
142
+ def from_parakeet_hypothesis(cls, hypothesis: "Hypothesis", **extra) -> Self:
143
+ """Parse a hypothesis returned by a Parakeet RNN model
144
+
145
+ :param hypothesis: Parakeet hypothesis
146
+ :return: copy of self
147
+ """
148
+
149
+ # there's some weird inconsistency here between nemo versions
150
+ timestamps = hypothesis.timestamp
151
+ transcription = [
152
+ (s["start"], s["end"], s["segment"]) for s in timestamps["segment"]
153
+ ]
154
+ return cls(transcription=transcription, score=hypothesis.score, **extra)
155
+
156
+ @classmethod
157
+ def from_fireredasr2_result(cls, result: dict, **extra) -> Self:
158
+ """Parse a result dict returned by a FireRedASR2 AED model
159
+
160
+ :param result: dict with keys 'text', 'confidence', 'dur_s', 'timestamp'
161
+ :return: ASRResult
162
+ """
163
+ text = result.get("text") or ""
164
+ timestamp = result.get("timestamp") or []
165
+ if timestamp:
166
+ start_s = float(timestamp[0][1])
167
+ end_s = float(timestamp[-1][2])
168
+ else:
169
+ start_s = 0.0
170
+ end_s = float(result.get("dur_s") or 0.0)
171
+ transcription = [(start_s, end_s, text)] if text.strip() else []
172
+ confidence = result.get("confidence")
173
+ score = float(confidence) if confidence is not None else -1.0
174
+ return cls(transcription=transcription, score=score, **extra)
175
+
176
+ @classmethod
177
+ def from_faster_whisper_result(cls, segments, **extra) -> Self:
178
+ """Parse segments returned by a faster-whisper model
179
+
180
+ :param segments: iterable of Segment objects with start, end, text, avg_logprob
181
+ :return: ASRResult
182
+ """
183
+ transcription = []
184
+ weighted_logprob = 0.0
185
+ total_duration = 0.0
186
+ for segment in segments:
187
+ duration = segment.end - segment.start
188
+ transcription.append((segment.start, segment.end, segment.text))
189
+ weighted_logprob += segment.avg_logprob * duration
190
+ total_duration += duration
191
+ score = math.exp(weighted_logprob / total_duration) if total_duration else -1.0
192
+ return cls(transcription=transcription, score=score, **extra)
193
+
194
+ def __add__(self, other: Self) -> Self:
195
+ if not isinstance(other, ASRResult):
196
+ msg = f"expected {ASRResult.__class__.__class__} but found: {type(other)}"
197
+ raise TypeError(msg)
198
+
199
+ if other.input_ordering != self.input_ordering:
200
+ raise ValueError("can't merge transcriptions from different inputs")
201
+
202
+ transcription = self.transcription + other.transcription
203
+ # We have to weight by total segment len
204
+ total_duration = self.duration + other.duration
205
+ score = 1.0
206
+ if total_duration:
207
+ score = self.score * self.duration + other.score * other.duration
208
+ score /= total_duration
209
+ return ASRResult(
210
+ input_ordering=self.input_ordering, transcription=transcription, score=score
211
+ )
212
+
213
+
214
+ def _utc_now() -> datetime.datetime:
215
+ return datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0)
216
+
217
+
218
+ def _uuid() -> str:
219
+ return uuid.uuid4().hex
220
+
221
+
222
+ class InputMetadata(BaseModel):
223
+ """Preprocessed input metadata"""
224
+
225
+ duration_s: float
226
+ input_ordering: int = -1
227
+ preprocessed_at: datetime.datetime = Field(default_factory=_utc_now)
228
+ uuid: str = Field(default_factory=_uuid)
229
+ input_format: str | None = None
230
+ input_file_path: Path | None = None
231
+ preprocessed_file_path: Path | None = None
232
+
233
+
234
+ class PreprocessedInput(BaseModel):
235
+ metadata: InputMetadata
236
+
237
+
238
+ @dataclass(frozen=True)
239
+ class PreprocessedInputWithTensor:
240
+ # Avoid importing torch when importing objects
241
+
242
+ metadata: InputMetadata
243
+ tensor: "torch.Tensor | list | None" = None
244
+
245
+
246
+ PreprocessorOutput = PreprocessedInput | PreprocessedInputWithTensor
@@ -0,0 +1,30 @@
1
+ [project]
2
+ name = "caul-core"
3
+ dynamic = ["version"]
4
+ description = "core objects for caul ASR"
5
+ authors = [
6
+ {name = "Lion Summerbell", email = "lsummerbell@icij.org"}
7
+ ]
8
+ readme = "README.md"
9
+ requires-python = ">=3.11.0, <3.14.0"
10
+ dependencies = [
11
+ "icij-common~=0.8.1",
12
+ "pydantic-extra-types[pycountry]~=2.11",
13
+ ]
14
+
15
+ [tool.uv]
16
+ package = true
17
+
18
+ [build-system]
19
+ requires = ["hatchling", "uv-dynamic-versioning"]
20
+ build-backend = "hatchling.build"
21
+
22
+ [tool.hatch.version]
23
+ source = "uv-dynamic-versioning"
24
+
25
+ [tool.hatch.build.targets.wheel]
26
+ packages = ["caul_core"]
27
+
28
+ [tool.uv-dynamic-versioning]
29
+ fallback-version = "0.0.0"
30
+ pattern-prefix = "caul-core-"
@@ -0,0 +1,211 @@
1
+ version = 1
2
+ revision = 3
3
+ requires-python = ">=3.11.0, <3.14.0"
4
+
5
+ [[package]]
6
+ name = "aiostream"
7
+ version = "0.7.1"
8
+ source = { registry = "https://pypi.org/simple" }
9
+ dependencies = [
10
+ { name = "typing-extensions" },
11
+ ]
12
+ sdist = { url = "https://files.pythonhosted.org/packages/8b/65/b9b69695702b76a878c9879f2ee80cefce75bc5cb864fc100460bc1c5380/aiostream-0.7.1.tar.gz", hash = "sha256:272aaa0d8f83beb906f5aa9022bb59046bb7a103fa3770f807c31f918595acf6", size = 44059, upload-time = "2025-10-13T20:02:06.961Z" }
13
+ wheels = [
14
+ { url = "https://files.pythonhosted.org/packages/52/a0/d7c6ca304140f3f49987d710e15bc164248924a35d8cdfac2f6e87fca041/aiostream-0.7.1-py3-none-any.whl", hash = "sha256:ea8739e9158ee6a606b3feedf3762721c3507344e540d09a10984c5e88a13b37", size = 41416, upload-time = "2025-10-13T20:02:05.535Z" },
15
+ ]
16
+
17
+ [[package]]
18
+ name = "annotated-types"
19
+ version = "0.7.0"
20
+ source = { registry = "https://pypi.org/simple" }
21
+ sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" }
22
+ wheels = [
23
+ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
24
+ ]
25
+
26
+ [[package]]
27
+ name = "caul-core"
28
+ version = "0.1.0"
29
+ source = { virtual = "." }
30
+ dependencies = [
31
+ { name = "icij-common" },
32
+ { name = "pydantic-extra-types", extra = ["pycountry"] },
33
+ ]
34
+
35
+ [package.metadata]
36
+ requires-dist = [
37
+ { name = "icij-common", specifier = "~=0.8.1" },
38
+ { name = "pydantic-extra-types", extras = ["pycountry"], specifier = "~=2.11" },
39
+ ]
40
+
41
+ [[package]]
42
+ name = "icij-common"
43
+ version = "0.8.2"
44
+ source = { registry = "https://pypi.org/simple" }
45
+ dependencies = [
46
+ { name = "aiostream" },
47
+ { name = "pydantic" },
48
+ { name = "pydantic-settings" },
49
+ ]
50
+ sdist = { url = "https://files.pythonhosted.org/packages/e0/51/91d85cc23e275bb51a5cae47873af9a7160f62797b25663d902cf38e6ab7/icij_common-0.8.2.tar.gz", hash = "sha256:7db68266d8facb43142131d81e998cd74c6ae73508456743e00df43a15cc2995", size = 15937, upload-time = "2026-04-07T12:13:39.774Z" }
51
+ wheels = [
52
+ { url = "https://files.pythonhosted.org/packages/15/5a/99d123230023124ba4ec67765feb2a04b656ae1f473a14f6b29cc54b02bf/icij_common-0.8.2-py3-none-any.whl", hash = "sha256:c5a1a3ccd54e7bf53acad293a0af50ab15156b225791b43383197b896bae955f", size = 20565, upload-time = "2026-04-07T12:13:38.709Z" },
53
+ ]
54
+
55
+ [[package]]
56
+ name = "pycountry"
57
+ version = "26.2.16"
58
+ source = { registry = "https://pypi.org/simple" }
59
+ sdist = { url = "https://files.pythonhosted.org/packages/de/1d/061b9e7a48b85cfd69f33c33d2ef784a531c359399ad764243399673c8f5/pycountry-26.2.16.tar.gz", hash = "sha256:5b6027d453fcd6060112b951dd010f01f168b51b4bf8a1f1fc8c95c8d94a0801", size = 7711342, upload-time = "2026-02-17T03:42:52.367Z" }
60
+ wheels = [
61
+ { url = "https://files.pythonhosted.org/packages/9c/42/7703bd45b62fecd44cd7d3495423097e2f7d28bc2e99e7c1af68892ab157/pycountry-26.2.16-py3-none-any.whl", hash = "sha256:115c4baf7cceaa30f59a4694d79483c9167dbce7a9de4d3d571c5f3ea77c305a", size = 8044600, upload-time = "2026-02-17T03:42:49.777Z" },
62
+ ]
63
+
64
+ [[package]]
65
+ name = "pydantic"
66
+ version = "2.13.4"
67
+ source = { registry = "https://pypi.org/simple" }
68
+ dependencies = [
69
+ { name = "annotated-types" },
70
+ { name = "pydantic-core" },
71
+ { name = "typing-extensions" },
72
+ { name = "typing-inspection" },
73
+ ]
74
+ sdist = { url = "https://files.pythonhosted.org/packages/18/a5/b60d21ac674192f8ab0ba4e9fd860690f9b4a6e51ca5df118733b487d8d6/pydantic-2.13.4.tar.gz", hash = "sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6", size = 844775, upload-time = "2026-05-06T13:43:05.343Z" }
75
+ wheels = [
76
+ { url = "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl", hash = "sha256:45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba", size = 472262, upload-time = "2026-05-06T13:43:02.641Z" },
77
+ ]
78
+
79
+ [[package]]
80
+ name = "pydantic-core"
81
+ version = "2.46.4"
82
+ source = { registry = "https://pypi.org/simple" }
83
+ dependencies = [
84
+ { name = "typing-extensions" },
85
+ ]
86
+ sdist = { url = "https://files.pythonhosted.org/packages/9d/56/921726b776ace8d8f5db44c4ef961006580d91dc52b803c489fafd1aa249/pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1", size = 471464, upload-time = "2026-05-06T13:37:06.98Z" }
87
+ wheels = [
88
+ { url = "https://files.pythonhosted.org/packages/5c/fa/6d7708d2cfc1a832acb6aeb0cd16e801902df8a0f583bb3b4b527fde022e/pydantic_core-2.46.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0e96592440881c74a213e5ad528e2b24d3d4f940de2766bed9010ab1d9e51594", size = 2111872, upload-time = "2026-05-06T13:40:27.596Z" },
89
+ { url = "https://files.pythonhosted.org/packages/ae/6f/aa064a3e74b5745afbdf250594f38e7ead05e2d651bcb35994b9417a0d4d/pydantic_core-2.46.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0d65b8c354be7fb5f720c3caa8bc940bc2d20ce749c8e06135f07f8ed95dd7c", size = 1948255, upload-time = "2026-05-06T13:39:12.574Z" },
90
+ { url = "https://files.pythonhosted.org/packages/43/3a/41114a9f7569b84b4d84e7a018c57c56347dac30c0d4a872946ec4e36c46/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bfb192b3f4b9e8a89b6277b6ce787564f62cfd272055f6e685726b111dc7826", size = 1972827, upload-time = "2026-05-06T13:38:19.841Z" },
91
+ { url = "https://files.pythonhosted.org/packages/ef/25/1ab42e8048fe551934d9884e8d64daa7e990ad386f310a15981aeb6a5b08/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9037063db01f09b09e237c282b6792bd4da634b5402c4e7f0c61effed7701a04", size = 2041051, upload-time = "2026-05-06T13:38:10.447Z" },
92
+ { url = "https://files.pythonhosted.org/packages/94/c2/1a934597ddf08da410385b3b7aae91956a5a76c635effef456074fad7e88/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc010ab034c8c7452522748bf937df58020d256ccae0874463d1f4d01758af8e", size = 2221314, upload-time = "2026-05-06T13:40:13.089Z" },
93
+ { url = "https://files.pythonhosted.org/packages/02/6d/9e8ad178c9c4df27ad3c8f25d1fe2a7ab0d2ba0559fad4aee5d3d1f16771/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c5dac79fa1614d1e06ca695109c6105923bd9c7d1d6c918d4e637b7e6b32fd3", size = 2285146, upload-time = "2026-05-06T13:38:59.224Z" },
94
+ { url = "https://files.pythonhosted.org/packages/80/50/540cd3aeefc041beb111125c4bff779831a2111fc6b15a9138cda277d32c/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9fa868638bf362d3d138ea55829cefb3d5f4b0d7f142234382a15e2485dbec4", size = 2089685, upload-time = "2026-05-06T13:38:17.762Z" },
95
+ { url = "https://files.pythonhosted.org/packages/6b/a4/b440ad35f05f6a38f89fa0f149accb3f0e02be94ca5e15f3c449a61b4bc9/pydantic_core-2.46.4-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:17299feefe090f2caa5b8e37222bb5f663e4935a8bfa6931d4102e5df1a9f398", size = 2115420, upload-time = "2026-05-06T13:37:58.195Z" },
96
+ { url = "https://files.pythonhosted.org/packages/99/61/de4f55db8dfd57bfdfa9a12ec90fe1b57c4f41062f7ca86f08586b3e0ac0/pydantic_core-2.46.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4c63ebc82684aa89d9a3bcbd13d515b3be44250dc68dd3bd81526c1cb31286c3", size = 2165122, upload-time = "2026-05-06T13:37:01.167Z" },
97
+ { url = "https://files.pythonhosted.org/packages/f7/52/7c529d7bdb2d1068bd52f51fe32572c8301f9a4febf1948f10639f1436f5/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:aaa2a54443eff1950ba5ddc6b6ccda0d9c84a364276a62f969bdf2a390650848", size = 2182573, upload-time = "2026-05-06T13:38:45.04Z" },
98
+ { url = "https://files.pythonhosted.org/packages/37/b3/7c40325848ba78247f2812dcf9c7274e38cd801820ca6dd9fe63bcfb0eb4/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:18e5ceec2ab67e6d5f1a9085e5a24c9c4e2ac4545730bfe668680bca05e555f3", size = 2317139, upload-time = "2026-05-06T13:37:15.539Z" },
99
+ { url = "https://files.pythonhosted.org/packages/d9/37/f913f81a657c865b75da6c0dbed79876073c2a43b5bd9edbe8da785e4d49/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a0f62d0a58f4e7da165457e995725421e0064f2255d8eccebc49f41bbc23b109", size = 2360433, upload-time = "2026-05-06T13:37:30.099Z" },
100
+ { url = "https://files.pythonhosted.org/packages/c4/67/6acaa1be2567f9256b056d8477158cac7240813956ce86e49deae8e173b4/pydantic_core-2.46.4-cp311-cp311-win32.whl", hash = "sha256:041bde0a48fd37cf71cab1c9d56d3e8625a3793fef1f7dd232b3ff37e978ecda", size = 1985513, upload-time = "2026-05-06T13:38:15.669Z" },
101
+ { url = "https://files.pythonhosted.org/packages/aa/e6/c505f83dfeda9a2e5c995cfd872949e4d05e12f7feb3dca72f633daefa94/pydantic_core-2.46.4-cp311-cp311-win_amd64.whl", hash = "sha256:6f2eeda33a839975441c86a4119e1383c50b47faf0cbb5176985565c6bb02c33", size = 2071114, upload-time = "2026-05-06T13:40:35.416Z" },
102
+ { url = "https://files.pythonhosted.org/packages/0f/da/7a263a96d965d9d0df5e8de8a475f33495451117035b09acb110288c381f/pydantic_core-2.46.4-cp311-cp311-win_arm64.whl", hash = "sha256:14f4c5d6db102bd796a627bbb3a17b4cf4574b9ae861d8b7c9a9661c6dd3362d", size = 2044298, upload-time = "2026-05-06T13:38:29.754Z" },
103
+ { url = "https://files.pythonhosted.org/packages/ce/8c/af022f0af448d7747c5154288d46b5f2bc5f17366eaa0e23e9aa04d59f3b/pydantic_core-2.46.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3245406455a5d98187ec35530fd772b1d799b26667980872c8d4614991e2c4a2", size = 2106158, upload-time = "2026-05-06T13:38:57.215Z" },
104
+ { url = "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:962ccbab7b642487b1d8b7df90ef677e03134cf1fd8880bf698649b22a69371f", size = 1951724, upload-time = "2026-05-06T13:37:02.697Z" },
105
+ { url = "https://files.pythonhosted.org/packages/8e/bc/f47d1ff9cbb1620e1b5b697eef06010035735f07820180e74178226b27b3/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8233f2947cf85404441fd7e0085f53b10c93e0ee78611099b5c7237e36aacbf7", size = 1975742, upload-time = "2026-05-06T13:37:09.448Z" },
106
+ { url = "https://files.pythonhosted.org/packages/5b/11/9b9a5b0306345664a2da6410877af6e8082481b5884b3ddd78d47c6013ce/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a233125ac121aa3ffba9a2b59edfc4a985a76092dc8279586ab4b71390875e7", size = 2052418, upload-time = "2026-05-06T13:37:38.234Z" },
107
+ { url = "https://files.pythonhosted.org/packages/f1/b7/a65fec226f5d78fc39f4a13c4cc0c768c22b113438f60c14adc9d2865038/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b712b53160b79a5850310b912a5ef8e57e56947c8ad690c227f5c9d7e561712", size = 2232274, upload-time = "2026-05-06T13:38:27.753Z" },
108
+ { url = "https://files.pythonhosted.org/packages/68/f0/92039db98b907ef49269a8271f67db9cb78ae2fc68062ef7e4e77adb5f61/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9401557acd873c3a7f3eb9383edef8ac4968f9510e340f4808d427e75667e7b4", size = 2309940, upload-time = "2026-05-06T13:38:05.353Z" },
109
+ { url = "https://files.pythonhosted.org/packages/5f/97/2aab507d3d00ca626e8e57c1eac6a79e4e5fbcc63eb99733ff55d1717f65/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:926c9541b14b12b1681dca8a0b75feb510b06c6341b70a8e500c2fdcff837cce", size = 2094516, upload-time = "2026-05-06T13:39:10.577Z" },
110
+ { url = "https://files.pythonhosted.org/packages/22/37/a8aca44d40d737dde2bc05b3c6c07dff0de07ce6f82e9f3167aeaf4d5dea/pydantic_core-2.46.4-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:56cb4851bcaf3d117eddcef4fe66afd750a50274b0da8e22be256d10e5611987", size = 2136854, upload-time = "2026-05-06T13:40:22.59Z" },
111
+ { url = "https://files.pythonhosted.org/packages/24/99/fcef1b79238c06a8cbec70819ac722ba76e02bc8ada9b0fd66eba40da01b/pydantic_core-2.46.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c68fcd102d71ea85c5b2dfac3f4f8476eff42a9e078fd5faefff6d145063536b", size = 2180306, upload-time = "2026-05-06T13:40:10.666Z" },
112
+ { url = "https://files.pythonhosted.org/packages/ae/6c/fc44000918855b42779d007ae63b0532794739027b2f417321cddbc44f6a/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b2f69dec1725e79a012d920df1707de5caf7ed5e08f3be4435e25803efc47458", size = 2190044, upload-time = "2026-05-06T13:40:43.231Z" },
113
+ { url = "https://files.pythonhosted.org/packages/6b/65/d9cadc9f1920d7a127ad2edba16c1db7916e59719285cd6c94600b0080ba/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:8d0820e8192167f80d88d64038e609c31452eeca865b4e1d9950a27a4609b00b", size = 2329133, upload-time = "2026-05-06T13:39:57.365Z" },
114
+ { url = "https://files.pythonhosted.org/packages/d0/cf/c873d91679f3a30bcf5e7ac280ce5573483e72295307685120d0d5ad3416/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fbdb89b3e1c94a30cc5edfce477c6e6a5dc4d8f84665b455c27582f211a1c72c", size = 2374464, upload-time = "2026-05-06T13:38:06.976Z" },
115
+ { url = "https://files.pythonhosted.org/packages/47/bd/6f2fc8188f31bf10590f1e98e7b306336161fac930a8c514cd7bd828c7dc/pydantic_core-2.46.4-cp312-cp312-win32.whl", hash = "sha256:9aa768456404a8bf48a4406685ac2bec8e72b62c69313734fa3b73cf33b3a894", size = 1974823, upload-time = "2026-05-06T13:40:47.985Z" },
116
+ { url = "https://files.pythonhosted.org/packages/40/8c/985c1d41ea1107c2534abd9870e4ed5c8e7669b5c308297835c001e7a1c4/pydantic_core-2.46.4-cp312-cp312-win_amd64.whl", hash = "sha256:e9c26f834c65f5752f3f06cb08cb86a913ceb7274d0db6e267808a708b46bc89", size = 2072919, upload-time = "2026-05-06T13:39:21.153Z" },
117
+ { url = "https://files.pythonhosted.org/packages/c4/ba/f463d006e0c47373ca7ec5e1a261c59dc01ef4d62b2657af925fb0deee3a/pydantic_core-2.46.4-cp312-cp312-win_arm64.whl", hash = "sha256:4fc73cb559bdb54b1134a706a2802a4cddd27a0633f5abb7e53056268751ac6a", size = 2027604, upload-time = "2026-05-06T13:39:03.753Z" },
118
+ { url = "https://files.pythonhosted.org/packages/51/a2/5d30b469c5267a17b39dec53208222f76a8d351dfac4af661888c5aee77d/pydantic_core-2.46.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5d5902252db0d3cedf8d4a1bc68f70eeb430f7e4c7104c8c476753519b423008", size = 2106306, upload-time = "2026-05-06T13:37:48.029Z" },
119
+ { url = "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c94f0688e7b8d0a67abf40e57a7eaaecd17cc9586706a31b76c031f63df052b4", size = 1951906, upload-time = "2026-05-06T13:37:17.012Z" },
120
+ { url = "https://files.pythonhosted.org/packages/03/d5/fd02da45b659668b05923b17ba3a0100a0a3d5541e3bd8fcc4ecb711309e/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f027324c56cd5406ca49c124b0db10e56c69064fec039acc571c29020cc87c76", size = 1976802, upload-time = "2026-05-06T13:37:35.113Z" },
121
+ { url = "https://files.pythonhosted.org/packages/21/f2/95727e1368be3d3ed485eaab7adbd7dda408f33f7a36e8b48e0144002b91/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e739fee756ba1010f8bcccb534252e85a35fe45ae92c295a06059ce58b74ccd3", size = 2052446, upload-time = "2026-05-06T13:37:12.313Z" },
122
+ { url = "https://files.pythonhosted.org/packages/9c/86/5d99feea3f77c7234b8718075b23db11532773c1a0dbd9b9490215dc2eeb/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d56801be94b86a9da183e5f3766e6310752b99ff647e38b09a9500d88e46e76", size = 2232757, upload-time = "2026-05-06T13:39:01.149Z" },
123
+ { url = "https://files.pythonhosted.org/packages/d2/3a/508ac615935ef7588cf6d9e9b91309fdc2da751af865e02a9098de88258c/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2412e734dcb48da14d4e4006b82b46b74f2518b8a26ee7e58c6844a6cd6d03c4", size = 2309275, upload-time = "2026-05-06T13:37:41.406Z" },
124
+ { url = "https://files.pythonhosted.org/packages/07/f8/41db9de19d7987d6b04715a02b3b40aea467000275d9d758ffaa31af7d50/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9551187363ffc0de2a00b2e47c25aeaeb1020b69b668762966df15fc5659dd5a", size = 2094467, upload-time = "2026-05-06T13:39:18.847Z" },
125
+ { url = "https://files.pythonhosted.org/packages/2c/e2/f35033184cb11d0052daf4416e8e10a502ea2ac006fc4f459aee872727d1/pydantic_core-2.46.4-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0186750b482eefa11d7f435892b09c5c606193ef3375bcf94aa00ae6bfb66262", size = 2134417, upload-time = "2026-05-06T13:40:17.944Z" },
126
+ { url = "https://files.pythonhosted.org/packages/7e/7b/6ceeb1cc90e193862f444ebe373d8fdf613f0a82572dde03fb10734c6c71/pydantic_core-2.46.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5855698a4856556d86e8e6cd8434bc3ac0314ee8e12089ae0e143f64c6256e4e", size = 2179782, upload-time = "2026-05-06T13:40:32.618Z" },
127
+ { url = "https://files.pythonhosted.org/packages/5a/f2/c8d7773ede6af08036423a00ae0ceffce266c3c52a096c435d68c896083f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cbaf13819775b7f769bf4a1f066cb6df7a28d4480081a589828ef190226881cd", size = 2188782, upload-time = "2026-05-06T13:36:51.018Z" },
128
+ { url = "https://files.pythonhosted.org/packages/59/31/0c864784e31f09f05cdd87606f08923b9c9e7f6e51dd27f20f62f975ce9f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:633147d34cf4550417f12e2b1a0383973bdf5cdfde212cb09e9a581cf10820be", size = 2328334, upload-time = "2026-05-06T13:40:37.764Z" },
129
+ { url = "https://files.pythonhosted.org/packages/c2/eb/4f6c8a41efa30baa755590f4141abf3a8c370fab610915733e74134a7270/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:82cf5301172168103724d49a1444d3378cb20cdee30b116a1bd6031236298a5d", size = 2372986, upload-time = "2026-05-06T13:39:34.152Z" },
130
+ { url = "https://files.pythonhosted.org/packages/5b/24/b375a480d53113860c299764bfe9f349a3dc9108b3adc0d7f0d786492ebf/pydantic_core-2.46.4-cp313-cp313-win32.whl", hash = "sha256:9fa8ae11da9e2b3126c6426f147e0fba88d96d65921799bb30c6abd1cb2c97fb", size = 1973693, upload-time = "2026-05-06T13:37:55.072Z" },
131
+ { url = "https://files.pythonhosted.org/packages/7e/e8/cff247591966f2d22ec8c003cd7587e27b7ba7b81ab2fb888e3ab75dc285/pydantic_core-2.46.4-cp313-cp313-win_amd64.whl", hash = "sha256:6b3ace8194b0e5204818c92802dcdca7fc6d88aabbb799d7c795540d9cd6d292", size = 2071819, upload-time = "2026-05-06T13:38:49.139Z" },
132
+ { url = "https://files.pythonhosted.org/packages/c6/1a/f4aee670d5670e9e148e0c82c7db98d780be566c6e6a97ee8035528ca0b3/pydantic_core-2.46.4-cp313-cp313-win_arm64.whl", hash = "sha256:184c081504d17f1c1066e430e117142b2c77d9448a97f7b65c6ac9fd9aee238d", size = 2027411, upload-time = "2026-05-06T13:40:45.796Z" },
133
+ { url = "https://files.pythonhosted.org/packages/ee/a4/73995fd4ebbb46ba0ee51e6fa049b8f02c40daebb762208feda8a6b7894d/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:14d4edf427bdcf950a8a02d7cb44a08614388dd6e1bdcbf4f67504fa7887da9c", size = 2111589, upload-time = "2026-05-06T13:37:10.817Z" },
134
+ { url = "https://files.pythonhosted.org/packages/fb/7f/f37d3a5e8bfcc2e403f5c57a730f2d815693fb42119e8ea48b3789335af1/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:0ce40cd7b21210e99342afafbd4d0f76d784eb5b1d60f3bdc566be4983c6c73b", size = 1944552, upload-time = "2026-05-06T13:36:56.717Z" },
135
+ { url = "https://files.pythonhosted.org/packages/15/3c/d7eb777b3ff43e8433a4efb39a17aa8fd98a4ee8561a24a67ef5db07b2d6/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90884113d8b48f760e9587002789ddd741e76ab9f89518cd1e43b1f1a52ec44b", size = 1982984, upload-time = "2026-05-06T13:39:06.207Z" },
136
+ { url = "https://files.pythonhosted.org/packages/63/87/70b9f40170a81afd55ca26c9b2acb25c20d64bcfbf888fafecb3ba077d4c/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66ce7632c22d837c95301830e111ad0128a32b8207533b60896a96c4915192ea", size = 2138417, upload-time = "2026-05-06T13:39:45.476Z" },
137
+ { url = "https://files.pythonhosted.org/packages/9d/1d/8987ad40f65ae1432753072f214fb5c74fe47ffbd0698bb9cbbb585664f8/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:1d8ba486450b14f3b1d63bc521d410ec7565e52f887b9fb671791886436a42f7", size = 2095527, upload-time = "2026-05-06T13:39:52.283Z" },
138
+ { url = "https://files.pythonhosted.org/packages/64/d3/84c282a7eee1d3ac4c0377546ef5a1ea436ce26840d9ac3b7ed54a377507/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:3009f12e4e90b7f88b4f9adb1b0c4a3d58fe7820f3238c190047209d148026df", size = 1936024, upload-time = "2026-05-06T13:40:15.671Z" },
139
+ { url = "https://files.pythonhosted.org/packages/d7/ca/eac61596cdeb4d7e174d3dc0bd8a6238f14f75f97a24e7b7db4c7e7340a0/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad785e92e6dc634c21555edc8bd6b64957ab844541bcb96a1366c202951ae526", size = 1990696, upload-time = "2026-05-06T13:38:34.717Z" },
140
+ { url = "https://files.pythonhosted.org/packages/fa/c3/7c8b240552251faf6b3a957db200fcfbbcec36763c050428b601e0c9b83b/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00c603d540afdd6b80eb39f078f33ebd46211f02f33e34a32d9f053bba711de0", size = 2147590, upload-time = "2026-05-06T13:39:29.883Z" },
141
+ { url = "https://files.pythonhosted.org/packages/11/cb/428de0385b6c8d44b716feba566abfacfbd23ee3c4439faa789a1456242f/pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0c563b08bca408dc7f65f700633d8442fffb2421fc47b8101377e9fd65051ff0", size = 2112782, upload-time = "2026-05-06T13:37:04.016Z" },
142
+ { url = "https://files.pythonhosted.org/packages/0b/b5/6a17bdadd0fc1f170adfd05a20d37c832f52b117b4d9131da1f41bb097ce/pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:db06ffe51636ffe9ca531fe9023dd64bdd794be8754cb5df57c5498ae5b518a7", size = 1952146, upload-time = "2026-05-06T13:39:43.092Z" },
143
+ { url = "https://files.pythonhosted.org/packages/2a/dc/03734d80e362cd43ef65428e9de77c730ce7f2f11c60d2b1e1b39f0fbf99/pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:133878133d271ade3d41d1bfb2a45ec38dbdbda40bc065921c6b04e4630127e2", size = 2134492, upload-time = "2026-05-06T13:36:58.124Z" },
144
+ { url = "https://files.pythonhosted.org/packages/de/df/5e5ffc085ed07cc22d298134d3d911c63e91f6a0eb91fe646750a3209910/pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9bc519fbf2b7578398853d815009ae5e4d4603d12f4e3f91da8c06852d3da3e9", size = 2156604, upload-time = "2026-05-06T13:37:49.88Z" },
145
+ { url = "https://files.pythonhosted.org/packages/81/44/6e112a4253e56f5705467cbab7ab5e91ee7398ba3d56d358635958893d3e/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c7a7bd4e39e8e4c12c39cd480356842b6a8a06e41b23a55a5e3e191718838ddf", size = 2183828, upload-time = "2026-05-06T13:37:43.053Z" },
146
+ { url = "https://files.pythonhosted.org/packages/ac/ad/5565071e937d8e752842ac241463944c9eb14c87e2d269f2658a5bd05e98/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:d396ec2b979760aaf3218e76c24e65bd0aca24983298653b3a9d7a45f9e47b30", size = 2310000, upload-time = "2026-05-06T13:37:56.694Z" },
147
+ { url = "https://files.pythonhosted.org/packages/4f/c3/66883a5cec183e7fba4d024b4cbbe61851a63750ef606b0afecc46d1f2bf/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:86e1a4418c6cd97d60c95c71164158eaf7324fae7b0923264016baa993eba6fc", size = 2361286, upload-time = "2026-05-06T13:40:05.667Z" },
148
+ { url = "https://files.pythonhosted.org/packages/4b/2d/69abac8f838090bbecd5df894befb2c2619e7996a98ddb949db9f3b93225/pydantic_core-2.46.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:d51026d73fcfd93610abc7b27789c26b313920fcfb20e27462d74a7f8b06e983", size = 2193071, upload-time = "2026-05-06T13:38:08.682Z" },
149
+ ]
150
+
151
+ [[package]]
152
+ name = "pydantic-extra-types"
153
+ version = "2.11.1"
154
+ source = { registry = "https://pypi.org/simple" }
155
+ dependencies = [
156
+ { name = "pydantic" },
157
+ { name = "typing-extensions" },
158
+ ]
159
+ sdist = { url = "https://files.pythonhosted.org/packages/66/71/dba38ee2651f84f7842206adbd2233d8bbdb59fb85e9fa14232486a8c471/pydantic_extra_types-2.11.1.tar.gz", hash = "sha256:46792d2307383859e923d8fcefa82108b1a141f8a9c0198982b3832ab5ef1049", size = 172002, upload-time = "2026-03-16T08:08:03.92Z" }
160
+ wheels = [
161
+ { url = "https://files.pythonhosted.org/packages/17/c1/3226e6d7f5a4f736f38ac11a6fbb262d701889802595cdb0f53a885ac2e0/pydantic_extra_types-2.11.1-py3-none-any.whl", hash = "sha256:1722ea2bddae5628ace25f2aa685b69978ef533123e5638cfbddb999e0100ec1", size = 79526, upload-time = "2026-03-16T08:08:02.533Z" },
162
+ ]
163
+
164
+ [package.optional-dependencies]
165
+ pycountry = [
166
+ { name = "pycountry" },
167
+ ]
168
+
169
+ [[package]]
170
+ name = "pydantic-settings"
171
+ version = "2.14.1"
172
+ source = { registry = "https://pypi.org/simple" }
173
+ dependencies = [
174
+ { name = "pydantic" },
175
+ { name = "python-dotenv" },
176
+ { name = "typing-inspection" },
177
+ ]
178
+ sdist = { url = "https://files.pythonhosted.org/packages/07/60/1d1e59c9c90d54591469ada7d268251f71c24bdb765f1a8a832cee8c6653/pydantic_settings-2.14.1.tar.gz", hash = "sha256:e874d3bec7e787b0c9958277956ed9b4dd5de6a80e162188fdaff7c5e26fd5fa", size = 235551, upload-time = "2026-05-08T13:40:06.542Z" }
179
+ wheels = [
180
+ { url = "https://files.pythonhosted.org/packages/ae/8d/f1af3832f5e6eb13ba94ee809e72b8ecb5eef226d27ee0bef7d963d943c7/pydantic_settings-2.14.1-py3-none-any.whl", hash = "sha256:6e3c7edfd8277687cdc598f56e5cff0e9bfff0910a3749deaa8d4401c3a2b9de", size = 60964, upload-time = "2026-05-08T13:40:04.958Z" },
181
+ ]
182
+
183
+ [[package]]
184
+ name = "python-dotenv"
185
+ version = "1.2.2"
186
+ source = { registry = "https://pypi.org/simple" }
187
+ sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" }
188
+ wheels = [
189
+ { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" },
190
+ ]
191
+
192
+ [[package]]
193
+ name = "typing-extensions"
194
+ version = "4.15.0"
195
+ source = { registry = "https://pypi.org/simple" }
196
+ sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
197
+ wheels = [
198
+ { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
199
+ ]
200
+
201
+ [[package]]
202
+ name = "typing-inspection"
203
+ version = "0.4.2"
204
+ source = { registry = "https://pypi.org/simple" }
205
+ dependencies = [
206
+ { name = "typing-extensions" },
207
+ ]
208
+ sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" }
209
+ wheels = [
210
+ { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" },
211
+ ]