Loading tagthunder/api/routers/queries.py +13 −10 Changes for tagthunder/api/routers/queries.py: 13 added lines, 10 removed lines. Original line number Diff line number Diff line from typing import Optional, Union import fastapi import pydantic import api.configurations.pipeline as algos import api.models.schemas as api_schemas Loading Loading @@ -27,8 +30,8 @@ class AlgorithmQuery(BaseModel): pass class AugmentationQuery(BaseModel): url: HttpUrl class AugmentationQuery(AlgorithmQuery): url: HttpUrl = pydantic.Field(..., description="url", example="https://www.example.com") algorithm: Optional[Queries.AUGMENTATION] = DefaultQuery.AUGMENTATION Loading @@ -48,15 +51,15 @@ class ExtractionQuery(AlgorithmQuery): class VocalizationQuery(AlgorithmQuery): keywords: api_schemas.Keywords segmentation: api_schemas.Segmentation algorithm: Optional[Queries.VOCALIZATION] = DefaultQuery.VOCALIZATION class PipelineQuery(AlgorithmQuery): url: HttpUrl htmlpp: Optional[api_schemas.HTMLPP] recompute: bool = False cleaning: Optional[Queries.CLEANING] = DefaultQuery.CLEANING segmentation: Optional[Queries.SEGMENTATION] = DefaultQuery.SEGMENTATION extraction: Optional[Queries.EXTRACTION] = DefaultQuery.EXTRACTION vocalization: Optional[Queries.VOCALIZATION] = DefaultQuery.VOCALIZATION url: HttpUrl = pydantic.Field(..., description="url", example="https://www.example.com") htmlpp: Optional[api_schemas.HTMLPP] = pydantic.Field(..., description="HTML++", example="") augmentation: Optional[Queries.AUGMENTATION] = None cleaning: Optional[Queries.CLEANING] = None segmentation: Optional[Queries.SEGMENTATION] = None extraction: Optional[Queries.EXTRACTION] = None vocalization: Optional[Queries.VOCALIZATION] = None tagthunder/api/routers/routes.py +49 −6 Changes for tagthunder/api/routers/routes.py: 49 added lines, 6 removed lines. Original line number Diff line number Diff line import base64 import io import typing import fastapi import pydantic Loading Loading @@ -98,21 +102,60 @@ def extraction( async def vocalization( query: queries.VocalizationQuery ): audio = services.AlgorithmServices.vocalization( query.keywords, return services.AlgorithmServices.vocalization( query.segmentation, query.algorithm.name, query.algorithm.parameters.dict() ) return fastapi.responses.StreamingResponse(audio, media_type="audio/mpeg3") @router.post( Routes.PIPELINE, description="Pipeline of TagThunder operations", response_model=schemas.Segmentation # response_class=typing.Union[ # fastapi.responses.StreamingResponse, # fastapi.responses.JSONResponse # ], response_model=typing.Union[ schemas.HTMLP, schemas.HTMLPP, schemas.Segmentation ] ) def pipeline( query: queries.PipelineQuery ): raise NotImplementedError() res = None if query.augmentation is not None: res = services.AlgorithmServices.augmentation( query.url, query.augmentation.name, query.augmentation.parameters.dict() ) if query.cleaning is not None: res = services.AlgorithmServices.cleaning( htmlp=res, algorithm_name=query.cleaning.name, parameters=query.cleaning.parameters.dict() ) if query.segmentation is not None: res = services.AlgorithmServices.segmentation( htmlpp=res, algorithm_name=query.segmentation.name, parameters=query.segmentation.parameters.dict() ) if query.extraction is not None: res = services.AlgorithmServices.extraction( segmentation=res, algorithm_name=query.extraction.name, parameters=query.extraction.parameters.dict() ) if query.vocalization is not None: res = services.AlgorithmServices.vocalization( segmentation=res, algorithm_name=query.vocalization.name, parameters=query.vocalization.parameters.dict() ) return res tagthunder/api/routers/services.py +57 −17 Changes for tagthunder/api/routers/services.py: 57 added lines, 17 removed lines. Original line number Diff line number Diff line import csv import enum import io import zipfile from typing import Optional import fastapi import toolz from pydantic import HttpUrl import api.models.schemas as schemas Loading @@ -12,35 +18,69 @@ class AlgorithmServices: @classmethod def augmentation(cls, url: [HttpUrl], algorithm_name: str, parameters) -> Optional[schemas.HTMLP]: augmentation_block = algorithms_conf.AugmentationBlocks.get_algorithm(algorithm_name) htmlp = augmentation_block(url, **parameters) algorithm = cls.get_algorithm("augmentation", algorithm_name, **parameters) htmlp = algorithm(url) return factories.Responses.HTMLP(htmlp) @classmethod def cleaning(cls, htmlp: schemas.HTMLP, algorithm_name: str, parameters) -> schemas.HTMLPP: cleaning_algorithm = algorithms_conf.CleaningBlocks.get_algorithm(algorithm_name) html_cleaned = cleaning_algorithm(factories.AlgorithmInput.HTMLP(htmlp), **parameters) algorithm = cls.get_algorithm("cleaning", algorithm_name, **parameters) html_cleaned = algorithm(factories.AlgorithmInput.HTMLP(htmlp)) return factories.Responses.HTMLPP(html_cleaned) @classmethod def segmentation(cls, htmlpp: schemas.HTMLPP, algorithm_name: str, parameters) -> schemas.Segmentation: segmentation_algorithm = algorithms_conf.SegmentationBlocks.get_algorithm(algorithm_name) segmentation = segmentation_algorithm( factories.AlgorithmInput.HTMLPP(htmlpp), **parameters ) algorithm = cls.get_algorithm("segmentation", algorithm_name, **parameters) segmentation = algorithm(factories.AlgorithmInput.HTMLPP(htmlpp)) return factories.Responses.Segmentation(segmentation) @classmethod def extraction(cls, segmentation: schemas.Segmentation, algorithm_name: str, parameters) -> schemas.Segmentation: extraction_algorithm = algorithms_conf.ExtractionBlocks.get_algorithm(algorithm_name) segmentation = extraction_algorithm(factories.AlgorithmInput.Segmentation(segmentation), **parameters) algorithm = cls.get_algorithm("extraction", algorithm_name, **parameters) segmentation = algorithm(factories.AlgorithmInput.Segmentation(segmentation)) return factories.Responses.Segmentation(segmentation) @classmethod def vocalization(cls, keywords: schemas.Keywords, algorithm_name: str, parameters) -> io.BytesIO: vocalization_algorithm = algorithms_conf.VocalizationBlocks.get_algorithm(algorithm_name) return vocalization_algorithm(factories.AlgorithmInput.Keywords(keywords), **parameters) def vocalization(cls, segmentation: schemas.Segmentation, algorithm_name: str, parameters) -> fastapi.responses.StreamingResponse: algorithm = cls.get_algorithm("vocalization", algorithm_name, **parameters) vocalization = algorithm(factories.AlgorithmInput.Segmentation(segmentation)) # for f in vocalization: # play_song(f) zip = MiscServices.zip_files( files=vocalization, file_name_func=lambda file: f"zone_{file.zone_id}.wav" ) response = fastapi.responses.StreamingResponse(iter([zip.getvalue()]), media_type="application/x-zip-compressed") response.headers["Content-Disposition"] = "attachment; filename=vocalization.zip" return response @classmethod def get_algorithm(cls, block_type, name, **parameters): algo = algorithms_conf.pipeline_blocks[block_type].get_algorithm(name) parameters = cls.prepare_parameters(parameters) algo.config(**parameters) return algo @classmethod def prepare_parameters(cls, parameters): def manage_enum(value): if isinstance(value, enum.Enum): return value.value return value return toolz.valmap(manage_enum, parameters) class MiscServices: @classmethod def zip_files(cls, files, file_name_func): zipped_file = io.BytesIO() with zipfile.ZipFile(zipped_file, "a", zipfile.ZIP_DEFLATED) as zipped: for i, f in enumerate(files): f.seek(0) zipped.writestr(file_name_func(f), f.read()) zipped_file.seek(0) return zipped_file Loading
tagthunder/api/routers/queries.py +13 −10 Changes for tagthunder/api/routers/queries.py: 13 added lines, 10 removed lines. Original line number Diff line number Diff line from typing import Optional, Union import fastapi import pydantic import api.configurations.pipeline as algos import api.models.schemas as api_schemas Loading Loading @@ -27,8 +30,8 @@ class AlgorithmQuery(BaseModel): pass class AugmentationQuery(BaseModel): url: HttpUrl class AugmentationQuery(AlgorithmQuery): url: HttpUrl = pydantic.Field(..., description="url", example="https://www.example.com") algorithm: Optional[Queries.AUGMENTATION] = DefaultQuery.AUGMENTATION Loading @@ -48,15 +51,15 @@ class ExtractionQuery(AlgorithmQuery): class VocalizationQuery(AlgorithmQuery): keywords: api_schemas.Keywords segmentation: api_schemas.Segmentation algorithm: Optional[Queries.VOCALIZATION] = DefaultQuery.VOCALIZATION class PipelineQuery(AlgorithmQuery): url: HttpUrl htmlpp: Optional[api_schemas.HTMLPP] recompute: bool = False cleaning: Optional[Queries.CLEANING] = DefaultQuery.CLEANING segmentation: Optional[Queries.SEGMENTATION] = DefaultQuery.SEGMENTATION extraction: Optional[Queries.EXTRACTION] = DefaultQuery.EXTRACTION vocalization: Optional[Queries.VOCALIZATION] = DefaultQuery.VOCALIZATION url: HttpUrl = pydantic.Field(..., description="url", example="https://www.example.com") htmlpp: Optional[api_schemas.HTMLPP] = pydantic.Field(..., description="HTML++", example="") augmentation: Optional[Queries.AUGMENTATION] = None cleaning: Optional[Queries.CLEANING] = None segmentation: Optional[Queries.SEGMENTATION] = None extraction: Optional[Queries.EXTRACTION] = None vocalization: Optional[Queries.VOCALIZATION] = None
tagthunder/api/routers/routes.py +49 −6 Changes for tagthunder/api/routers/routes.py: 49 added lines, 6 removed lines. Original line number Diff line number Diff line import base64 import io import typing import fastapi import pydantic Loading Loading @@ -98,21 +102,60 @@ def extraction( async def vocalization( query: queries.VocalizationQuery ): audio = services.AlgorithmServices.vocalization( query.keywords, return services.AlgorithmServices.vocalization( query.segmentation, query.algorithm.name, query.algorithm.parameters.dict() ) return fastapi.responses.StreamingResponse(audio, media_type="audio/mpeg3") @router.post( Routes.PIPELINE, description="Pipeline of TagThunder operations", response_model=schemas.Segmentation # response_class=typing.Union[ # fastapi.responses.StreamingResponse, # fastapi.responses.JSONResponse # ], response_model=typing.Union[ schemas.HTMLP, schemas.HTMLPP, schemas.Segmentation ] ) def pipeline( query: queries.PipelineQuery ): raise NotImplementedError() res = None if query.augmentation is not None: res = services.AlgorithmServices.augmentation( query.url, query.augmentation.name, query.augmentation.parameters.dict() ) if query.cleaning is not None: res = services.AlgorithmServices.cleaning( htmlp=res, algorithm_name=query.cleaning.name, parameters=query.cleaning.parameters.dict() ) if query.segmentation is not None: res = services.AlgorithmServices.segmentation( htmlpp=res, algorithm_name=query.segmentation.name, parameters=query.segmentation.parameters.dict() ) if query.extraction is not None: res = services.AlgorithmServices.extraction( segmentation=res, algorithm_name=query.extraction.name, parameters=query.extraction.parameters.dict() ) if query.vocalization is not None: res = services.AlgorithmServices.vocalization( segmentation=res, algorithm_name=query.vocalization.name, parameters=query.vocalization.parameters.dict() ) return res
tagthunder/api/routers/services.py +57 −17 Changes for tagthunder/api/routers/services.py: 57 added lines, 17 removed lines. Original line number Diff line number Diff line import csv import enum import io import zipfile from typing import Optional import fastapi import toolz from pydantic import HttpUrl import api.models.schemas as schemas Loading @@ -12,35 +18,69 @@ class AlgorithmServices: @classmethod def augmentation(cls, url: [HttpUrl], algorithm_name: str, parameters) -> Optional[schemas.HTMLP]: augmentation_block = algorithms_conf.AugmentationBlocks.get_algorithm(algorithm_name) htmlp = augmentation_block(url, **parameters) algorithm = cls.get_algorithm("augmentation", algorithm_name, **parameters) htmlp = algorithm(url) return factories.Responses.HTMLP(htmlp) @classmethod def cleaning(cls, htmlp: schemas.HTMLP, algorithm_name: str, parameters) -> schemas.HTMLPP: cleaning_algorithm = algorithms_conf.CleaningBlocks.get_algorithm(algorithm_name) html_cleaned = cleaning_algorithm(factories.AlgorithmInput.HTMLP(htmlp), **parameters) algorithm = cls.get_algorithm("cleaning", algorithm_name, **parameters) html_cleaned = algorithm(factories.AlgorithmInput.HTMLP(htmlp)) return factories.Responses.HTMLPP(html_cleaned) @classmethod def segmentation(cls, htmlpp: schemas.HTMLPP, algorithm_name: str, parameters) -> schemas.Segmentation: segmentation_algorithm = algorithms_conf.SegmentationBlocks.get_algorithm(algorithm_name) segmentation = segmentation_algorithm( factories.AlgorithmInput.HTMLPP(htmlpp), **parameters ) algorithm = cls.get_algorithm("segmentation", algorithm_name, **parameters) segmentation = algorithm(factories.AlgorithmInput.HTMLPP(htmlpp)) return factories.Responses.Segmentation(segmentation) @classmethod def extraction(cls, segmentation: schemas.Segmentation, algorithm_name: str, parameters) -> schemas.Segmentation: extraction_algorithm = algorithms_conf.ExtractionBlocks.get_algorithm(algorithm_name) segmentation = extraction_algorithm(factories.AlgorithmInput.Segmentation(segmentation), **parameters) algorithm = cls.get_algorithm("extraction", algorithm_name, **parameters) segmentation = algorithm(factories.AlgorithmInput.Segmentation(segmentation)) return factories.Responses.Segmentation(segmentation) @classmethod def vocalization(cls, keywords: schemas.Keywords, algorithm_name: str, parameters) -> io.BytesIO: vocalization_algorithm = algorithms_conf.VocalizationBlocks.get_algorithm(algorithm_name) return vocalization_algorithm(factories.AlgorithmInput.Keywords(keywords), **parameters) def vocalization(cls, segmentation: schemas.Segmentation, algorithm_name: str, parameters) -> fastapi.responses.StreamingResponse: algorithm = cls.get_algorithm("vocalization", algorithm_name, **parameters) vocalization = algorithm(factories.AlgorithmInput.Segmentation(segmentation)) # for f in vocalization: # play_song(f) zip = MiscServices.zip_files( files=vocalization, file_name_func=lambda file: f"zone_{file.zone_id}.wav" ) response = fastapi.responses.StreamingResponse(iter([zip.getvalue()]), media_type="application/x-zip-compressed") response.headers["Content-Disposition"] = "attachment; filename=vocalization.zip" return response @classmethod def get_algorithm(cls, block_type, name, **parameters): algo = algorithms_conf.pipeline_blocks[block_type].get_algorithm(name) parameters = cls.prepare_parameters(parameters) algo.config(**parameters) return algo @classmethod def prepare_parameters(cls, parameters): def manage_enum(value): if isinstance(value, enum.Enum): return value.value return value return toolz.valmap(manage_enum, parameters) class MiscServices: @classmethod def zip_files(cls, files, file_name_func): zipped_file = io.BytesIO() with zipfile.ZipFile(zipped_file, "a", zipfile.ZIP_DEFLATED) as zipped: for i, f in enumerate(files): f.seek(0) zipped.writestr(file_name_func(f), f.read()) zipped_file.seek(0) return zipped_file