mac-speech-analyzer 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,33 @@
1
+ name: "Publish release to PyPI"
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ # Publish on any tag starting with a `v`, e.g., v0.1.0
7
+ - v*
8
+
9
+ jobs:
10
+ build:
11
+ runs-on: macos-26
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ - uses: astral-sh/setup-uv@v5
15
+ - uses: maxim-lobanov/setup-xcode@v1
16
+ with:
17
+ xcode-version: latest-stable
18
+ - run: uv build
19
+ - uses: actions/upload-artifact@v4
20
+ with:
21
+ name: dist
22
+ path: dist/
23
+ publish:
24
+ needs: build
25
+ runs-on: ubuntu-latest
26
+ environment: pypi
27
+ permissions:
28
+ id-token: write
29
+ steps:
30
+ - uses: actions/download-artifact@v4
31
+ with: { name: dist, path: dist/ }
32
+ - uses: astral-sh/setup-uv@v7
33
+ - run: uv publish
@@ -0,0 +1 @@
1
+ 3.14
@@ -0,0 +1,19 @@
1
+ cmake_minimum_required(VERSION 3.26)
2
+ project(macspeechanalyzer LANGUAGES Swift)
3
+
4
+ add_library(macspeechanalyzer_core SHARED
5
+ swift/core.swift
6
+ swift/bridge.swift)
7
+
8
+ # Editable/inplace: no install step runs, so aim the linker output
9
+ # directly at the package. $<0:> keeps multi-config generators happy.
10
+ if(SKBUILD_STATE STREQUAL "editable")
11
+ set_target_properties(macspeechanalyzer_core PROPERTIES
12
+ LIBRARY_OUTPUT_DIRECTORY
13
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/macspeechanalyzer/$<0:>")
14
+ endif()
15
+
16
+ # Wheel builds: install step runs, destination is relative to the wheel root
17
+ install(TARGETS macspeechanalyzer_core
18
+ LIBRARY DESTINATION macspeechanalyzer
19
+ RUNTIME DESTINATION macspeechanalyzer)
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 paraversal
4
+ Copyright (c) 2025 Argmax, Inc.
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
@@ -0,0 +1,82 @@
1
+ Metadata-Version: 2.4
2
+ Name: mac-speech-analyzer
3
+ Version: 0.1.0
4
+ Summary: On-device speech transcription for macOS via Apple's SpeechAnalyzer
5
+ License-Expression: MIT
6
+ Classifier: Operating System :: MacOS
7
+ Classifier: Programming Language :: Python :: 3
8
+ Requires-Python: >=3.10
9
+ Description-Content-Type: text/markdown
10
+
11
+ # mac-speech-analyzer
12
+
13
+ 🐍 Python package to run the macOS 26 SpeechAnalyzer API from Python to transcribe audio files.
14
+
15
+ The SpeechAnalyzer API generally provides [faster and better results]((https://get-inscribe.com/blog/apple-speech-api-benchmark.html)) than other locally running transcription engines of comparable size.
16
+
17
+ ## Features
18
+
19
+ - **Online** or **Offline** transcription
20
+ - Automatic download of new languages
21
+
22
+ ## Requirements
23
+
24
+ - macOS >= 26.0
25
+ - XCode command-line tools
26
+
27
+ ## Installation
28
+
29
+ mac-speech-analyzer is currently not tracked on pypi yet.
30
+
31
+ ```bash
32
+ uv add git+https://github.com/paraversal/mac-speech-analyzer
33
+ # or
34
+ pip install git+https://github.com/paraversal/mac-speech-analyzer
35
+ ```
36
+
37
+ ## Usage
38
+
39
+ ### Basic usage
40
+
41
+ ```py
42
+ from macspeechanalyzer import transcribe
43
+
44
+ text = transcribe("/path/to/file", locale = "en_US")
45
+ ```
46
+
47
+ ## Technical details
48
+
49
+ This package is made up of two parts: the Python wrapper provides the API, but the actual functionality is achieved by embedding a Swift project which exposes functions to C. With this kind of three language interplay, a clean separation of concerns is really important. Therefore, the implementation is divided into the following four layers:
50
+
51
+ - Pure Python
52
+ - Python → C compat
53
+ - Swift → C compat
54
+ - Pure Swift
55
+
56
+ The pure Swift and pure Python layers only deal with their respective languages & types, while the compat layers do all the ugly work of converting between native and C-compatible types
57
+
58
+ ## Roadmap
59
+
60
+ - ✅ Basic one-shot transcription
61
+ - Class-based interface
62
+ - Context manager implementation
63
+ - Transcription of live audio stream (microphone, ...)
64
+
65
+
66
+ ## Development
67
+
68
+ ```zsh
69
+ uv pip install -e .
70
+ ```
71
+
72
+ to one-time-install the package as editable, from then on:
73
+
74
+ ```zsh
75
+ ninja
76
+ ```
77
+
78
+ to rebuild the package
79
+
80
+ # License
81
+
82
+ mac-speech-analyzer is released under the MIT License. See [LICENSE](./LICENSE) for more details.
@@ -0,0 +1,19 @@
1
+ import PackageDescription
2
+
3
+ let package = Package(
4
+ name: "mac-speech-analyzer",
5
+ platforms: [ .macOS(.v26) ],
6
+ targets: [
7
+ .executableTarget(
8
+ name: "mac-speech-analyzer",
9
+ linkerSettings: [
10
+ .unsafeFlags([
11
+ "-Xlinker","-sectcreate",
12
+ "-Xlinker","__TEXT",
13
+ "-Xlinker","__info_plist",
14
+ "-Xlinker","Info.plist"
15
+ ])
16
+ ]
17
+ )
18
+ ]
19
+ )
@@ -0,0 +1,72 @@
1
+ # mac-speech-analyzer
2
+
3
+ 🐍 Python package to run the macOS 26 SpeechAnalyzer API from Python to transcribe audio files.
4
+
5
+ The SpeechAnalyzer API generally provides [faster and better results]((https://get-inscribe.com/blog/apple-speech-api-benchmark.html)) than other locally running transcription engines of comparable size.
6
+
7
+ ## Features
8
+
9
+ - **Online** or **Offline** transcription
10
+ - Automatic download of new languages
11
+
12
+ ## Requirements
13
+
14
+ - macOS >= 26.0
15
+ - XCode command-line tools
16
+
17
+ ## Installation
18
+
19
+ mac-speech-analyzer is currently not tracked on pypi yet.
20
+
21
+ ```bash
22
+ uv add git+https://github.com/paraversal/mac-speech-analyzer
23
+ # or
24
+ pip install git+https://github.com/paraversal/mac-speech-analyzer
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ ### Basic usage
30
+
31
+ ```py
32
+ from macspeechanalyzer import transcribe
33
+
34
+ text = transcribe("/path/to/file", locale = "en_US")
35
+ ```
36
+
37
+ ## Technical details
38
+
39
+ This package is made up of two parts: the Python wrapper provides the API, but the actual functionality is achieved by embedding a Swift project which exposes functions to C. With this kind of three language interplay, a clean separation of concerns is really important. Therefore, the implementation is divided into the following four layers:
40
+
41
+ - Pure Python
42
+ - Python → C compat
43
+ - Swift → C compat
44
+ - Pure Swift
45
+
46
+ The pure Swift and pure Python layers only deal with their respective languages & types, while the compat layers do all the ugly work of converting between native and C-compatible types
47
+
48
+ ## Roadmap
49
+
50
+ - ✅ Basic one-shot transcription
51
+ - Class-based interface
52
+ - Context manager implementation
53
+ - Transcription of live audio stream (microphone, ...)
54
+
55
+
56
+ ## Development
57
+
58
+ ```zsh
59
+ uv pip install -e .
60
+ ```
61
+
62
+ to one-time-install the package as editable, from then on:
63
+
64
+ ```zsh
65
+ ninja
66
+ ```
67
+
68
+ to rebuild the package
69
+
70
+ # License
71
+
72
+ mac-speech-analyzer is released under the MIT License. See [LICENSE](./LICENSE) for more details.
@@ -0,0 +1,11 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
3
+ "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
4
+ <plist version="1.0">
5
+ <dict>
6
+ <key>com.apple.developer.speech-recognition</key>
7
+ <true/>
8
+ <key>com.apple.security.cs.disable-library-validation</key>
9
+ <true/>
10
+ </dict>
11
+ </plist>
@@ -0,0 +1,35 @@
1
+ [build-system]
2
+ requires = ["scikit-build-core>=0.10"]
3
+ build-backend = "scikit_build_core.build"
4
+
5
+ [project]
6
+ name = "mac-speech-analyzer"
7
+ version = "0.1.0"
8
+ description = "On-device speech transcription for macOS via Apple's SpeechAnalyzer"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.10"
12
+ classifiers = [
13
+ "Operating System :: MacOS",
14
+ "Programming Language :: Python :: 3"
15
+ ]
16
+
17
+ [tool.scikit-build]
18
+ wheel.packages = ["src/macspeechanalyzer"]
19
+ wheel.py-api = "py3"
20
+ minimum-version = "build-system.requires"
21
+ build-dir = "build/{wheel_tag}"
22
+
23
+ [tool.scikit-build.cmake]
24
+ version = ">=3.26"
25
+
26
+ [tool.scikit-build.editable]
27
+ mode = "inplace"
28
+ rebuild = true
29
+
30
+ [dependency-groups]
31
+ dev = [
32
+ "cmake>=4.4.0",
33
+ "ninja>=1.13.0",
34
+ "scikit-build-core>=1.0.3",
35
+ ]
@@ -0,0 +1,4 @@
1
+ import logging
2
+ from macspeechanalyzer.main import transcribe
3
+
4
+ logging.getLogger(__name__).addHandler(logging.NullHandler())
@@ -0,0 +1,116 @@
1
+ import ctypes
2
+ from pathlib import Path
3
+ import logging
4
+ from typing import Callable
5
+ import os
6
+
7
+ log = logging.getLogger(__name__)
8
+
9
+ LOG_CB = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p)
10
+ SEGMENT_CB = ctypes.CFUNCTYPE(None, ctypes.c_char_p)
11
+
12
+ @LOG_CB
13
+ def _log_cb(level, msg):
14
+ # for now, hacky: newline and flush stdout before/after each log print, otherwise logs may be bolted straight to a segment
15
+ print("", flush=True)
16
+ log.log(level or logging.INFO, msg.decode("utf-8", "replace") if msg else "")
17
+
18
+ @SEGMENT_CB
19
+ def _live_cb(msg):
20
+ print(msg.decode("utf-8", "replace") if msg else "", end="", flush=True)
21
+
22
+ _lib = ctypes.CDLL(str(Path(__file__).parent / f"libmacspeechanalyzer_core.dylib"))
23
+
24
+ # int32 msa_transcribe(const char* url, const char* locale, char** outText, bool* emitLiveFragments)
25
+ _lib.msa_transcribe.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.POINTER(ctypes.c_void_p), ctypes.c_bool]
26
+ _lib.msa_transcribe.restype = ctypes.c_int32
27
+
28
+ # void msa_free_string(char* ptr)
29
+ _lib.msa_free_string.argtypes = [ctypes.c_void_p]
30
+ _lib.msa_free_string.restype = None
31
+
32
+ # char* msa_last_error() — strdup'ed message, caller frees
33
+ _lib.msa_last_error.argtypes = []
34
+ _lib.msa_last_error.restype = ctypes.c_void_p
35
+
36
+ _lib.msa_set_log_callback.argtypes = [LOG_CB]
37
+ _lib.msa_set_log_callback.restype = None
38
+ _lib.msa_set_log_callback(_log_cb)
39
+
40
+ _lib.msa_set_live_callback.argtypes = [SEGMENT_CB]
41
+ _lib.msa_set_live_callback.restype = None
42
+
43
+ class SpeechAnalyzerError(Exception):
44
+ pass
45
+
46
+ def _take_string(ptr: ctypes.c_void_p) -> str:
47
+ """Copy a Swift-allocated C string into a Python str, then free it."""
48
+ try:
49
+ return ctypes.string_at(ptr).decode("utf-8")
50
+ finally:
51
+ _lib.msa_free_string(ptr)
52
+
53
+ def _raise_last_error(status: int) -> None:
54
+ ptr = _lib.msa_last_error()
55
+ msg = _take_string(ctypes.c_void_p(ptr)) if ptr else f"native error (status {status})"
56
+ raise SpeechAnalyzerError(msg)
57
+
58
+ def transcribe(path: str | Path, locale: str | None = None, on_segment: Callable[[str], None] | None = None) -> str:
59
+ """Transcribe an audio file on-device.
60
+
61
+ Runs synchronously and returns the full transcript once the file has
62
+ been fully analyzed. If ``on_segment`` is provided, it is also invoked
63
+ once per finalized segment as transcription progresses, allowing the
64
+ caller to observe or display partial results without waiting for the
65
+ final return value.
66
+
67
+ Args:
68
+ path: Filesystem path to the audio file to transcribe. Any format
69
+ readable by ``AVAudioFile`` is accepted (e.g. wav, m4a, mp3,
70
+ caf, aiff).
71
+ locale: BCP 47 / Apple locale identifier (e.g. ``"en_US"``,
72
+ ``"de_DE"``, ``"ja_JP"``) selecting the transcription language.
73
+ If ``None``, the system's current locale is used when supported,
74
+ otherwise English. If the requested locale's model is not yet
75
+ installed on the device, it will be downloaded on first use.
76
+ on_segment: Optional callback invoked from a background thread once
77
+ per finalized transcript segment, in order, with the segment
78
+ text as its single argument. Segments are non-overlapping and
79
+ never revised, so appending them reconstructs the full
80
+ transcript. Pass ``print`` to echo segments to stdout as they
81
+ arrive.
82
+
83
+ Returns:
84
+ The complete transcript as a single string.
85
+
86
+ Raises:
87
+ FileNotFoundError: If ``url`` does not point to a readable file.
88
+ RuntimeError: If the host is running a macOS version older than
89
+ 26.0, or if the native transcription pipeline fails.
90
+ """
91
+ emit_live_segments = False
92
+ if on_segment is print:
93
+ _lib.msa_set_live_callback(_live_cb)
94
+ emit_live_segments = True
95
+ elif on_segment is not None:
96
+ def _trampoline(raw: bytes | None) -> None:
97
+ if raw is not None:
98
+ on_segment(raw.decode("utf-8", "replace"))
99
+ cb = SEGMENT_CB(_trampoline)
100
+ _lib.msa_set_live_callback(cb)
101
+ emit_live_segments = True
102
+
103
+ path = os.fspath(path)
104
+
105
+ out = ctypes.c_void_p()
106
+ status = _lib.msa_transcribe(
107
+ path.encode("utf-8"),
108
+ locale.encode("utf-8") if locale is not None else None,
109
+ ctypes.byref(out), # &out -> char**
110
+ emit_live_segments
111
+ )
112
+ if status != 0:
113
+ _raise_last_error(status)
114
+ if not out.value:
115
+ raise SpeechAnalyzerError("transcribe returned success but no text")
116
+ return _take_string(out)
@@ -0,0 +1,87 @@
1
+ import Foundation
2
+
3
+ // Async compat
4
+ final class ResultBox<T>: @unchecked Sendable {
5
+ var value: Result<T, Error>?
6
+ }
7
+
8
+ func runBlocking<T: Sendable>(_ body: @Sendable @escaping () async throws -> T) throws -> T {
9
+ let box = ResultBox<T>()
10
+ let semaphore = DispatchSemaphore(value: 0)
11
+ Task.detached {
12
+ do { box.value = .success(try await body()) }
13
+ catch { box.value = .failure(error) }
14
+ semaphore.signal()
15
+ }
16
+ semaphore.wait()
17
+ return try box.value!.get()
18
+ }
19
+
20
+ private let errorLock = NSLock()
21
+ private var _lastError: String?
22
+
23
+ func setLastError(_ message: String) {
24
+ errorLock.lock(); defer { errorLock.unlock() }
25
+ _lastError = message
26
+ }
27
+
28
+ @_cdecl("msa_last_error")
29
+ public func msaLastError() -> UnsafeMutablePointer<CChar>? {
30
+ errorLock.lock(); defer { errorLock.unlock() }
31
+ guard let err = _lastError else { return nil }
32
+ return strdup(err) // Python copies + msa_free_string's it
33
+ }
34
+
35
+ @_cdecl("msa_transcribe")
36
+ public func msaTranscribe(
37
+ _ url: UnsafePointer<CChar>?,
38
+ _ locale: UnsafePointer<CChar>?,
39
+ _ outText: UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>?,
40
+ _ emitLiveSegments: CBool) -> Int32 {
41
+ let localeStr = locale.map { String(cString: $0) } // nil stays nil
42
+ let urlStr = url.map { String(cString: $0) }!
43
+ do {
44
+ let text = try runBlocking { try await transcribe(url: urlStr, locale: localeStr, emitLiveSegments: emitLiveSegments) }
45
+ outText?.pointee = strdup(text)
46
+ return 0
47
+ } catch {
48
+ setLastError("\(error)")
49
+ return 1
50
+ }
51
+ }
52
+
53
+ @_cdecl("msa_free_string")
54
+ public func msaFreeString(_ ptr: UnsafeMutablePointer<CChar>?) {
55
+ free(ptr)
56
+ }
57
+
58
+ public typealias MSALogCallback = @convention(c) (Int32, UnsafePointer<CChar>?) -> Void
59
+ private var logSink: MSALogCallback?
60
+
61
+ @_cdecl("msa_set_log_callback")
62
+ public func msa_set_log_callback(_ cb: MSALogCallback?) {
63
+ logSink = cb
64
+ }
65
+
66
+ // use this everywhere instead of print()
67
+ func msaLog(_ level: Int32, _ message: String) {
68
+ if let sink = logSink {
69
+ message.withCString { sink(level, $0) }
70
+ } else {
71
+ print(message) // fallback when nobody registered
72
+ }
73
+ }
74
+
75
+ public typealias MSALiveTranscription = @convention(c) (UnsafePointer<CChar>?) -> Void
76
+ private var liveTranscriptionSink: MSALiveTranscription?
77
+
78
+ @_cdecl("msa_set_live_callback")
79
+ public func msa_set_live_transcription_callback(_ cb: MSALiveTranscription?) {
80
+ liveTranscriptionSink = cb
81
+ }
82
+
83
+ func msaLiveTranscriptionSendFragment(_ message: String) {
84
+ if let sink = liveTranscriptionSink {
85
+ message.withCString { sink($0) }
86
+ }
87
+ }
@@ -0,0 +1,95 @@
1
+ import Foundation
2
+ import AVFAudio
3
+ import Speech
4
+ import Darwin
5
+
6
+ let INFO = Int32(20)
7
+
8
+ enum MSAError: Error {
9
+ case osRequirementError(String)
10
+ }
11
+
12
+ func checkMacosVersion () throws {
13
+ guard #available(macOS 26.0, *) else {
14
+ throw MSAError.osRequirementError("SpeechAnalyzer is only available on macos >= 26.0.")
15
+ }
16
+ }
17
+
18
+ func transcribe(url: String, locale: String?, emitLiveSegments: Bool) async throws -> String {
19
+ try checkMacosVersion()
20
+ let locale = await getLocale(customLocale: locale)
21
+
22
+ let transcriber = SpeechTranscriber(
23
+ locale: locale,
24
+ preset: .transcription
25
+ )
26
+ do {
27
+ try await downloadLocale(locale, transcriber)
28
+ } catch {
29
+ msaLog(INFO, "so this failed...")
30
+ }
31
+
32
+ let analyzer = SpeechAnalyzer(modules: [transcriber])
33
+ let inputURL = URL(fileURLWithPath: url)
34
+ let audioFile = try AVAudioFile(forReading: inputURL)
35
+
36
+ var transcript = ""
37
+ let consumer = Task {
38
+ for try await result in transcriber.results where result.isFinal {
39
+ let piece = String(result.text.characters)
40
+ if emitLiveSegments {
41
+ msaLiveTranscriptionSendFragment(piece)
42
+ }
43
+ transcript += piece
44
+ }
45
+ return transcript
46
+ }
47
+
48
+ if let last = try await analyzer.analyzeSequence(from: audioFile) {
49
+ try await analyzer.finalizeAndFinish(through: last)
50
+ } else {
51
+ await analyzer.cancelAndFinishNow()
52
+ }
53
+ try await consumer.value
54
+
55
+ msaLog(INFO, "Successfully transcribed text.")
56
+ return transcript
57
+ }
58
+
59
+ /// Obtains a valid locale (e.g., en_US).
60
+ /// Only a subset of all available locales are supported by the SpeechAnalyzer API.
61
+ /// 1. If a custom locale was passed, there is an attempt to parse it.
62
+ /// 2. If there was no custom locale passed or the parsing failed, we try to use the system locale.
63
+ /// 3. If this also fails, we use the `en` locale
64
+ func getLocale(customLocale: String?) async -> Locale {
65
+ var locale: Locale
66
+ // if a custom locale was passed; try to parse it
67
+ if let setCustomLocaleString = customLocale {
68
+ let setCustomLocale = Locale.init(identifier: setCustomLocaleString)
69
+ if let supportedCustomLocale = await SpeechTranscriber.supportedLocale(equivalentTo: setCustomLocale) {
70
+ return supportedCustomLocale
71
+ } else {
72
+ // we should probably throw an exception here
73
+ }
74
+ }
75
+
76
+ // if not, try to use current system locale
77
+ if let currentLocale = await SpeechTranscriber.supportedLocale(equivalentTo: Locale.current) {
78
+ locale = currentLocale
79
+ } else {
80
+ // if even this doesn't work, we simply use English
81
+ locale = Locale.init(languageCode: .english, script: .latin, languageRegion: .unknown)
82
+ }
83
+
84
+ return locale
85
+ }
86
+
87
+ /// Checks the availability of the selected locale, and downloads it if necessary.
88
+ func downloadLocale(_ locale: Locale, _ transcriber: SpeechTranscriber) async throws {
89
+ if !(await SpeechTranscriber.installedLocales).contains(locale) {
90
+ msaLog(INFO, "Downloading locale \(locale)")
91
+ if let request = try await AssetInventory.assetInstallationRequest(supporting: [transcriber]) {
92
+ try await request.downloadAndInstall()
93
+ }
94
+ }
95
+ }
@@ -0,0 +1,185 @@
1
+ version = 1
2
+ revision = 3
3
+ requires-python = ">=3.10"
4
+
5
+ [[package]]
6
+ name = "cmake"
7
+ version = "4.4.0"
8
+ source = { registry = "https://pypi.org/simple" }
9
+ sdist = { url = "https://files.pythonhosted.org/packages/ca/4c/fec299c7e437299ac354b7907bdcedfb85860afce76471ed0fcc6879166d/cmake-4.4.0.tar.gz", hash = "sha256:933eb5977ecc5226e47d702d1c412b69f77ca00f59a4660c80b436cf7d5472de", size = 34915, upload-time = "2026-07-10T20:50:32.879Z" }
10
+ wheels = [
11
+ { url = "https://files.pythonhosted.org/packages/50/21/9e97957b80e548f44277753f369bfcb9a997333380d5adb9f4dcf8cc6790/cmake-4.4.0-py3-none-macosx_10_10_universal2.whl", hash = "sha256:3068d219f21dde2c757fc65bf6fa1f11e892ddba1a00f2bc87276529d9c95f9a", size = 54381909, upload-time = "2026-07-10T20:48:51.167Z" },
12
+ { url = "https://files.pythonhosted.org/packages/a3/fc/83b3472c3c40759e29970f583a6602fb584ae0123b573de2ff44a0a52712/cmake-4.4.0-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7ce803007cbebd3440eb0c52cec6b28a172b5cd7737ceaf613bc566880c1d0a4", size = 30277284, upload-time = "2026-07-10T20:48:57.604Z" },
13
+ { url = "https://files.pythonhosted.org/packages/3d/36/0c83d4682758f6e1cbc56f0aaac5b392a3c93d81518d99418aa0f2e1d805/cmake-4.4.0-py3-none-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:41021341a394406fa56d54dabe2eaa32ac7f74fde076720397872bdc3f96a19d", size = 31451960, upload-time = "2026-07-10T20:49:02.31Z" },
14
+ { url = "https://files.pythonhosted.org/packages/22/fc/33224d3f8310555e26934a119a681b76e6324601e5617b88515b2aecddd5/cmake-4.4.0-py3-none-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:825ce04c2873b4d1e6185d7cf8330d38658b00d72e56a375445241d14fe21ff7", size = 31208506, upload-time = "2026-07-10T20:49:07.954Z" },
15
+ { url = "https://files.pythonhosted.org/packages/fe/86/640651cd15993ce76f54bf953cc39c1f0114f5d22960301b208887c0b8d5/cmake-4.4.0-py3-none-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:4329555c90091d10c4651272c36c8fe91b7af8c25655529c8276c33461d02957", size = 29087073, upload-time = "2026-07-10T20:49:12.731Z" },
16
+ { url = "https://files.pythonhosted.org/packages/f8/8d/6f62747b52bf1b48f05f1bf187ea95bfbc6338d21692223f67db2576b944/cmake-4.4.0-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:51bcb2e65c0d5c1af4a749ba40a321b7436420c7359724ab46719004f3cd2149", size = 30215347, upload-time = "2026-07-10T20:49:18.265Z" },
17
+ { url = "https://files.pythonhosted.org/packages/f1/5a/370b663877b0f58083fdcf1c5490604d0d4bf7750d63169e1c49c7035a5e/cmake-4.4.0-py3-none-manylinux_2_31_armv7l.whl", hash = "sha256:a70cafba0e4f7a741b8ef41fc8a58da0963512a0f505a38256ed0a2c70ef07eb", size = 27309126, upload-time = "2026-07-10T20:49:23.161Z" },
18
+ { url = "https://files.pythonhosted.org/packages/2f/63/83bf7eacccf338d939098f5f6944eed3b27b7da2c56442eb7640c2468f7d/cmake-4.4.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a550aaae137eaed453eb4493ceafa135f70da0b6660cd3ef05adbf9a2e9da629", size = 27419954, upload-time = "2026-07-10T20:49:28.13Z" },
19
+ { url = "https://files.pythonhosted.org/packages/5e/f6/4a9158c97cbbc73a99102228914453f71a429cc05e54193bdb94306d6679/cmake-4.4.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:43d07406792836dc27d3d17f0ef927aa1f07f9cabf19674bf3daf64998a1a4c1", size = 39458539, upload-time = "2026-07-10T20:49:34.228Z" },
20
+ { url = "https://files.pythonhosted.org/packages/29/8c/86cf5eb866dabc1e19c64ea0e2445504b32633a609d54ae78537a9374d11/cmake-4.4.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:efaca203845fdb611e2709fc88e39034d9596139e7ef8c87875ff8b63728576e", size = 36091712, upload-time = "2026-07-10T20:49:40.29Z" },
21
+ { url = "https://files.pythonhosted.org/packages/1e/37/b23658343f7c00ced44813dd1dd272840c733601fb8c05d99e8e7b1f6246/cmake-4.4.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2df0e65b29fd68067ace39a5405ce334a6f3a738ae59f9ca50f79bee178d1ae0", size = 42227957, upload-time = "2026-07-10T20:49:46.901Z" },
22
+ { url = "https://files.pythonhosted.org/packages/f2/b4/f197a34feaee62b5ffd0091cce8bb89b46420ae322fd0ba503829b08f1a0/cmake-4.4.0-py3-none-musllinux_1_2_ppc64le.whl", hash = "sha256:3e9260372bbdc68f4b575548ca92ba02c459ed6acfc1903fae49d8945afe529b", size = 41381016, upload-time = "2026-07-10T20:49:53.213Z" },
23
+ { url = "https://files.pythonhosted.org/packages/97/d9/6deaf3453ce1c60d72cdfea8b3fe05cf367578f5610ed96d5548e3019970/cmake-4.4.0-py3-none-musllinux_1_2_riscv64.whl", hash = "sha256:fc30f2cffc29951ba996db0f73a5f6cb4e4ef96be983199a10c2eeb25c4f151e", size = 36306195, upload-time = "2026-07-10T20:49:59.07Z" },
24
+ { url = "https://files.pythonhosted.org/packages/8b/0f/2c397d6712fac6ed892d2614ed08947b78714aeca53ccb6c58b62730304c/cmake-4.4.0-py3-none-musllinux_1_2_s390x.whl", hash = "sha256:66271dacfa14a1a6abd845b65ae76dc14491716c3fdaa499745e6d16f41712c8", size = 38652910, upload-time = "2026-07-10T20:50:05.141Z" },
25
+ { url = "https://files.pythonhosted.org/packages/f1/85/24cb4bf15eecfb7bf8092bccbe6263c4ff1cd22ce88077fb5131f5279d16/cmake-4.4.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:842de4296c7fb651799e6e3c1f8dc2355d3539067507f5c8012d1dc4625657b2", size = 39428686, upload-time = "2026-07-10T20:50:11.299Z" },
26
+ { url = "https://files.pythonhosted.org/packages/ca/51/f2057dcfdd2d87e98a7ddd4347111165612780a9da872195f538d947e869/cmake-4.4.0-py3-none-win32.whl", hash = "sha256:8e245108da252fc67410b549f025d578d7689f99366e00d8cea1f6a1c49fc1a9", size = 38759093, upload-time = "2026-07-10T20:50:17.491Z" },
27
+ { url = "https://files.pythonhosted.org/packages/6d/cb/7118b720745d76a6dca9ddf3c096fb90c71a2841b8ca493218202fc9d40a/cmake-4.4.0-py3-none-win_amd64.whl", hash = "sha256:13209a4d89d554c0b5623ed1158024b045e468bbb912c3f491de5e957b940858", size = 42309353, upload-time = "2026-07-10T20:50:23.85Z" },
28
+ { url = "https://files.pythonhosted.org/packages/04/8f/2818561f47151e0ffdfe44356c160038b5ae4e9025c0a3e61e36cd685489/cmake-4.4.0-py3-none-win_arm64.whl", hash = "sha256:7d481da3868e1b5831db34573c061daa8534a584baaffac93b1348b92e493f20", size = 40473618, upload-time = "2026-07-10T20:50:30.352Z" },
29
+ ]
30
+
31
+ [[package]]
32
+ name = "exceptiongroup"
33
+ version = "1.3.1"
34
+ source = { registry = "https://pypi.org/simple" }
35
+ dependencies = [
36
+ { name = "typing-extensions" },
37
+ ]
38
+ sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" }
39
+ wheels = [
40
+ { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" },
41
+ ]
42
+
43
+ [[package]]
44
+ name = "mac-speech-analyzer"
45
+ version = "0.1.0"
46
+ source = { editable = "." }
47
+
48
+ [package.dev-dependencies]
49
+ dev = [
50
+ { name = "cmake" },
51
+ { name = "ninja" },
52
+ { name = "scikit-build-core" },
53
+ ]
54
+
55
+ [package.metadata]
56
+
57
+ [package.metadata.requires-dev]
58
+ dev = [
59
+ { name = "cmake", specifier = ">=4.4.0" },
60
+ { name = "ninja", specifier = ">=1.13.0" },
61
+ { name = "scikit-build-core", specifier = ">=1.0.3" },
62
+ ]
63
+
64
+ [[package]]
65
+ name = "ninja"
66
+ version = "1.13.0"
67
+ source = { registry = "https://pypi.org/simple" }
68
+ sdist = { url = "https://files.pythonhosted.org/packages/43/73/79a0b22fc731989c708068427579e840a6cf4e937fe7ae5c5d0b7356ac22/ninja-1.13.0.tar.gz", hash = "sha256:4a40ce995ded54d9dc24f8ea37ff3bf62ad192b547f6c7126e7e25045e76f978", size = 242558, upload-time = "2025-08-11T15:10:19.421Z" }
69
+ wheels = [
70
+ { url = "https://files.pythonhosted.org/packages/3c/74/d02409ed2aa865e051b7edda22ad416a39d81a84980f544f8de717cab133/ninja-1.13.0-py3-none-macosx_10_9_universal2.whl", hash = "sha256:fa2a8bfc62e31b08f83127d1613d10821775a0eb334197154c4d6067b7068ff1", size = 310125, upload-time = "2025-08-11T15:09:50.971Z" },
71
+ { url = "https://files.pythonhosted.org/packages/8e/de/6e1cd6b84b412ac1ef327b76f0641aeb5dcc01e9d3f9eee0286d0c34fd93/ninja-1.13.0-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3d00c692fb717fd511abeb44b8c5d00340c36938c12d6538ba989fe764e79630", size = 177467, upload-time = "2025-08-11T15:09:52.767Z" },
72
+ { url = "https://files.pythonhosted.org/packages/c8/83/49320fb6e58ae3c079381e333575fdbcf1cca3506ee160a2dcce775046fa/ninja-1.13.0-py3-none-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:be7f478ff9f96a128b599a964fc60a6a87b9fa332ee1bd44fa243ac88d50291c", size = 187834, upload-time = "2025-08-11T15:09:54.115Z" },
73
+ { url = "https://files.pythonhosted.org/packages/56/c7/ba22748fb59f7f896b609cd3e568d28a0a367a6d953c24c461fe04fc4433/ninja-1.13.0-py3-none-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:60056592cf495e9a6a4bea3cd178903056ecb0943e4de45a2ea825edb6dc8d3e", size = 202736, upload-time = "2025-08-11T15:09:55.745Z" },
74
+ { url = "https://files.pythonhosted.org/packages/79/22/d1de07632b78ac8e6b785f41fa9aad7a978ec8c0a1bf15772def36d77aac/ninja-1.13.0-py3-none-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:1c97223cdda0417f414bf864cfb73b72d8777e57ebb279c5f6de368de0062988", size = 179034, upload-time = "2025-08-11T15:09:57.394Z" },
75
+ { url = "https://files.pythonhosted.org/packages/ed/de/0e6edf44d6a04dabd0318a519125ed0415ce437ad5a1ec9b9be03d9048cf/ninja-1.13.0-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fb46acf6b93b8dd0322adc3a4945452a4e774b75b91293bafcc7b7f8e6517dfa", size = 180716, upload-time = "2025-08-11T15:09:58.696Z" },
76
+ { url = "https://files.pythonhosted.org/packages/54/28/938b562f9057aaa4d6bfbeaa05e81899a47aebb3ba6751e36c027a7f5ff7/ninja-1.13.0-py3-none-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4be9c1b082d244b1ad7ef41eb8ab088aae8c109a9f3f0b3e56a252d3e00f42c1", size = 146843, upload-time = "2025-08-11T15:10:00.046Z" },
77
+ { url = "https://files.pythonhosted.org/packages/2a/fb/d06a3838de4f8ab866e44ee52a797b5491df823901c54943b2adb0389fbb/ninja-1.13.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:6739d3352073341ad284246f81339a384eec091d9851a886dfa5b00a6d48b3e2", size = 154402, upload-time = "2025-08-11T15:10:01.657Z" },
78
+ { url = "https://files.pythonhosted.org/packages/31/bf/0d7808af695ceddc763cf251b84a9892cd7f51622dc8b4c89d5012779f06/ninja-1.13.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:11be2d22027bde06f14c343f01d31446747dbb51e72d00decca2eb99be911e2f", size = 552388, upload-time = "2025-08-11T15:10:03.349Z" },
79
+ { url = "https://files.pythonhosted.org/packages/9d/70/c99d0c2c809f992752453cce312848abb3b1607e56d4cd1b6cded317351a/ninja-1.13.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:aa45b4037b313c2f698bc13306239b8b93b4680eb47e287773156ac9e9304714", size = 472501, upload-time = "2025-08-11T15:10:04.735Z" },
80
+ { url = "https://files.pythonhosted.org/packages/9f/43/c217b1153f0e499652f5e0766da8523ce3480f0a951039c7af115e224d55/ninja-1.13.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5f8e1e8a1a30835eeb51db05cf5a67151ad37542f5a4af2a438e9490915e5b72", size = 638280, upload-time = "2025-08-11T15:10:06.512Z" },
81
+ { url = "https://files.pythonhosted.org/packages/8c/45/9151bba2c8d0ae2b6260f71696330590de5850e5574b7b5694dce6023e20/ninja-1.13.0-py3-none-musllinux_1_2_ppc64le.whl", hash = "sha256:3d7d7779d12cb20c6d054c61b702139fd23a7a964ec8f2c823f1ab1b084150db", size = 642420, upload-time = "2025-08-11T15:10:08.35Z" },
82
+ { url = "https://files.pythonhosted.org/packages/3c/fb/95752eb635bb8ad27d101d71bef15bc63049de23f299e312878fc21cb2da/ninja-1.13.0-py3-none-musllinux_1_2_riscv64.whl", hash = "sha256:d741a5e6754e0bda767e3274a0f0deeef4807f1fec6c0d7921a0244018926ae5", size = 585106, upload-time = "2025-08-11T15:10:09.818Z" },
83
+ { url = "https://files.pythonhosted.org/packages/c1/31/aa56a1a286703800c0cbe39fb4e82811c277772dc8cd084f442dd8e2938a/ninja-1.13.0-py3-none-musllinux_1_2_s390x.whl", hash = "sha256:e8bad11f8a00b64137e9b315b137d8bb6cbf3086fbdc43bf1f90fd33324d2e96", size = 707138, upload-time = "2025-08-11T15:10:11.366Z" },
84
+ { url = "https://files.pythonhosted.org/packages/34/6f/5f5a54a1041af945130abdb2b8529cbef0cdcbbf9bcf3f4195378319d29a/ninja-1.13.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b4f2a072db3c0f944c32793e91532d8948d20d9ab83da9c0c7c15b5768072200", size = 581758, upload-time = "2025-08-11T15:10:13.295Z" },
85
+ { url = "https://files.pythonhosted.org/packages/95/97/51359c77527d45943fe7a94d00a3843b81162e6c4244b3579fe8fc54cb9c/ninja-1.13.0-py3-none-win32.whl", hash = "sha256:8cfbb80b4a53456ae8a39f90ae3d7a2129f45ea164f43fadfa15dc38c4aef1c9", size = 267201, upload-time = "2025-08-11T15:10:15.158Z" },
86
+ { url = "https://files.pythonhosted.org/packages/29/45/c0adfbfb0b5895aa18cec400c535b4f7ff3e52536e0403602fc1a23f7de9/ninja-1.13.0-py3-none-win_amd64.whl", hash = "sha256:fb8ee8719f8af47fed145cced4a85f0755dd55d45b2bddaf7431fa89803c5f3e", size = 309975, upload-time = "2025-08-11T15:10:16.697Z" },
87
+ { url = "https://files.pythonhosted.org/packages/df/93/a7b983643d1253bb223234b5b226e69de6cda02b76cdca7770f684b795f5/ninja-1.13.0-py3-none-win_arm64.whl", hash = "sha256:3c0b40b1f0bba764644385319028650087b4c1b18cdfa6f45cb39a3669b81aa9", size = 290806, upload-time = "2025-08-11T15:10:18.018Z" },
88
+ ]
89
+
90
+ [[package]]
91
+ name = "packaging"
92
+ version = "26.2"
93
+ source = { registry = "https://pypi.org/simple" }
94
+ sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" }
95
+ wheels = [
96
+ { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" },
97
+ ]
98
+
99
+ [[package]]
100
+ name = "pathspec"
101
+ version = "1.1.1"
102
+ source = { registry = "https://pypi.org/simple" }
103
+ sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" }
104
+ wheels = [
105
+ { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" },
106
+ ]
107
+
108
+ [[package]]
109
+ name = "scikit-build-core"
110
+ version = "1.0.3"
111
+ source = { registry = "https://pypi.org/simple" }
112
+ dependencies = [
113
+ { name = "exceptiongroup", marker = "python_full_version < '3.11'" },
114
+ { name = "packaging" },
115
+ { name = "pathspec" },
116
+ { name = "tomli", marker = "python_full_version < '3.11'" },
117
+ { name = "typing-extensions", marker = "python_full_version < '3.11'" },
118
+ ]
119
+ sdist = { url = "https://files.pythonhosted.org/packages/8d/7c/0f69b0c7150ce4bcee78c199fe3b7e03a6e01578451bd5d5d1a58beb32f9/scikit_build_core-1.0.3.tar.gz", hash = "sha256:a4d7a05978ee37975c37743510c8991e2debce7ef83afb0a07c0c576fd4f16e8", size = 477539, upload-time = "2026-07-12T05:08:30.298Z" }
120
+ wheels = [
121
+ { url = "https://files.pythonhosted.org/packages/b7/b0/7ad8fa9aebb0835b2e20afebf1483cbe175d1612fe01e85042ce9ced8755/scikit_build_core-1.0.3-py3-none-any.whl", hash = "sha256:ae95427b7d3c14a6cf8bbfd4d901f6138ab64c99e20cbe8ea7d75cd26093f085", size = 278294, upload-time = "2026-07-12T05:08:28.725Z" },
122
+ ]
123
+
124
+ [[package]]
125
+ name = "tomli"
126
+ version = "2.4.1"
127
+ source = { registry = "https://pypi.org/simple" }
128
+ sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", size = 17543, upload-time = "2026-03-25T20:22:03.828Z" }
129
+ wheels = [
130
+ { url = "https://files.pythonhosted.org/packages/f4/11/db3d5885d8528263d8adc260bb2d28ebf1270b96e98f0e0268d32b8d9900/tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30", size = 154704, upload-time = "2026-03-25T20:21:10.473Z" },
131
+ { url = "https://files.pythonhosted.org/packages/6d/f7/675db52c7e46064a9aa928885a9b20f4124ecb9bc2e1ce74c9106648d202/tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a", size = 149454, upload-time = "2026-03-25T20:21:12.036Z" },
132
+ { url = "https://files.pythonhosted.org/packages/61/71/81c50943cf953efa35bce7646caab3cf457a7d8c030b27cfb40d7235f9ee/tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076", size = 237561, upload-time = "2026-03-25T20:21:13.098Z" },
133
+ { url = "https://files.pythonhosted.org/packages/48/c1/f41d9cb618acccca7df82aaf682f9b49013c9397212cb9f53219e3abac37/tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9", size = 243824, upload-time = "2026-03-25T20:21:14.569Z" },
134
+ { url = "https://files.pythonhosted.org/packages/22/e4/5a816ecdd1f8ca51fb756ef684b90f2780afc52fc67f987e3c61d800a46d/tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c", size = 242227, upload-time = "2026-03-25T20:21:15.712Z" },
135
+ { url = "https://files.pythonhosted.org/packages/6b/49/2b2a0ef529aa6eec245d25f0c703e020a73955ad7edf73e7f54ddc608aa5/tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc", size = 247859, upload-time = "2026-03-25T20:21:17.001Z" },
136
+ { url = "https://files.pythonhosted.org/packages/83/bd/6c1a630eaca337e1e78c5903104f831bda934c426f9231429396ce3c3467/tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049", size = 97204, upload-time = "2026-03-25T20:21:18.079Z" },
137
+ { url = "https://files.pythonhosted.org/packages/42/59/71461df1a885647e10b6bb7802d0b8e66480c61f3f43079e0dcd315b3954/tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e", size = 108084, upload-time = "2026-03-25T20:21:18.978Z" },
138
+ { url = "https://files.pythonhosted.org/packages/b8/83/dceca96142499c069475b790e7913b1044c1a4337e700751f48ed723f883/tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece", size = 95285, upload-time = "2026-03-25T20:21:20.309Z" },
139
+ { url = "https://files.pythonhosted.org/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", size = 155924, upload-time = "2026-03-25T20:21:21.626Z" },
140
+ { url = "https://files.pythonhosted.org/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", size = 150018, upload-time = "2026-03-25T20:21:23.002Z" },
141
+ { url = "https://files.pythonhosted.org/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", size = 244948, upload-time = "2026-03-25T20:21:24.04Z" },
142
+ { url = "https://files.pythonhosted.org/packages/10/90/d62ce007a1c80d0b2c93e02cab211224756240884751b94ca72df8a875ca/tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", size = 253341, upload-time = "2026-03-25T20:21:25.177Z" },
143
+ { url = "https://files.pythonhosted.org/packages/1a/7e/caf6496d60152ad4ed09282c1885cca4eea150bfd007da84aea07bcc0a3e/tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", size = 248159, upload-time = "2026-03-25T20:21:26.364Z" },
144
+ { url = "https://files.pythonhosted.org/packages/99/e7/c6f69c3120de34bbd882c6fba7975f3d7a746e9218e56ab46a1bc4b42552/tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", size = 253290, upload-time = "2026-03-25T20:21:27.46Z" },
145
+ { url = "https://files.pythonhosted.org/packages/d6/2f/4a3c322f22c5c66c4b836ec58211641a4067364f5dcdd7b974b4c5da300c/tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", size = 98141, upload-time = "2026-03-25T20:21:28.492Z" },
146
+ { url = "https://files.pythonhosted.org/packages/24/22/4daacd05391b92c55759d55eaee21e1dfaea86ce5c571f10083360adf534/tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", size = 108847, upload-time = "2026-03-25T20:21:29.386Z" },
147
+ { url = "https://files.pythonhosted.org/packages/68/fd/70e768887666ddd9e9f5d85129e84910f2db2796f9096aa02b721a53098d/tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", size = 95088, upload-time = "2026-03-25T20:21:30.677Z" },
148
+ { url = "https://files.pythonhosted.org/packages/07/06/b823a7e818c756d9a7123ba2cda7d07bc2dd32835648d1a7b7b7a05d848d/tomli-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54", size = 155866, upload-time = "2026-03-25T20:21:31.65Z" },
149
+ { url = "https://files.pythonhosted.org/packages/14/6f/12645cf7f08e1a20c7eb8c297c6f11d31c1b50f316a7e7e1e1de6e2e7b7e/tomli-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a", size = 149887, upload-time = "2026-03-25T20:21:33.028Z" },
150
+ { url = "https://files.pythonhosted.org/packages/5c/e0/90637574e5e7212c09099c67ad349b04ec4d6020324539297b634a0192b0/tomli-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897", size = 243704, upload-time = "2026-03-25T20:21:34.51Z" },
151
+ { url = "https://files.pythonhosted.org/packages/10/8f/d3ddb16c5a4befdf31a23307f72828686ab2096f068eaf56631e136c1fdd/tomli-2.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f", size = 251628, upload-time = "2026-03-25T20:21:36.012Z" },
152
+ { url = "https://files.pythonhosted.org/packages/e3/f1/dbeeb9116715abee2485bf0a12d07a8f31af94d71608c171c45f64c0469d/tomli-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d", size = 247180, upload-time = "2026-03-25T20:21:37.136Z" },
153
+ { url = "https://files.pythonhosted.org/packages/d3/74/16336ffd19ed4da28a70959f92f506233bd7cfc2332b20bdb01591e8b1d1/tomli-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5", size = 251674, upload-time = "2026-03-25T20:21:38.298Z" },
154
+ { url = "https://files.pythonhosted.org/packages/16/f9/229fa3434c590ddf6c0aa9af64d3af4b752540686cace29e6281e3458469/tomli-2.4.1-cp313-cp313-win32.whl", hash = "sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd", size = 97976, upload-time = "2026-03-25T20:21:39.316Z" },
155
+ { url = "https://files.pythonhosted.org/packages/6a/1e/71dfd96bcc1c775420cb8befe7a9d35f2e5b1309798f009dca17b7708c1e/tomli-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36", size = 108755, upload-time = "2026-03-25T20:21:40.248Z" },
156
+ { url = "https://files.pythonhosted.org/packages/83/7a/d34f422a021d62420b78f5c538e5b102f62bea616d1d75a13f0a88acb04a/tomli-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd", size = 95265, upload-time = "2026-03-25T20:21:41.219Z" },
157
+ { url = "https://files.pythonhosted.org/packages/3c/fb/9a5c8d27dbab540869f7c1f8eb0abb3244189ce780ba9cd73f3770662072/tomli-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf", size = 155726, upload-time = "2026-03-25T20:21:42.23Z" },
158
+ { url = "https://files.pythonhosted.org/packages/62/05/d2f816630cc771ad836af54f5001f47a6f611d2d39535364f148b6a92d6b/tomli-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac", size = 149859, upload-time = "2026-03-25T20:21:43.386Z" },
159
+ { url = "https://files.pythonhosted.org/packages/ce/48/66341bdb858ad9bd0ceab5a86f90eddab127cf8b046418009f2125630ecb/tomli-2.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662", size = 244713, upload-time = "2026-03-25T20:21:44.474Z" },
160
+ { url = "https://files.pythonhosted.org/packages/df/6d/c5fad00d82b3c7a3ab6189bd4b10e60466f22cfe8a08a9394185c8a8111c/tomli-2.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853", size = 252084, upload-time = "2026-03-25T20:21:45.62Z" },
161
+ { url = "https://files.pythonhosted.org/packages/00/71/3a69e86f3eafe8c7a59d008d245888051005bd657760e96d5fbfb0b740c2/tomli-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15", size = 247973, upload-time = "2026-03-25T20:21:46.937Z" },
162
+ { url = "https://files.pythonhosted.org/packages/67/50/361e986652847fec4bd5e4a0208752fbe64689c603c7ae5ea7cb16b1c0ca/tomli-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba", size = 256223, upload-time = "2026-03-25T20:21:48.467Z" },
163
+ { url = "https://files.pythonhosted.org/packages/8c/9a/b4173689a9203472e5467217e0154b00e260621caa227b6fa01feab16998/tomli-2.4.1-cp314-cp314-win32.whl", hash = "sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6", size = 98973, upload-time = "2026-03-25T20:21:49.526Z" },
164
+ { url = "https://files.pythonhosted.org/packages/14/58/640ac93bf230cd27d002462c9af0d837779f8773bc03dee06b5835208214/tomli-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7", size = 109082, upload-time = "2026-03-25T20:21:50.506Z" },
165
+ { url = "https://files.pythonhosted.org/packages/d5/2f/702d5e05b227401c1068f0d386d79a589bb12bf64c3d2c72ce0631e3bc49/tomli-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232", size = 96490, upload-time = "2026-03-25T20:21:51.474Z" },
166
+ { url = "https://files.pythonhosted.org/packages/45/4b/b877b05c8ba62927d9865dd980e34a755de541eb65fffba52b4cc495d4d2/tomli-2.4.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4", size = 164263, upload-time = "2026-03-25T20:21:52.543Z" },
167
+ { url = "https://files.pythonhosted.org/packages/24/79/6ab420d37a270b89f7195dec5448f79400d9e9c1826df982f3f8e97b24fd/tomli-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c", size = 160736, upload-time = "2026-03-25T20:21:53.674Z" },
168
+ { url = "https://files.pythonhosted.org/packages/02/e0/3630057d8eb170310785723ed5adcdfb7d50cb7e6455f85ba8a3deed642b/tomli-2.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d", size = 270717, upload-time = "2026-03-25T20:21:55.129Z" },
169
+ { url = "https://files.pythonhosted.org/packages/7a/b4/1613716072e544d1a7891f548d8f9ec6ce2faf42ca65acae01d76ea06bb0/tomli-2.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41", size = 278461, upload-time = "2026-03-25T20:21:56.228Z" },
170
+ { url = "https://files.pythonhosted.org/packages/05/38/30f541baf6a3f6df77b3df16b01ba319221389e2da59427e221ef417ac0c/tomli-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c", size = 274855, upload-time = "2026-03-25T20:21:57.653Z" },
171
+ { url = "https://files.pythonhosted.org/packages/77/a3/ec9dd4fd2c38e98de34223b995a3b34813e6bdadf86c75314c928350ed14/tomli-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f", size = 283144, upload-time = "2026-03-25T20:21:59.089Z" },
172
+ { url = "https://files.pythonhosted.org/packages/ef/be/605a6261cac79fba2ec0c9827e986e00323a1945700969b8ee0b30d85453/tomli-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8", size = 108683, upload-time = "2026-03-25T20:22:00.214Z" },
173
+ { url = "https://files.pythonhosted.org/packages/12/64/da524626d3b9cc40c168a13da8335fe1c51be12c0a63685cc6db7308daae/tomli-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26", size = 121196, upload-time = "2026-03-25T20:22:01.169Z" },
174
+ { url = "https://files.pythonhosted.org/packages/5a/cd/e80b62269fc78fc36c9af5a6b89c835baa8af28ff5ad28c7028d60860320/tomli-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396", size = 100393, upload-time = "2026-03-25T20:22:02.137Z" },
175
+ { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" },
176
+ ]
177
+
178
+ [[package]]
179
+ name = "typing-extensions"
180
+ version = "4.16.0"
181
+ source = { registry = "https://pypi.org/simple" }
182
+ sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" }
183
+ wheels = [
184
+ { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" },
185
+ ]