diff --git a/ai4rag/components/data/constants.py b/ai4rag/components/data/constants.py index 87c7bc2..0525f71 100644 --- a/ai4rag/components/data/constants.py +++ b/ai4rag/components/data/constants.py @@ -19,5 +19,11 @@ ".qmd", ".rmd", ".xhtml", + ".wav", + ".mp3", + ".m4a", + ".aac", + ".ogg", + ".flac", } ) diff --git a/ai4rag/components/data/text_extraction.py b/ai4rag/components/data/text_extraction.py index 09da247..37a59b4 100644 --- a/ai4rag/components/data/text_extraction.py +++ b/ai4rag/components/data/text_extraction.py @@ -12,11 +12,17 @@ from pathlib import Path from typing import Any +from docling.datamodel import asr_model_specs from docling.datamodel.accelerator_options import AcceleratorOptions from docling.datamodel.base_models import InputFormat -from docling.datamodel.pipeline_options import PaginatedPipelineOptions, ThreadedPdfPipelineOptions +from docling.datamodel.pipeline_options import ( + AsrPipelineOptions, + PaginatedPipelineOptions, + ThreadedPdfPipelineOptions, +) from docling.document_converter import ( AsciiDocFormatOption, + AudioFormatOption, DocumentConverter, EmailFormatOption, EpubFormatOption, @@ -29,6 +35,7 @@ PowerpointFormatOption, WordFormatOption, ) +from docling.pipeline.asr_pipeline import AsrPipeline from ai4rag import handler from ai4rag.components.data.constants import SUPPORTED_EXTENSIONS @@ -361,6 +368,12 @@ def _build_docling_format_options(do_table_structure: bool = False) -> dict: do_table_structure=do_table_structure, accelerator_options=accel, ) + + asr_pipeline_options = AsrPipelineOptions( + asr_options=asr_model_specs.WHISPER_BASE, + ) + asr_pipeline_options.asr_options.language = None + paginated_pipeline_options = PaginatedPipelineOptions( artifacts_path=ap, generate_page_images=False, @@ -379,6 +392,7 @@ def _build_docling_format_options(do_table_structure: bool = False) -> dict: InputFormat.LATEX: LatexFormatOption(), InputFormat.EPUB: EpubFormatOption(), InputFormat.EMAIL: EmailFormatOption(), + InputFormat.AUDIO: AudioFormatOption(pipeline_cls=AsrPipeline, pipeline_options=asr_pipeline_options), } diff --git a/dev_utils/file_store.py b/dev_utils/file_store.py index 3c184af..1a98c3d 100644 --- a/dev_utils/file_store.py +++ b/dev_utils/file_store.py @@ -8,32 +8,45 @@ from pathlib import Path from typing import Sequence +from docling.datamodel import asr_model_specs from docling.datamodel.accelerator_options import AcceleratorOptions from docling.datamodel.base_models import InputFormat -from docling.datamodel.pipeline_options import PdfPipelineOptions -from docling.document_converter import DocumentConverter, PdfFormatOption, settings +from docling.datamodel.pipeline_options import PdfPipelineOptions, AsrPipelineOptions +from docling.document_converter import ( + DocumentConverter, + PdfFormatOption, + settings, + AudioFormatOption, +) +from docling.pipeline.asr_pipeline import AsrPipeline from docling_core.types.doc import DoclingDocument from docling_core.types.doc.labels import DocItemLabel logger = logging.getLogger(__name__) -SUPPORTED_EXTENSIONS = { - ".pdf", - ".docx", - ".pptx", - ".md", - ".html", - ".txt", - ".odt", - ".odp", - ".adoc", - ".tex", - ".epub", - ".eml", - ".qmd", - ".rmd", - ".xhtml", - } +SUPPORTED_EXTENSIONS = { + ".pdf", + ".docx", + ".pptx", + ".md", + ".html", + ".txt", + ".odt", + ".odp", + ".adoc", + ".tex", + ".epub", + ".eml", + ".qmd", + ".rmd", + ".xhtml", + ".wav", + ".mp3", + ".m4a", + ".aac", + ".ogg", + ".flac", +} _DEFAULT_CACHE_DIR = Path(__file__).parent / "local" / "docling_cache" @@ -71,17 +84,28 @@ def __init__( self.cache_dir = Path(cache_dir) if cache_dir is not None else None self.files = {} - pipeline_options = PdfPipelineOptions() - pipeline_options.do_ocr = False - pipeline_options.do_table_structure = True - pipeline_options.accelerator_options = AcceleratorOptions(device="auto") + pdf_options = PdfPipelineOptions() + pdf_options.do_ocr = False + pdf_options.do_table_structure = True + pdf_options.accelerator_options = AcceleratorOptions(device="auto") + + asr_options = AsrPipelineOptions() + asr_options.asr_options = asr_model_specs.WHISPER_BASE + asr_options.asr_options.language = None #if we stay with default the multilang has problems with non-eng texts num_workers = os.cpu_count() or 1 settings.perf.doc_batch_size = num_workers settings.perf.doc_batch_concurrency = num_workers self._converter = DocumentConverter( - format_options={InputFormat.PDF: PdfFormatOption(pipeline_options=pipeline_options)} + format_options={ + InputFormat.PDF: PdfFormatOption( + pipeline_options=pdf_options), + InputFormat.AUDIO: AudioFormatOption( + pipeline_cls=AsrPipeline, + pipeline_options=asr_options + ), + } ) def __repr__(self) -> str: diff --git a/pyproject.toml b/pyproject.toml index 70b586e..f256539 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,7 @@ dynamic = ["version"] dependencies = [ "boto3>=1.28", - "docling-slim[standard,feat-chunking,format-opendocument]~=2.107.0", + "docling-slim[standard,feat-chunking,format-opendocument,asr]~=2.107.0", "langchain_chroma~=1.1.0", "langchain-text-splitters~=1.1.0", "multiprocess>=0.70", diff --git a/tests/unit/ai4rag/components/data/test_discovery.py b/tests/unit/ai4rag/components/data/test_discovery.py index 4583a93..173b3a1 100644 --- a/tests/unit/ai4rag/components/data/test_discovery.py +++ b/tests/unit/ai4rag/components/data/test_discovery.py @@ -326,3 +326,57 @@ def test_list_objects_called_correctly(self, mocker): ) mock_client.list_objects_v2.assert_called_once_with(Bucket="my-bucket", Prefix="prefix/") + + def test_audio_extensions_discovered(self, mocker): + """Audio files with supported extensions must be discovered.""" + contents = [ + _s3_object("audio/meeting.wav", 1000), + _s3_object("audio/podcast.mp3", 2000), + _s3_object("audio/recording.m4a", 1500), + _s3_object("audio/clip.aac", 800), + _s3_object("audio/voice.ogg", 600), + _s3_object("audio/sample.flac", 3000), + ] + mock_client = _make_mock_s3_client(mocker, contents) + + result = discover_documents( + bucket_name="bucket", + prefix="audio/", + sampling_enabled=False, + s3_client=mock_client, + ) + + assert result.count == 6 + keys = [d.key for d in result.documents] + assert "audio/meeting.wav" in keys + assert "audio/podcast.mp3" in keys + assert "audio/recording.m4a" in keys + assert "audio/clip.aac" in keys + assert "audio/voice.ogg" in keys + assert "audio/sample.flac" in keys + + def test_mixed_audio_and_document_extensions(self, mocker): + """Audio and document files should both be discovered together.""" + contents = [ + _s3_object("data/report.pdf", 500), + _s3_object("data/meeting.mp3", 2000), + _s3_object("data/notes.md", 100), + _s3_object("data/recording.wav", 3000), + _s3_object("data/image.png", 400), + ] + mock_client = _make_mock_s3_client(mocker, contents) + + result = discover_documents( + bucket_name="bucket", + prefix="data/", + sampling_enabled=False, + s3_client=mock_client, + ) + + assert result.count == 4 + keys = [d.key for d in result.documents] + assert "data/report.pdf" in keys + assert "data/meeting.mp3" in keys + assert "data/notes.md" in keys + assert "data/recording.wav" in keys + assert "data/image.png" not in keys diff --git a/tests/unit/ai4rag/components/data/test_extraction.py b/tests/unit/ai4rag/components/data/test_extraction.py index e3a2698..3e60c9e 100644 --- a/tests/unit/ai4rag/components/data/test_extraction.py +++ b/tests/unit/ai4rag/components/data/test_extraction.py @@ -371,6 +371,7 @@ def test_formats_registered_have_entries_in_options(self): InputFormat.LATEX, InputFormat.EPUB, InputFormat.EMAIL, + InputFormat.AUDIO, ): assert fmt in options, f"{fmt} missing from format options" @@ -389,3 +390,47 @@ def test_do_table_structure_false(self): options = _build_docling_format_options(do_table_structure=False) pdf_option = options[InputFormat.PDF] assert pdf_option.pipeline_options.do_table_structure is False + + def test_audio_format_uses_asr_pipeline(self): + """Audio format option must use the AsrPipeline class.""" + from docling.datamodel.base_models import InputFormat + from docling.pipeline.asr_pipeline import AsrPipeline + + options = _build_docling_format_options() + audio_option = options[InputFormat.AUDIO] + assert audio_option.pipeline_cls is AsrPipeline + + def test_audio_format_language_is_auto_detect(self): + """Audio ASR options must use language=None for auto-detection.""" + from docling.datamodel.base_models import InputFormat + + options = _build_docling_format_options() + audio_option = options[InputFormat.AUDIO] + assert audio_option.pipeline_options.asr_options.language is None + + +# --------------------------------------------------------------------------- +# SUPPORTED_EXTENSIONS — audio formats +# --------------------------------------------------------------------------- + + +class TestSupportedExtensionsAudio: + """Tests that audio formats are included in SUPPORTED_EXTENSIONS.""" + + AUDIO_EXTENSIONS = {".wav", ".mp3", ".m4a", ".aac", ".ogg", ".flac"} + + def test_audio_extensions_present(self): + """All audio extensions must be in SUPPORTED_EXTENSIONS.""" + from ai4rag.components.data.constants import SUPPORTED_EXTENSIONS + + for ext in self.AUDIO_EXTENSIONS: + assert ext in SUPPORTED_EXTENSIONS, f"{ext} missing from SUPPORTED_EXTENSIONS" + + def test_original_extensions_still_present(self): + """Adding audio extensions must not remove existing document formats.""" + from ai4rag.components.data.constants import SUPPORTED_EXTENSIONS + + original = {".pdf", ".docx", ".pptx", ".md", ".html", ".txt", ".odt", ".odp", + ".adoc", ".tex", ".epub", ".eml", ".qmd", ".rmd", ".xhtml"} + for ext in original: + assert ext in SUPPORTED_EXTENSIONS, f"{ext} missing from SUPPORTED_EXTENSIONS" diff --git a/uv.lock b/uv.lock index 6f9e477..33caed7 100644 --- a/uv.lock +++ b/uv.lock @@ -91,7 +91,7 @@ requires-dist = [ { name = "beautifulsoup4", marker = "extra == 'dev'" }, { name = "black", marker = "extra == 'code-check'" }, { name = "boto3", specifier = ">=1.28" }, - { name = "docling-slim", extras = ["feat-chunking", "format-opendocument", "standard"], specifier = "~=2.107.0" }, + { name = "docling-slim", extras = ["asr", "feat-chunking", "format-opendocument", "standard"], specifier = "~=2.107.0" }, { name = "dotenv", marker = "extra == 'dev'" }, { name = "ipykernel", marker = "extra == 'dev'" }, { name = "isort", marker = "extra == 'code-check'" }, @@ -574,14 +574,14 @@ wheels = [ [[package]] name = "colorlog" -version = "6.12.0" +version = "6.11.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8c/55/ba79756cb90c8d69d599d57785398ac87bba7b19c80e87f4e8a562197c93/colorlog-6.12.0.tar.gz", hash = "sha256:2a7924c1dadf18b22a0eb8b06d1c7b01d5341707ec1641eb6fcc4fde0c3e8e5f", size = 18151, upload-time = "2026-07-23T13:40:40.71Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0a/bf/cb30a51af3aa8ce63735f77e23dcd4fc0720fe0339bcb04f77345659c277/colorlog-6.11.0.tar.gz", hash = "sha256:9d90fb53fa906c8970c18fbe46506bae1fb5f86b513b8f867db37e4ace9be7ae", size = 17734, upload-time = "2026-07-17T12:16:46.59Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d4/19/0b6647bf5e331521e55d2b63bfbdc210bd9cd605189273f03614a05f702d/colorlog-6.12.0-py3-none-any.whl", hash = "sha256:30d392604e9110045a2c2aeefc27d7a017abbab63f3a8aee594eac0801df784e", size = 12239, upload-time = "2026-07-23T13:40:39.562Z" }, + { url = "https://files.pythonhosted.org/packages/ec/a1/6b71004ab0fea510230be9ce05a4059029ac847c009fcc80b1b73d6fa5ab/colorlog-6.11.0-py3-none-any.whl", hash = "sha256:f1e27d75aa2cb138f3f640c0e305b65b680ccbef6ecc034eba7e03494ffcd2a1", size = 12016, upload-time = "2026-07-17T12:16:45.3Z" }, ] [[package]] @@ -654,10 +654,10 @@ wheels = [ [[package]] name = "cuda-pathfinder" -version = "1.6.0" +version = "1.5.6" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/b4/d088047afe39827556df21118cac9ffd20cc3f968c99a7681494d1eb333c/cuda_pathfinder-1.6.0-py3-none-any.whl", hash = "sha256:1503af579d8379c24bdd65528379bc57039b0455be9f5f9686cf8e473a1fce51", size = 54591, upload-time = "2026-07-21T15:03:56.224Z" }, + { url = "https://files.pythonhosted.org/packages/d2/53/8fc9b0cdc5b7f62746e6a01b85b6461e5ae27f871010a5fcf8fa6950766d/cuda_pathfinder-1.5.6-py3-none-any.whl", hash = "sha256:7e4c07c117b78ba1fb35dac4c444d21f3677b1b1ff56175c53a8e3025c5b43c0", size = 52972, upload-time = "2026-06-30T00:58:04.34Z" }, ] [[package]] @@ -870,7 +870,7 @@ wheels = [ [[package]] name = "docling-parse" -version = "7.8.1" +version = "7.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "docling-core" }, @@ -878,18 +878,16 @@ dependencies = [ { name = "pydantic" }, { name = "pywin32", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/90/94/33a91dfb849c1c2a645481cbd7b131c92ff6de17e0b01fe584177b1cb82b/docling_parse-7.8.1.tar.gz", hash = "sha256:5bb5ff8e003b9d0a88da9bf1d1f9927c81677dc9dc20815c87ba6e117d1af661", size = 6758311, upload-time = "2026-07-20T04:15:43.003Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7a/28/feffb968ddb332b1d2c2a5d2b9be47e36f9ab8121367ff9781f4ef0f43ae/docling_parse-7.0.0.tar.gz", hash = "sha256:bc7710a13d0e0619ee288499ac163637f9356425781f4bed83c3e6a061cb86d4", size = 6682303, upload-time = "2026-06-22T10:17:58.181Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cf/c4/15af758b4d5ae2c3e6bf1c986558f6cd355340685c3fc0448c031adc96e9/docling_parse-7.8.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:8b7d046008ad37ca9072b8f908f3ae05d984cfe448f4219b342cfb3ca27ff772", size = 9580184, upload-time = "2026-07-20T04:15:13.014Z" }, - { url = "https://files.pythonhosted.org/packages/da/0c/66bb5f201103eeee54698bf45848dd154ebf2882664e4a020a3336b26cca/docling_parse-7.8.1-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2494aeb0ff130effa06c29d194dbb6ead9f4721a7c4b168c7200ba99ffe0812b", size = 10308032, upload-time = "2026-07-20T04:15:14.799Z" }, - { url = "https://files.pythonhosted.org/packages/29/7c/d056ed7e035891e44daa5aa454f5ff1bf2bac2d2b1909ddc666ae3d2068e/docling_parse-7.8.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:724d75d80d24fd41597f00dba38508438e20efafae4f465582332f743e6e7106", size = 10719107, upload-time = "2026-07-20T04:15:16.862Z" }, - { url = "https://files.pythonhosted.org/packages/1b/3b/e0e4ce34fd48974b8140c3970e12ebc52b86155e83556733f04e4b8ee9db/docling_parse-7.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:83b0d782b68c7122f1966bd6a590d7a4e06d33d40722e95fa63288d1f9a713e5", size = 11466873, upload-time = "2026-07-20T04:15:18.863Z" }, - { url = "https://files.pythonhosted.org/packages/4f/6e/ab7d1baca6793ef29039d03132939ed0738db70c978c17fb7cb16eedc31d/docling_parse-7.8.1-cp312-cp312-win_arm64.whl", hash = "sha256:775c493f095fe4fa55e907c87912a875cdc74f4829d4078ead4b2ad0d3e76d7c", size = 8876011, upload-time = "2026-07-20T04:15:20.867Z" }, - { url = "https://files.pythonhosted.org/packages/c6/9d/35e9a445c1ad125f8890d7f6b67e41b1659cea2223e41137f49123d273dd/docling_parse-7.8.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:14efe7e430fc700f8e846fb3db156db5c61da50e8aab488c3d2225d68cabcc3a", size = 9580089, upload-time = "2026-07-20T04:15:22.601Z" }, - { url = "https://files.pythonhosted.org/packages/fc/7f/ce2b358fa8d0b8fd60ef7097cc163fb8114ae6e03efbed56dabdbd3cc284/docling_parse-7.8.1-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1b982f5446d87f852c701ce95e6c88834d282c6102fb283837407f5223e38b8", size = 10308281, upload-time = "2026-07-20T04:15:24.817Z" }, - { url = "https://files.pythonhosted.org/packages/65/b5/f8e64db9e39c1cb3cd6b605f61b100c17a60a49bb8a0d307f91f2cf805c4/docling_parse-7.8.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2a9c5d032b8e975b46cbd7d4f3f1d4c67ba871f0f8e04d1f841f56906a962a9a", size = 10720162, upload-time = "2026-07-20T04:15:26.583Z" }, - { url = "https://files.pythonhosted.org/packages/ba/c9/01a7797577f29ce88de064e1643c5bd9436c64cf12ce74dabeeb0720214c/docling_parse-7.8.1-cp313-cp313-win_amd64.whl", hash = "sha256:fb1e0136ad7e4812cecf5ed0894d147e7ab9db40d58495cbbce3277f51da88fe", size = 11466865, upload-time = "2026-07-20T04:15:29.03Z" }, - { url = "https://files.pythonhosted.org/packages/61/fe/4d1ed910ccb0d68fd478be32892e88e58230e5da0cbe465c4be04a1b364b/docling_parse-7.8.1-cp313-cp313-win_arm64.whl", hash = "sha256:daf8223320b51565a87ac0ee85af5b3a24be2a3b340dfe1934e096fe3f15a603", size = 8876079, upload-time = "2026-07-20T04:15:30.978Z" }, + { url = "https://files.pythonhosted.org/packages/de/8b/ef2c2b7837d01474851f17829404796232e78204aa737a1cce5d29cf6f13/docling_parse-7.0.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:37ef02b683e3a36557d45c9038f4e43cc5a293e544df0ab3ea5db159f5a32b21", size = 9158273, upload-time = "2026-06-22T10:17:33.184Z" }, + { url = "https://files.pythonhosted.org/packages/05/6d/83d0e80bcd87d0810c3ef37d617b24a1af854af84f297a06d126d563b02e/docling_parse-7.0.0-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a453afacbf659133aae4072b708828e3f9c745215d23aeac70620f65ab71e239", size = 9827022, upload-time = "2026-06-22T10:17:35.003Z" }, + { url = "https://files.pythonhosted.org/packages/8d/e8/2be20897f8569d02c93a26390e517c1faa336a566a84a867f5a97ae89c5f/docling_parse-7.0.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da3a005be3e8a58795ab2f75cf2277be933c677c880e9ee58c33506cd69176ea", size = 10209846, upload-time = "2026-06-22T10:17:36.838Z" }, + { url = "https://files.pythonhosted.org/packages/66/a8/2c3054477eb7e171bb5f44eb9792b66c9f27ace2fabde5dcbada56085bda/docling_parse-7.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:ca0411a058ce8ac823dd9b0e665917f3a53ac65b278390e052da868825513cef", size = 10973091, upload-time = "2026-06-22T10:17:39.312Z" }, + { url = "https://files.pythonhosted.org/packages/78/bc/b042eb64a18aabeab11ba16c46df64ac69590feabd267afecb1afc961794/docling_parse-7.0.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:b0982fff0d7a754d7a037bff1a3afd2f2b601dc5fb6f1d5ed7cfc9b24afe7e95", size = 9158220, upload-time = "2026-06-22T10:17:41.44Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5f/387cc3a3c48d7591594f165e997f471fd8958b019faa240ef42a3a1ccc58/docling_parse-7.0.0-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5b9e9807fa8d1705ba589d1b935b8aa506c6260dede8d3c02f31e92fad7930b4", size = 9826867, upload-time = "2026-06-22T10:17:43.242Z" }, + { url = "https://files.pythonhosted.org/packages/4a/67/3bfe88293ae70cba56abb1751649ce9cd6ba2d4c26e9228f1bb6abbe222a/docling_parse-7.0.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fe5d5fcdd098166d0bf4f0b3c449aca26bf736c37fcad02179d61853a31ce4e3", size = 10210039, upload-time = "2026-06-22T10:17:45.155Z" }, + { url = "https://files.pythonhosted.org/packages/c0/fb/88fcc144e438d4588b994af1b71a0a0bc2a6a986f6f9b597fe6e697aa672/docling_parse-7.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:c386c18bb4f7aba42bec227c4efeeb99468a1b5ca3a7886a2dd08dec75d0b5fa", size = 10973044, upload-time = "2026-06-22T10:17:47.557Z" }, ] [[package]] @@ -1011,14 +1009,14 @@ wheels = [ [[package]] name = "faker" -version = "40.36.0" +version = "40.31.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "tzdata", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/98/d2/026af1e002bbc6df534d1f8262b18ec79a974f928e9290bfbfdfe7c7b2af/faker-40.36.0.tar.gz", hash = "sha256:754048c76c03afa7de83eee8f4bcee3cf668cbb7d995f54a4e9678db7f110308", size = 2025903, upload-time = "2026-07-24T21:11:33.088Z" } +sdist = { url = "https://files.pythonhosted.org/packages/74/e1/adf05724d5838fa9fe2ada64bf390bbf37b77e3714189ae9f17a2c6d0470/faker-40.31.0.tar.gz", hash = "sha256:af163a937aec99dca5abaeb94dd5008c51c26c6e9af1a26c8db4b3c4e7ca4403", size = 2024136, upload-time = "2026-07-14T15:33:32.045Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/50/9a/b947ed175ce9a0dcb070ccf3607f0ce8720cfb5ed1a36166a150b2acd5af/faker-40.36.0-py3-none-any.whl", hash = "sha256:82b9497d9cfe017048075bcf969298a74b1b6e39f5e4dad1211085d1133f7b62", size = 2062829, upload-time = "2026-07-24T21:11:31.37Z" }, + { url = "https://files.pythonhosted.org/packages/e0/f5/e427b19d79e241a51ce6fcd69a47e7a9ca791a8bc3da00d91d5be05e1456/faker-40.31.0-py3-none-any.whl", hash = "sha256:bedc97c292a48a6a1bbe471a9076d7395a196421ede1cedde99d5719f6b91027", size = 2061930, upload-time = "2026-07-14T15:33:29.004Z" }, ] [[package]] @@ -1730,11 +1728,11 @@ wheels = [ [[package]] name = "mail-parser" -version = "4.5.0" +version = "4.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4e/4d/5fe2ab8505a0f1fe2160e4fdd42500dac32a7ea41a55709aeb2025ba4dbd/mail_parser-4.5.0.tar.gz", hash = "sha256:9ce06b44332115d43b82ee6d21a77a4e2a25cc42e219efe43730534b70c77a7e", size = 2857302, upload-time = "2026-07-29T21:59:34.568Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9c/6e/2cee08e0d6fbce02a301d5ab72ef5ffe8f47dd59ac3d8ce61324d8a9143a/mail_parser-4.4.0.tar.gz", hash = "sha256:82d2c0fa98a138620feaa87a378af2a2643b2941b2e125d7abfc65dd21094b33", size = 2852896, upload-time = "2026-06-11T06:56:49.789Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/02/fa/acbe2bb6e328703094306ef7e75cb5952233a487f17381cb030e6e640006/mail_parser-4.5.0-py3-none-any.whl", hash = "sha256:27ce06c80d2bf3680bc0a8d4aadef05a4f5ff6ebf13f6a668b8182bdcccdd72e", size = 35857, upload-time = "2026-07-29T21:59:33.587Z" }, + { url = "https://files.pythonhosted.org/packages/26/a7/99dfed167ba728384521acd54fadbb7649ce49333018f42e1f190ed25911/mail_parser-4.4.0-py3-none-any.whl", hash = "sha256:46f7931817660fec4f7723e6f1722e66a9cce44c2daeacbeb9e705078379561f", size = 35504, upload-time = "2026-06-11T06:56:48.348Z" }, ] [[package]] @@ -2383,15 +2381,15 @@ wheels = [ [[package]] name = "odfdo" -version = "3.23.1" +version = "3.24.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "lxml" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/32/7c/77b3ef7ac4074eebd5fea4edd839c0637f2738ac323ee5ba60459b0c4f8e/odfdo-3.23.1.tar.gz", hash = "sha256:86414364d1184f94f7d1788822d9002d402e5b5737fdaa463e9c637a1428baf9", size = 326049, upload-time = "2026-07-22T16:54:06.327Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7c/67/c89cb591f92879292b583309805743b264288e6d173704f2049766221afe/odfdo-3.24.0.tar.gz", hash = "sha256:7a76d2194442e684e6b68cd89a2338e6dcc7183015ff8d4fae0938228106dc01", size = 330847, upload-time = "2026-08-01T12:16:40.85Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/86/57/8a1713d09b3366be82adf51571922afe5ac245e481b9ffbdbf5a0de47509/odfdo-3.23.1-py3-none-any.whl", hash = "sha256:06e4136dcffb5407041a8342b15b15bf874906c190d546551d15bbf20fa3062a", size = 428137, upload-time = "2026-07-22T16:54:04.957Z" }, + { url = "https://files.pythonhosted.org/packages/11/2a/232c324d92e0b637400acbfab3101d43154af88aefe057d29fffb0d89147/odfdo-3.24.0-py3-none-any.whl", hash = "sha256:7d9769a7a110632942d910d4794fe99bde763961a3f14604cd175c06cbba1711", size = 431945, upload-time = "2026-08-01T12:16:39.465Z" }, ] [[package]] @@ -3132,12 +3130,9 @@ wheels = [ [[package]] name = "pylatexenc" -version = "2.11" +version = "2.10" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/52/45/ddb0fb04acf95fe9cf9c369814dbdd08651bd2c9ee455f142651e06f4488/pylatexenc-2.11.tar.gz", hash = "sha256:305a072a99ce736246049c9da05841b9d718c0f7ea8888f5f596cf15cb621053", size = 165743, upload-time = "2026-07-25T17:26:31.534Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/06/3d67bd912ef337aa4856b466121d03f304aa1bb4d804f9298b6227cd227e/pylatexenc-2.11-py2.py3-none-any.whl", hash = "sha256:e78e7391d6c104f1ed150e21cfaa58016cdb50aa54406a2eecb793649ffdfdd0", size = 137533, upload-time = "2026-07-25T17:26:30.141Z" }, -] +sdist = { url = "https://files.pythonhosted.org/packages/5d/ab/34ec41718af73c00119d0351b7a2531d2ebddb51833a36448fc7b862be60/pylatexenc-2.10.tar.gz", hash = "sha256:3dd8fd84eb46dc30bee1e23eaab8d8fb5a7f507347b23e5f38ad9675c84f40d3", size = 162597, upload-time = "2021-04-06T07:56:07.854Z" } [[package]] name = "pylint" @@ -3436,7 +3431,7 @@ wheels = [ [[package]] name = "rapidocr" -version = "3.9.2" +version = "3.9.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorlog" }, @@ -3452,7 +3447,7 @@ dependencies = [ { name = "tqdm" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/55/ed/0ee9b9281986974be9d2406ae0134c8d7c91d2fc613f16ffda9701eeda6f/rapidocr-3.9.2-py3-none-any.whl", hash = "sha256:04d6b8d151f823d930bd91910555f57bea897c0c44fa6794267b94cf9c1ef9a0", size = 27275208, upload-time = "2026-07-21T10:59:01.599Z" }, + { url = "https://files.pythonhosted.org/packages/a0/23/e8d7251c53137b5b66d89e85cb0bc3e6bcfaec9527f29b477ec04389c8b2/rapidocr-3.9.1-py3-none-any.whl", hash = "sha256:600885e4e94e0b427abad394fccb0ec1d3c9118a215ca435bf7680aeae0e292b", size = 27274755, upload-time = "2026-07-02T13:37:00.827Z" }, ] [[package]]