diff --git a/.idea/asr-benchmarks.iml b/.idea/asr-benchmarks.iml index de5fcde38002e8a5d853278c1c1dbc5c302a7115..816680ee8b03340b4763439bf165105b558a849b 100644 --- a/.idea/asr-benchmarks.iml +++ b/.idea/asr-benchmarks.iml @@ -4,7 +4,7 @@ <content url="file://$MODULE_DIR$"> <excludeFolder url="file://$MODULE_DIR$/venv" /> </content> - <orderEntry type="inheritedJdk" /> + <orderEntry type="jdk" jdkName="Poetry (asr-benchmarks) (2)" jdkType="Python SDK" /> <orderEntry type="sourceFolder" forTests="false" /> </component> <component name="PyDocumentationSettings"> diff --git a/.idea/misc.xml b/.idea/misc.xml index e4cf2e31963eccaa9c43fcc4a2c9d0ee8396d9be..060748f024f206a8a3ef8a3ff47ea9ad3dcefc0a 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,4 @@ <?xml version="1.0" encoding="UTF-8"?> <project version="4"> - <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9 (asr-benchmarks)" project-jdk-type="Python SDK" /> + <component name="ProjectRootManager" version="2" project-jdk-name="Poetry (asr-benchmarks) (2)" project-jdk-type="Python SDK" /> </project> \ No newline at end of file diff --git a/docker/ajn_asr/Dockerfile b/docker/ajn_asr/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..e9190202268fc6d25025498ce8b486c736ddc59b --- /dev/null +++ b/docker/ajn_asr/Dockerfile @@ -0,0 +1,25 @@ +FROM danijel3/clarin-pl-speechtools:pkf +ENV PATH="/root/miniconda3/bin:${PATH}" +ARG PATH="/root/miniconda3/bin:${PATH}" +# RUN python3 --version +RUN mkdir /data +RUN mkdir /data/processing_flask +ADD requirements.txt . +RUN apt-get update && apt-get install -y curl wget +RUN rm -rf /var/lib/apt/lists/* + +RUN wget \ + https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh \ + && mkdir /root/.conda \ + && bash Miniconda3-latest-Linux-x86_64.sh -b \ + && rm -f Miniconda3-latest-Linux-x86_64.sh +RUN conda --version +# RUN bash Miniconda3-py39_4.9.2-Linux-x86_64.sh +RUN pip install -i https://pypi.clarin-pl.eu/simple -r requirements.txt +RUN rm requirements.txt +RUN ls -l + +ADD main.py . + +CMD ["python3", "-u", "main.py"] +ENTRYPOINT ["python3", "-u", "main.py"] diff --git a/docker/ajn_asr/main.py b/docker/ajn_asr/main.py new file mode 100644 index 0000000000000000000000000000000000000000..37459f0c10fcefd3f2d19ab655c9b4ac3ec87559 --- /dev/null +++ b/docker/ajn_asr/main.py @@ -0,0 +1,40 @@ +import os +import uuid + +from sziszapangma.integration.service_core.asr.asr_base_processor import AsrBaseProcessor +from sziszapangma.integration.service_core.asr.asr_result import AsrResult + + +class SpeechbrainAsrProcessor(AsrBaseProcessor): + + def process_asr(self, audio_file_path: str) -> AsrResult: + # prepare paths + file_tag = str(uuid.uuid4()) + file_extension = audio_file_path.split('.')[-1] + file_name = f'{file_tag}.{file_extension}' + result_file_path = f'processing_flask/{file_tag}.txt' + file_path = f'processing_flask/{file_name}' + # create file in /data/uuid.ext + os.system(f"cp {audio_file_path} /data/{file_path}") + + command = f'/tools/Recognize/run.sh {file_path} {result_file_path}' + print(f'run {command}') + os.system(command) + with open(f'/data/{result_file_path}', 'r') as f: + transcription = f.read() + + transcription = transcription.replace('\n', ' ') + + # remove temp file + os.remove(f'/data/{file_path}') + os.remove(f'/data/{result_file_path}') + + return AsrResult( + words=[it for it in transcription.split(' ')], + full_text=transcription, + words_time_alignment=None + ) + + +if __name__ == '__main__': + SpeechbrainAsrProcessor().start_processor() diff --git a/docker/ajn_asr/prepare_docker.sh b/docker/ajn_asr/prepare_docker.sh new file mode 100755 index 0000000000000000000000000000000000000000..a47ad1318644338f1a3fc241fad3bb6cb58c0c67 --- /dev/null +++ b/docker/ajn_asr/prepare_docker.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" + +docker build -t asr-clarin-pl-service "$SCRIPT_DIR" +docker tag asr-clarin-pl-service docker-registry.theliver.pl/asr-clarin-pl-service:1.4 +docker push docker-registry.theliver.pl/asr-clarin-pl-service:1.4 diff --git a/docker/ajn_asr/requirements.txt b/docker/ajn_asr/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..0fbe5a72ff22184edbe1aac33f3390401c441599 --- /dev/null +++ b/docker/ajn_asr/requirements.txt @@ -0,0 +1 @@ +asr-benchmarks==0.0.1-alpha.48 diff --git a/docker/build-all-dockers.sh b/docker/build-all-dockers.sh new file mode 100644 index 0000000000000000000000000000000000000000..5f0afa7d4d31e8ae5c6bb33574f949207a7c8bf6 --- /dev/null +++ b/docker/build-all-dockers.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" + +"$SCRIPT_DIR"/ajn_asr/prepare_docker.sh +"$SCRIPT_DIR"/fasttext_embedding/prepare_docker.sh +"$SCRIPT_DIR"/polish_asr_hf/prepare_docker.sh +"$SCRIPT_DIR"/speechbrain_asr/prepare_docker.sh +"$SCRIPT_DIR"/techmo_asr/prepare_docker.sh diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000000000000000000000000000000000000..47ac2cbfbd89275d1e6622c0c17492ec3d381041 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,68 @@ +version: "3.8" +services: + + techmo_asr: + image: docker-registry.theliver.pl/techmo-asr:1.1 + container_name: techmo_asr + restart: always + ports: + - 5001:5000 + volumes: + - /etc/localtime:/etc/localtime:ro + - /home/marcinwatroba/.ssh/keys/techmo_asr_server:/keys/techmo_rsa_key:ro + environment: + - TECHMO_SSH_SERVER_USERNAME=mwatroba + - TECHMO_SSH_SERVER_URL=jankocon.clarin-pl.eu + - TECHMO_SERVER_SSH_PORT=9222 + - TECHMO_REMOTE_SERVICE_PORT=12321 + - TECHMO_SERVER_URL=156.17.135.34 + - AUTH_TOKEN=t8sv-9bwd-6rps-rs9u + + transformers-wav2vec2for_ctc: + image: docker-registry.theliver.pl/transformers-wav2vec2for_ctc:1.0 + container_name: transformers-wav2vec2for_ctc + restart: always + volumes: + - /etc/localtime:/etc/localtime:ro + - ./wav2vec2for_ctc_models:/models + ports: + - 5002:5000 + environment: + - AUTH_TOKEN=x42s-qz8u-baa4-d354 + - MODEL_NAME=jonatasgrosman/wav2vec2-large-xlsr-53-polish + - SAMPLING_RATE=16000 + + embedding_service: + image: docker-registry.theliver.pl/embedding_docker:1.0 + container_name: embeddings_service + restart: always + ports: + - 5003:5000 + environment: + - AUTH_TOKEN=fjsd-mkwe-oius-m9h2 + volumes: + - /etc/localtime:/etc/localtime:ro + - ./embedding_models:/models + + ajn_asr: + image: docker-registry.theliver.pl/asr-clarin-pl-service:1.4 + container_name: ajn_asr + restart: always + ports: + - 5004:5000 + environment: + - AUTH_TOKEN=am43-649g-gwa3-b9wj + volumes: + - /etc/localtime:/etc/localtime:ro + + speechbrain_asr: + image: docker-registry.theliver.pl/speechbrain-asr:1.5 + container_name: speechbrain_asr + restart: always + ports: + - 5005:5000 + volumes: + - /etc/localtime:/etc/localtime:ro + - ./speechbrain_asr_models:/models + environment: + - AUTH_TOKEN=gwa3-b9wj-am43-649g diff --git a/docker/fasttext_embedding/Dockerfile b/docker/fasttext_embedding/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..25638acefa610a1d41d58681db82c0872de5bec3 --- /dev/null +++ b/docker/fasttext_embedding/Dockerfile @@ -0,0 +1,10 @@ +FROM python:3.9 + +WORKDIR /app + +COPY requirements.txt requirements.txt +RUN pip install -i https://pypi.clarin-pl.eu/simple -r requirements.txt && rm requirements.txt + +COPY main.py main.py + +CMD ["python3", "-u", "main.py"] diff --git a/docker/fasttext_embedding/main.py b/docker/fasttext_embedding/main.py new file mode 100644 index 0000000000000000000000000000000000000000..7b0d2c22ef3d7d6d2645f13e03d3672f4589826e --- /dev/null +++ b/docker/fasttext_embedding/main.py @@ -0,0 +1,43 @@ +import os +import shutil +from typing import Dict + +import fasttext +import fasttext.util +import numpy as np +from fasttext.FastText import _FastText +from numpy import typing as npt +from sziszapangma.integration.service_core.embedding.embedding_base_processor \ + import EmbeddingBaseProcessor + + +class FasttextWebEmbeddingTransformer(EmbeddingBaseProcessor): + _models = Dict[str, _FastText] + + def __init__(self): + super().__init__() + self._models = dict() + + def get_embedding(self, phrase: str, language: str) -> npt.NDArray[np.float64]: + return self.get_model(language).get_word_vector(phrase) + + def get_model(self, language: str) -> _FastText: + if language not in self._models: + print(f'load model {language}') + model_filename = f'cc.{language}.300.bin' + model_path = f'/models/{model_filename}' + print(f'{model_filename} {model_path}') + if not os.path.exists(model_path): + full_model_name = fasttext.util.download_model(language, + if_exists='ignore') + shutil.move(full_model_name, f'/models/{full_model_name}') + print(f'downloaded {full_model_name}') + self._models[language] = fasttext.load_model(model_path) + return self._models[language] + + +if __name__ == '__main__': + transformer = FasttextWebEmbeddingTransformer() + transformer.get_model('pl') + transformer.get_model('en') + transformer.start_processor() diff --git a/docker/fasttext_embedding/prepare_docker.sh b/docker/fasttext_embedding/prepare_docker.sh new file mode 100755 index 0000000000000000000000000000000000000000..2e32082b2bc8883631ff748eb8f67a8c7bae1067 --- /dev/null +++ b/docker/fasttext_embedding/prepare_docker.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" + +docker build -t embedding_docker "$SCRIPT_DIR" +docker tag embedding_docker docker-registry.theliver.pl/embedding_docker:1.0 +docker push docker-registry.theliver.pl/embedding_docker:1.0 diff --git a/docker/fasttext_embedding/requirements.txt b/docker/fasttext_embedding/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..8fde735421f5290cc49c89464d1516034e82bc77 --- /dev/null +++ b/docker/fasttext_embedding/requirements.txt @@ -0,0 +1,2 @@ +fasttext>=0.9.2 +asr-benchmarks==0.0.1-alpha.48 diff --git a/docker/polish_asr_hf/Dockerfile b/docker/polish_asr_hf/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..1f7c1cc8505cb69e1b27199d618039c8d5b8fea5 --- /dev/null +++ b/docker/polish_asr_hf/Dockerfile @@ -0,0 +1,12 @@ +FROM python:3.9 + +WORKDIR /app + +RUN apt-get update && apt-get install -y libsndfile1 && apt-get clean + +COPY requirements.txt requirements.txt +RUN pip install -i https://pypi.clarin-pl.eu/simple -r requirements.txt && rm requirements.txt + +COPY main.py main.py + +CMD ["python3", "-u", "main.py"] diff --git a/docker/polish_asr_hf/docker-compose.yml b/docker/polish_asr_hf/docker-compose.yml new file mode 100644 index 0000000000000000000000000000000000000000..af06bb6745df2378751b2b42247ca63826fd5d4a --- /dev/null +++ b/docker/polish_asr_hf/docker-compose.yml @@ -0,0 +1,13 @@ +version: "3.8" +services: + transformers-wav2vec2for_ctc: + image: docker-registry.theliver.pl/transformers-wav2vec2for_ctc:1.0 + container_name: transformers-wav2vec2for_ctc + volumes: + - ./models:/models + ports: + - 5003:5000 + environment: + - AUTH_TOKEN=test1234 + - MODEL_ID=jonatasgrosman/wav2vec2-large-xlsr-53-polish + - SAMPLING_RATE=16000 \ No newline at end of file diff --git a/docker/polish_asr_hf/main.py b/docker/polish_asr_hf/main.py new file mode 100644 index 0000000000000000000000000000000000000000..bcebeb8c44f25795078a8b10a11d9620bd9d5503 --- /dev/null +++ b/docker/polish_asr_hf/main.py @@ -0,0 +1,47 @@ +import os +import warnings + +import librosa +import torch +from sziszapangma.integration.service_core.asr.asr_base_processor import AsrBaseProcessor +from sziszapangma.integration.service_core.asr.asr_result import AsrResult +from transformers import Wav2Vec2ForCTC, Wav2Vec2Processor + +warnings.filterwarnings("ignore") + + +# MODEL_ID = "jonatasgrosman/wav2vec2-large-xlsr-53-polish" +# SAMPLING_RATE = 16_000 + + +class SpeechbrainAsrProcessor(AsrBaseProcessor): + _model_id: str + _processor: Wav2Vec2Processor + _model: Wav2Vec2ForCTC + _sampling_rate: int + + def __init__(self, model_id: str, sampling_rate: int): + super().__init__() + self._model_id = model_id + self._sampling_rate = sampling_rate + self._processor = Wav2Vec2Processor.from_pretrained(model_id, cache_dir='/models') + self._model = Wav2Vec2ForCTC.from_pretrained(model_id, cache_dir='/models') + + def process_asr(self, audio_file_path: str) -> AsrResult: + speech_array, sampling_rate = librosa.load(audio_file_path, sr=self._sampling_rate) + inputs = self._processor([speech_array], sampling_rate=sampling_rate, return_tensors="pt", + padding=True) + with torch.no_grad(): + logits = self._model(inputs.input_values, attention_mask=inputs.attention_mask).logits + predicted_ids = torch.argmax(logits, dim=-1) + predicted_sentences = self._processor.batch_decode(predicted_ids) + transcription = predicted_sentences[0] + return AsrResult(words=transcription.split(' '), full_text=transcription, + words_time_alignment=None) + + +if __name__ == '__main__': + SpeechbrainAsrProcessor( + os.environ['MODEL_NAME'], + int(os.environ['SAMPLING_RATE']) + ).start_processor() diff --git a/docker/polish_asr_hf/prepare_docker.sh b/docker/polish_asr_hf/prepare_docker.sh new file mode 100755 index 0000000000000000000000000000000000000000..c305c346eddbc44bcd4fa287bb835ac07eb221e6 --- /dev/null +++ b/docker/polish_asr_hf/prepare_docker.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" + +docker build -t transformers-wav2vec2for_ctc "$SCRIPT_DIR" +docker tag transformers-wav2vec2for_ctc docker-registry.theliver.pl/transformers-wav2vec2for_ctc:1.0 +docker push docker-registry.theliver.pl/transformers-wav2vec2for_ctc:1.0 diff --git a/docker/polish_asr_hf/requirements.txt b/docker/polish_asr_hf/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..4ddd7ae173e0308fe5d2fd491e047ed3cc359e79 --- /dev/null +++ b/docker/polish_asr_hf/requirements.txt @@ -0,0 +1,6 @@ +torchaudio +datasets +transformers +asrp +asr-benchmarks==0.0.1-alpha.48 +librosa \ No newline at end of file diff --git a/docker/speechbrain_asr/Dockerfile b/docker/speechbrain_asr/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..18948628cab2fdb8706f135c0eeb8be45e198ff4 --- /dev/null +++ b/docker/speechbrain_asr/Dockerfile @@ -0,0 +1,11 @@ +FROM python:3.9 + +WORKDIR /app + +ADD requirements.txt . +RUN pip install -i https://pypi.clarin-pl.eu/simple -r requirements.txt +RUN rm requirements.txt +ADD main.py . +RUN mkdir asr_processing + +CMD ["python3", "-u", "main.py"] diff --git a/docker/speechbrain_asr/main.py b/docker/speechbrain_asr/main.py new file mode 100644 index 0000000000000000000000000000000000000000..32679abc1034827f8d836152326dcc539b2df960 --- /dev/null +++ b/docker/speechbrain_asr/main.py @@ -0,0 +1,26 @@ +import os + +from speechbrain.pretrained import EncoderDecoderASR +from sziszapangma.integration.service_core.asr.asr_base_processor import AsrBaseProcessor +from sziszapangma.integration.service_core.asr.asr_result import AsrResult + + +class SpeechbrainAsrProcessor(AsrBaseProcessor): + asr_model: EncoderDecoderASR + + def __init__(self): + super().__init__() + self.asr_model = EncoderDecoderASR.from_hparams( + source="speechbrain/asr-transformer-transformerlm-librispeech" + ) + + def process_asr(self, audio_file_path: str) -> AsrResult: + transcription = self.asr_model.transcribe_file(audio_file_path) + os.remove(audio_file_path) + words = [it.lower() for it in transcription.split(' ')] + final_transcription = transcription.lower() + return AsrResult(words=words, full_text=final_transcription, words_time_alignment=None) + + +if __name__ == '__main__': + SpeechbrainAsrProcessor().start_processor() diff --git a/docker/speechbrain_asr/prepare_docker.sh b/docker/speechbrain_asr/prepare_docker.sh new file mode 100755 index 0000000000000000000000000000000000000000..1731522f1854abc6abcf0ec6dbc3dd2191b86d5b --- /dev/null +++ b/docker/speechbrain_asr/prepare_docker.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" + +docker build --no-cache -t speechbrain-asr "$SCRIPT_DIR" +docker tag speechbrain-asr docker-registry.theliver.pl/speechbrain-asr:1.5 +docker push docker-registry.theliver.pl/speechbrain-asr:1.5 diff --git a/docker/speechbrain_asr/requirements.txt b/docker/speechbrain_asr/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..9fe7783640fcb45493056873358a8aa59f0ee317 --- /dev/null +++ b/docker/speechbrain_asr/requirements.txt @@ -0,0 +1,2 @@ +asr-benchmarks==0.0.1-alpha.48 +speechbrain diff --git a/docker/techmo_asr/Dockerfile b/docker/techmo_asr/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..72e93ed096dfb87df2cbd32de594c93a0df2410b --- /dev/null +++ b/docker/techmo_asr/Dockerfile @@ -0,0 +1,23 @@ +FROM python:3.9-slim + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get update \ + && apt-get dist-upgrade -y \ + && apt-get install -y --no-install-recommends \ + build-essential \ + portaudio19-dev \ + openssh-client \ + python3-pip \ + python3-dev \ + && apt-get clean \ + && rm -fr /var/lib/apt/lists/* \ + && rm -fr /var/cache/apt/* + +ADD ./python /dictation_client + +WORKDIR /dictation_client + +RUN pip3 install -i https://pypi.clarin-pl.eu/simple -r requirements.txt + +CMD ["./run_web_service.sh"] diff --git a/docker/techmo_asr/docker-compose.yml b/docker/techmo_asr/docker-compose.yml new file mode 100644 index 0000000000000000000000000000000000000000..f9291fe8b156462948c17189af04c0b3b83ee870 --- /dev/null +++ b/docker/techmo_asr/docker-compose.yml @@ -0,0 +1,15 @@ +version: "3.8" +services: + + techmo_asr: + image: docker-registry.theliver.pl/techmo-asr:1.1 + container_name: techmo_asr + environment: + - TECHMO_SSH_SERVER_USERNAME=mwatroba + - TECHMO_SSH_SERVER_URL=jankocon.clarin-pl.eu + - TECHMO_SERVER_SSH_PORT=9222 + - TECHMO_REMOTE_SERVICE_PORT=12321 + - TECHMO_SERVER_URL=156.17.135.34 + - AUTH_TOKEN=test1234 + volumes: + - /Users/marcinwatroba/Desktop/WUST/KEYS/techmo_asr_server:/keys diff --git a/docker/techmo_asr/prepare_docker.sh b/docker/techmo_asr/prepare_docker.sh new file mode 100755 index 0000000000000000000000000000000000000000..0af4b816df543f0292a0e7f2317ea72a23e23129 --- /dev/null +++ b/docker/techmo_asr/prepare_docker.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" + +docker build -t techmo-asr "$SCRIPT_DIR" +docker tag techmo-asr docker-registry.theliver.pl/techmo-asr:1.1 +docker push docker-registry.theliver.pl/techmo-asr:1.1 diff --git a/docker/techmo_asr/python/README.md b/docker/techmo_asr/python/README.md new file mode 100755 index 0000000000000000000000000000000000000000..b34bd0fae8c0904251c739969baf2c0256c10ca2 --- /dev/null +++ b/docker/techmo_asr/python/README.md @@ -0,0 +1,289 @@ +# Python implementation of Dictation ASR gRPC client. + +## Docker usage + +### Build docker image + +To prepare a docker image with Python implementation of the Dictation Client, open the project's main directory and run following command: + +``` +docker build -f Dockerfile-python -t dictation-client-python:2.3.0 . +``` +The build process will take several minutes. +When the build process is complete, you will receive a message: +``` +Successfully tagged dictation-client-python:2.3.0 +``` + +### Run Dictation client + +To use the Dictation Client on Docker container, go to the `dictation-client/python/docker` directory and run `run_dictation_client_python.sh` script. + +To send a simple request to the Dictation service, use: +``` +./run_dictation_client_python.sh --service-address IP_ADDRESS:PORT --filename WAV_FILE_NAME +``` + +To print the list of available options, use: +``` +./run_dictation_client_python.sh --help +``` +Audio files to be transcribed should be placed inside the `dictation-client/python/docker/wav` directory. +TLS credentials should be placed inside the `dictation-client/python/docker/tls` directory, if used. + + + +## Local instance usage + +### Basic Usage + +Dictation Client includes a scripts for automatic environment configuration and launching on systems from the Debian Linux family. For launching the Dictation Client on other Linux-based OS or Windows, check out the "Manual Usage" section. + + +#### Before run + +To install required dependencies and to prepare virtual environment, run: +``` +./setup.sh +``` + +#### Run + +To run the Dictation Client, use the `run.sh` script, e.g.: +``` +./run --service-address IP_ADDRESS:PORT --wave-path INPUT_WAVE +``` +To print the usage description, use: +``` +./run --help +``` + + +### Manual Usage + +#### Before run + +##### Submodules + +After cloning a git repository, download submodules: +``` +git submodule update --init --recursive +``` +(this command has to be invoked from the project's root directory) + +If you are not using git, you have to manually download `googleapis` submodule. +To do this, open project repository in web browser, go to the `submodules` directory and use the link located there to open the relevant commit in the googleapis repository. Then download it, unpack and copy all files to the `submodules/googleapis` directory. + + +##### Dependencies + +If you don't have virtualenv yet, install it first (https://virtualenv.pypa.io/en/stable/installation.html) +On Debian/Ubuntu OS this package can be installed by using `setup.sh` script. + +Then install the required dependencies inside the virtual environment (this step only needs to be done the first time, for the further usage it is enough to use the existing virtual environment). + + +- On Linux: + +Use Python 3 with the virtual environment and install required packages (supported Python versions are: 3.5, 3.6, 3.7, 3.8, 3.9): + +``` +virtualenv -p python3 .env +source .env/bin/activate +pip install -r requirements.txt +``` + +- On Windows 10: + +Temporarily change the PowerShell's execution policy to allow scripting. Start the PowerShell with `Run as Administrator` and use command: + +``` +Set-ExecutionPolicy RemoteSigned +``` +then confirm your choice. + +Use Python 3 with virtual environment and install required packages (supported Python versions are: 3.5, 3.6, 3.7, 3.8, 3.9): + +``` +virtualenv -p python3 .env +.\.env\Scripts\activate +pip install -r requirements.txt +``` + +To switch back PowerShell's execution policy to the default, use command: + +``` +Set-ExecutionPolicy Restricted +``` + +##### Proto sources + +[Optional] To regenerate the sources from `.proto`, run: +``` +./make_proto.sh +``` +This might be required when using other gRPC or Protocol Buffers version. + + + +#### Run + +To run the Dictation Client, activate the virtual environment first: +- On Linux: +``` +source .env/bin/activate +``` +- On Windows: +``` +.\.env\Scripts\activate +``` +Then run Dictation Client. Sample use: + +``` +python dictation_client.py --service-address "192.168.1.1:4321" --wave-path audio.wav +``` + +For each request you have to provide the service address and the audio source (wav file or microphone). + + +## Usage: +``` +Basic usage: dictation_client.py --service-address ADDRESS --wave-path WAVE +``` + +Available options: +``` + -h, --help show this help message and exit + --service-address ADDRESS + IP address and port (address:port) of a service the + client will connect to. + --ssl-dir SSL_DIRECTORY + If set to a path with ssl credential files + (client.crt, client.key, ca.crt), use ssl + authentication. Otherwise use insecure channel + (default). + --wave-path WAVE Path to wave file with speech to be recognized. Should + be mono, 8kHz or 16kHz. + --mic Use microphone as an audio source (instead of wave + file). + --session-id SESSION_ID + Session ID to be passed to the service. If not + specified, the service will generate a default session + ID itself. + --grpc-timeout GRPC_TIMEOUT + Timeout in milliseconds used to set gRPC deadline - + how long the client is willing to wait for a reply + from the server. If not specified, the service will + set the deadline to a very large number. + --max-alternatives MAX_ALTERNATIVES + Maximum number of recognition hypotheses to be + returned. + --time-offsets If set - the recognizer will return also word time + offsets. + --single-utterance If set - the recognizer will detect a single spoken + utterance. + --interim-results If set - messages with temporal results will be shown. + --no-input-timeout NO_INPUT_TIMEOUT + MRCP v2 no input timeout [ms]. + --speech-complete-timeout SPEECH_COMPLETE_TIMEOUT + MRCP v2 speech complete timeout [ms]. + --speech-incomplete-timeout SPEECH_INCOMPLETE_TIMEOUT + MRCP v2 speech incomplete timeout [ms]. + --recognition-timeout RECOGNITION_TIMEOUT + MRCP v2 recognition timeout [ms]. + --context-phrase CONTEXT_PHRASE + Specifies which context model to use. +``` + + +## Troubleshooting + +### Dependencies + +If process of installing dependencies fails with the message similar to this one: + +``` + src/_portaudiomodule.c:28:10: fatal error: Python.h: No such file or directory + #include "Python.h" + ^~~~~~~~~~ + compilation terminated. + error: command '/usr/bin/x86_64-linux-gnu-gcc' failed with exit code 1 +``` +it means that `python3-dev` package is missing. +On Debian/Ubuntu OS this package can be installed by using `setup.sh` script. + + +If process of installing dependencies fails with the message similar to this one: + +``` + src/_portaudiomodule.c:29:10: fatal error: portaudio.h: No such file or directory + #include "portaudio.h" + ^~~~~~~~~~~~~ + compilation terminated. + error: command 'x86_64-linux-gnu-gcc' failed with exit status 1 +``` +it means that PortAudio library is missing. +PortAudio can be downloaded from: http://www.portaudio.com/download.html. +On Debian/Ubuntu OS this package can be installed by using `setup.sh` script. + + +### Microphone + +To use a microphone as the audio source instead of the wav file, use `--mic` option. +It allows to send audio data directly from the microphone, however it does not provide information when to finish the recognition. +For this reason in most cases `--mic` should be followed by the `--single-utterance` option, which stops the recognition after a first spotted utterance. + +If the only output you receive is: +``` +Received speech event type: END_OF_SINGLE_UTTERANCE +``` +check if your microphone is connected and properly configured. + + +### ALSA Configuration + +On the Linux operating systems using Advanced Linux Sound Architecture (ALSA) minor configuration changes may be necessary before the first use. + +If you get the following output after runing request: +``` +Dictation ASR gRPC client 2.3.0 +ALSA lib pcm_dsnoop.c:618:(snd_pcm_dsnoop_open) unable to open slave +ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.rear +ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.center_lfe +ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.side +ALSA lib pcm_route.c:867:(find_matching_chmap) Found no matching channel map +ALSA lib pcm_route.c:867:(find_matching_chmap) Found no matching channel map +ALSA lib pcm_route.c:867:(find_matching_chmap) Found no matching channel map +``` +that means you need to modify the audio interfaces configuration. + +In such case, open the `/usr/share/alsa/alsa.conf` file with root privileges, e.g.: +``` +sudo vim /usr/share/alsa/alsa.conf +``` + +In the `# PCM interface` section find and comment (using #) all lines that defines interfaces marked as 'Unknown': + +``` +pcm.rear cards.pcm.rear +pcm.center_lfe cards.pcm.center_lfe +pcm.side cards.pcm.side +``` +To get rid of warnings, comment also several lines below, starting with `pcm.surround`. + +Then save and close the file. + + +### FFmpeg + +If the FFmpeg framework is not installed, the following warning appears in the program output: + +``` +RuntimeWarning: Couldn't find ffmpeg or avconv - defaulting to ffmpeg, but may not work + warn("Couldn't find ffmpeg or avconv - defaulting to ffmpeg, but may not work", RuntimeWarning) +``` +Installing the FFmpeg framework is not necessary to run the application, however it may be a useful stuff for everyone working with the sound files. + +FFmpeg can be downloaded from: https://ffmpeg.org/download.html + +On the Ubuntu/Debian Linux OS you can download and install FFmpeg directly from the official repositories. \ No newline at end of file diff --git a/docker/techmo_asr/python/VERSION.py b/docker/techmo_asr/python/VERSION.py new file mode 100644 index 0000000000000000000000000000000000000000..f0a86309d2a9d7d976dcb4d5ebb291da5544720b --- /dev/null +++ b/docker/techmo_asr/python/VERSION.py @@ -0,0 +1 @@ +DICTATION_CLIENT_VERSION = '2.3.0' diff --git a/docker/techmo_asr/python/dictation_client.py b/docker/techmo_asr/python/dictation_client.py new file mode 100755 index 0000000000000000000000000000000000000000..84bff1c8e5a5333f0923f60873f68bb87b24665a --- /dev/null +++ b/docker/techmo_asr/python/dictation_client.py @@ -0,0 +1,102 @@ +#!/usr/bin/python3 +from argparse import ArgumentParser +from typing import Tuple, List + +from sziszapangma.integration.service_core.asr.asr_result import WordTimeAlignment + +from VERSION import DICTATION_CLIENT_VERSION +from service.dictation_settings import DictationSettings +from service.streaming_recognizer import StreamingRecognizer +from utils.audio_source import AudioStream +from utils.mic_source import MicrophoneStream + + +def duration_to_normalised_millis(duration): + return int((duration.seconds * 1000000000 + duration.nanos) / 1000000) + + +def word_duration_to_dict(duration_word) -> WordTimeAlignment: + return WordTimeAlignment(duration_to_normalised_millis(duration_word[0]), + duration_to_normalised_millis(duration_word[1])) + + +def create_audio_stream(args): + # create wave file stream + if args.wave is not None: + return AudioStream(args.wave) + + # create microphone stream + if args.mic: + rate = 16000 # [Hz] + chunk = int(rate / 10) # [100 ms] + return MicrophoneStream(rate, chunk) + + # default + raise ValueError("Unknown media source to create") + + +def recognise(wav_path: str, return_time_offsets: bool) -> Tuple[str, List[WordTimeAlignment]]: + print("Dictation ASR gRPC client " + DICTATION_CLIENT_VERSION) + + parser = ArgumentParser() + parser.add_argument("--service-address", dest="address", required=False, + default="127.0.0.1:12321", + help="IP address and port (address:port) of a service the client will connect to.", + type=str) + parser.add_argument("--ssl-dir", dest="ssl_directory", default="", + help="If set to a path with ssl credential files (client.crt, client.key, ca.crt), use ssl authentication. Otherwise use insecure channel (default).", + type=str) + parser.add_argument("--wave-path", dest="wave", + help="Path to wave file with speech to be recognized. Should be mono, 8kHz or 16kHz.", + default=wav_path) + parser.add_argument("--mic", help="Use microphone as an audio source (instead of wave file).", + action='store_true') + parser.add_argument("--session-id", + help="Session ID to be passed to the service. If not specified, the service will generate a default session ID itself.", + default="", type=str) + parser.add_argument("--grpc-timeout", + help="Timeout in milliseconds used to set gRPC deadline - how long the client is willing to wait for a reply from the server. If not specified, the service will set the deadline to a very large number.", + default=0, type=int) + # request configuration section + parser.add_argument("--max-alternatives", + help="Maximum number of recognition hypotheses to be returned.", + default=1, type=int) + parser.add_argument("--time-offsets", + help="If set - the recognizer will return also word time offsets.", + action="store_true", default=return_time_offsets) + parser.add_argument("--single-utterance", + help="If set - the recognizer will detect a single spoken utterance.", + action="store_true", default=False) + parser.add_argument("--interim-results", + help="If set - messages with temporal results will be shown.", + action="store_true", default=False) + # timeouts + parser.add_argument("--no-input-timeout", help="MRCP v2 no input timeout [ms].", default=5000, + type=int) + parser.add_argument("--speech-complete-timeout", help="MRCP v2 speech complete timeout [ms].", + default=2000, + type=int) + parser.add_argument("--speech-incomplete-timeout", + help="MRCP v2 speech incomplete timeout [ms].", default=4000, + type=int) + parser.add_argument("--recognition-timeout", help="MRCP v2 recognition timeout [ms].", + default=10000, type=int) + parser.add_argument("--context-phrase", help="Specifies which context model to use.", + default="", type=str) + + # Stream audio to the ASR engine and print all hypotheses to standard output + args = parser.parse_args() + + print('args') + print(args) + + # if args.wave is not None or args.mic: + with create_audio_stream(args) as stream: + settings = DictationSettings(args) + recognizer = StreamingRecognizer(args.address, args.ssl_directory, settings) + + print('Recognizing...') + results = recognizer.recognize(stream) + print(results) + return results[0]['transcript'], [ + word_duration_to_dict(it) for it in results[0]['alignment']] diff --git a/docker/techmo_asr/python/docker/run_dictation_client_python.sh b/docker/techmo_asr/python/docker/run_dictation_client_python.sh new file mode 100755 index 0000000000000000000000000000000000000000..0482fd1bbf8331ae7eb23bde117f0a706c1df092 --- /dev/null +++ b/docker/techmo_asr/python/docker/run_dictation_client_python.sh @@ -0,0 +1,114 @@ +#!/bin/bash +# coding=utf-8 + +# This script sends request to dictation service using dictation client inside docker container +# Requires "dictation-client-python:2.3.0" docker image loaded locally + +set -euo pipefail +IFS=$'\n\t' + +SCRIPT=$(realpath "$0") +SCRIPTPATH=$(dirname "${SCRIPT}") +docker_image="dictation-client-python:2.3.0" + +usage() { + +echo " + +Dictation ASR gRPC client 2.3.0 + + -h, --help show this help message and exit + -s=ADDRESS, --service-address=ADDRESS + IP address and port (address:port) of a service the client will connect to. + -f=WAVE, --filename=WAVE + Name of the wave file with speech to be recognized. File should be inside 'wav' directory. Should be mono, 8kHz or 16kHz. + -m, --mic Use microphone as an audio source (instead of wave file). + --tls If set, uses tls authentication, otherwise use insecure channel (default). The tls credential files (client.crt, client.key, ca.crt) should be placed inside 'tls' directory. + --session-id=SESSION_ID + Session ID to be passed to the service. If not specified, the service will generate a default session ID itself. + --grpc-timeout=GRPC_TIMEOUT + Timeout in milliseconds used to set gRPC deadline - how long the client is willing to wait for a reply from the + server. If not specified, the service will set the deadline to a very large number. + --max-alternatives=MAX_ALTERNATIVES + Maximum number of recognition hypotheses to be returned. + --time-offsets If set - the recognizer will return also word time offsets. + --single-utterance If set - the recognizer will detect a single spoken utterance. + --interim-results If set - messages with temporal results will be shown. + --no-input-timeout=NO_INPUT_TIMEOUT + MRCP v2 no input timeout [ms]. + --speech-complete-timeout=SPEECH_COMPLETE_TIMEOUT + MRCP v2 speech complete timeout [ms]. + --speech-incomplete-timeout=SPEECH_INCOMPLETE_TIMEOUT + MRCP v2 speech incomplete timeout [ms]. + --recognition-timeout=RECOGNITION_TIMEOUT + MRCP v2 recognition timeout [ms]. + --context-phrase=CONTEXT_PHRASE + Specifies which context model to use. +" +} + +optspec=":fhms-:" +while getopts "f:hms:-:" optchar; do + case "${optchar}" in + -) + case "${OPTARG}" in + help) + usage; exit 0 + ;; + tls) + opts+=( "--ssl-dir" "/volumen/tls" ) + ;; + time-offsets) + opts+=( "--time-offsets" ) + ;; + single-utterance) + opts+=( "--single-utterance" ) + ;; + interim-results) + opts+=( "--interim-results" ) + ;; + mic) + opts+=("--mic") + ;; + filename=*) + val=${OPTARG#*=} + opt=${OPTARG%=$val} + opts+=( "--wave-path" "/volumen/wav/${val##*/}" ) + ;; + *=*) + val=${OPTARG#*=} + opt=${OPTARG%=$val} + opts+=( "--$opt" "$val" ) + ;; + *) + if [ "$OPTERR" = 1 ] && [ "${optspec:0:1}" != ":" ]; then + echo "Unknown option --${OPTARG}" >&2 + fi + ;; + esac;; + f) + val=${OPTARG#*=} + opt=${OPTARG%=$val} + opts+=( "--wave-path" "/volumen/wav/${val##*/}" ) + ;; + h) + usage; exit 0 + ;; + m) + opts+=("--mic") + ;; + s) + val=${OPTARG#*=} + opt=${OPTARG%=$val} + opts+=( "--service-address" "${val}" ) + ;; + *) + if [ "$OPTERR" != 1 ] || [ "${optspec:0:1}" = ":" ]; then + echo "Non-option argument: '-${OPTARG}'" >&2 + fi + ;; + esac +done + +docker run --rm -it -v "${SCRIPTPATH}:/volumen" --network host "${docker_image}" \ +python3 /dictation_client/dictation_client.py "${opts[@]}" \ No newline at end of file diff --git a/docker/techmo_asr/python/docker/tls/.gitkeep b/docker/techmo_asr/python/docker/tls/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/docker/techmo_asr/python/docker/wav/.gitkeep b/docker/techmo_asr/python/docker/wav/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/docker/techmo_asr/python/main.py b/docker/techmo_asr/python/main.py new file mode 100644 index 0000000000000000000000000000000000000000..511950effe96f55dfd8e363ea31204103fa6b4ea --- /dev/null +++ b/docker/techmo_asr/python/main.py @@ -0,0 +1,34 @@ +import os +import socket + +from sziszapangma.integration.service_core.asr.asr_base_processor import AsrBaseProcessor +from sziszapangma.integration.service_core.asr.asr_result import AsrResult + +from dictation_client import recognise + + +class TechmoAsrProcessor(AsrBaseProcessor): + + @staticmethod + def is_tunnel_running() -> bool: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + return s.connect_ex(('localhost', 12321)) == 0 + + def process_asr(self, audio_file_path: str) -> AsrResult: + print(f'processing start {audio_file_path}') + if not self.is_tunnel_running(): + os.system('./start_tunneling.sh') + raw_transcription, words_time_alignment = recognise(audio_file_path, True) + transcription = raw_transcription.replace('\n', ' ') + words = [ + it + for it in transcription.split(' ') + if it not in ['', ' '] + ] + asr_result = AsrResult(words, transcription, words_time_alignment) + print(f'processing end {audio_file_path}, {asr_result}') + return asr_result + + +if __name__ == '__main__': + TechmoAsrProcessor().start_processor() diff --git a/docker/techmo_asr/python/make_proto.sh b/docker/techmo_asr/python/make_proto.sh new file mode 100755 index 0000000000000000000000000000000000000000..b1455e00656863f5081d7e506446be68909120cf --- /dev/null +++ b/docker/techmo_asr/python/make_proto.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# coding=utf-8 + +set -eo pipefail + +virtualenv -p python3 proto_env +# shellcheck disable=SC1091 +source proto_env/bin/activate +pip install grpcio-tools==1.7.0 + +function cleanup() { + # shellcheck disable=SC1091 + rm -rf proto_env +} +trap cleanup EXIT + +echo "Generating dictation Python protobuf/grpc sources." +path_i="../proto" +path_o="service" +python3 -m grpc_tools.protoc \ + -I${path_i} \ + -I../submodules/googleapis \ + --python_out=${path_o} \ + --grpc_python_out=${path_o} \ + ${path_i}/dictation_asr.proto + +# Fix buggy autogenerated GRPC import +sed -i 's/.*import dictation_asr_pb2 as dictation__asr__pb2.*/from . import dictation_asr_pb2 as dictation__asr__pb2/' ${path_o}/dictation_asr_pb2_grpc.py diff --git a/docker/techmo_asr/python/prepare_key.py b/docker/techmo_asr/python/prepare_key.py new file mode 100644 index 0000000000000000000000000000000000000000..48c63872d00055aeade70c5e79f2eda1c3938e02 --- /dev/null +++ b/docker/techmo_asr/python/prepare_key.py @@ -0,0 +1,9 @@ +import os + +_TECHMO_SSH_SERVER_KEY = 'TECHMO_SSH_SERVER_KEY' +_TECHMO_KEY_FILE = './techmo_key_file' + +if __name__ == '__main__': + key_content = os.environ[_TECHMO_SSH_SERVER_KEY].replace('\\n', '\n') + with open(_TECHMO_KEY_FILE, 'w') as f: + f.write(key_content) diff --git a/docker/techmo_asr/python/requirements.txt b/docker/techmo_asr/python/requirements.txt new file mode 100755 index 0000000000000000000000000000000000000000..0bee16a9943f724d0a78d24c47de675ea515c743 --- /dev/null +++ b/docker/techmo_asr/python/requirements.txt @@ -0,0 +1,17 @@ +setuptools==50.3.2 +grpcio==1.37.0 +grpcio-tools==1.37.0 +protobuf==3.12.2 +gapic-google-cloud-speech-v1==0.15.3 +grpc-google-cloud-speech-v1==0.8.1 +proto-google-cloud-speech-v1==0.15.3 +google-auth==1.21.1 +google-auth-httplib2==0.0.3 +google-cloud-core==1.0.2 +google-cloud-speech==1.0.0 +googleapis-common-protos==1.6.0 +httplib2==0.14.0 +oauth2client==2.0.0 +pydub==0.23.1 +pyaudio==0.2.11 +asr-benchmarks==0.0.1-alpha.48 diff --git a/docker/techmo_asr/python/run.sh b/docker/techmo_asr/python/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..abdf96e203cbc3d2af23dfbde668f41b47cb288b --- /dev/null +++ b/docker/techmo_asr/python/run.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# coding=utf-8 + +# This script sends request to dictation service using python dictation client +# Before using this script, run 'setup.sh' to check dependencies and prepare virtual environment + +set -euo pipefail +IFS=$'\n\t' + +SCRIPT=$(realpath "$0") +SCRIPTPATH=$(dirname "${SCRIPT}") + +source "${SCRIPTPATH}/.env/bin/activate" +export PYTHONIOENCODING=utf8 +python3 "${SCRIPTPATH}/dictation_client.py" "$@" \ No newline at end of file diff --git a/docker/techmo_asr/python/run_web_service.sh b/docker/techmo_asr/python/run_web_service.sh new file mode 100755 index 0000000000000000000000000000000000000000..93fd03a4b1b0c77a82fa4dd6e45cc767f774af84 --- /dev/null +++ b/docker/techmo_asr/python/run_web_service.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +#python -u prepare_key.py +# +#chmod 600 ./techmo_key_file + +#./start_tunneling.sh + +python -u main.py diff --git a/docker/techmo_asr/python/service/dictation_asr_pb2.py b/docker/techmo_asr/python/service/dictation_asr_pb2.py new file mode 100644 index 0000000000000000000000000000000000000000..85421b9d0b79990acebb5646a0bd173c9675b322 --- /dev/null +++ b/docker/techmo_asr/python/service/dictation_asr_pb2.py @@ -0,0 +1,1039 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: dictation_asr.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from google.api import annotations_pb2 as google_dot_api_dot_annotations__pb2 +from google.protobuf import duration_pb2 as google_dot_protobuf_dot_duration__pb2 +from google.rpc import status_pb2 as google_dot_rpc_dot_status__pb2 + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='dictation_asr.proto', + package='google.cloud.speech.v1', + syntax='proto3', + serialized_pb=_b('\n\x13\x64ictation_asr.proto\x12\x16google.cloud.speech.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x17google/rpc/status.proto\"\x86\x01\n\x10RecognizeRequest\x12\x39\n\x06\x63onfig\x18\x01 \x01(\x0b\x32).google.cloud.speech.v1.RecognitionConfig\x12\x37\n\x05\x61udio\x18\x02 \x01(\x0b\x32(.google.cloud.speech.v1.RecognitionAudio\"\x99\x01\n\x19StreamingRecognizeRequest\x12N\n\x10streaming_config\x18\x01 \x01(\x0b\x32\x32.google.cloud.speech.v1.StreamingRecognitionConfigH\x00\x12\x17\n\raudio_content\x18\x02 \x01(\x0cH\x00\x42\x13\n\x11streaming_request\"\x8a\x01\n\x1aStreamingRecognitionConfig\x12\x39\n\x06\x63onfig\x18\x01 \x01(\x0b\x32).google.cloud.speech.v1.RecognitionConfig\x12\x18\n\x10single_utterance\x18\x02 \x01(\x08\x12\x17\n\x0finterim_results\x18\x03 \x01(\x08\"\xc4\x04\n\x11RecognitionConfig\x12I\n\x08\x65ncoding\x18\x01 \x01(\x0e\x32\x37.google.cloud.speech.v1.RecognitionConfig.AudioEncoding\x12\x19\n\x11sample_rate_hertz\x18\x02 \x01(\x05\x12\x15\n\rlanguage_code\x18\x03 \x01(\t\x12\x18\n\x10max_alternatives\x18\x04 \x01(\x05\x12\x18\n\x10profanity_filter\x18\x05 \x01(\x08\x12>\n\x0fspeech_contexts\x18\x06 \x03(\x0b\x32%.google.cloud.speech.v1.SpeechContext\x12 \n\x18\x65nable_word_time_offsets\x18\x08 \x01(\x08\x12$\n\x1c\x65nable_automatic_punctuation\x18\x0b \x01(\x08\x12:\n\rconfig_fields\x18\x0c \x03(\x0b\x32#.google.cloud.speech.v1.ConfigField\x12\r\n\x05model\x18\r \x01(\t\x12\x14\n\x0cuse_enhanced\x18\x0e \x01(\x08\"\x94\x01\n\rAudioEncoding\x12\x18\n\x14\x45NCODING_UNSPECIFIED\x10\x00\x12\x0c\n\x08LINEAR16\x10\x01\x12\x08\n\x04\x46LAC\x10\x02\x12\t\n\x05MULAW\x10\x03\x12\x07\n\x03\x41MR\x10\x04\x12\n\n\x06\x41MR_WB\x10\x05\x12\x0c\n\x08OGG_OPUS\x10\x06\x12\x1a\n\x16SPEEX_WITH_HEADER_BYTE\x10\x07\x12\x07\n\x03MP3\x10\x08\" \n\rSpeechContext\x12\x0f\n\x07phrases\x18\x01 \x03(\t\")\n\x0b\x43onfigField\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"D\n\x10RecognitionAudio\x12\x11\n\x07\x63ontent\x18\x01 \x01(\x0cH\x00\x12\r\n\x03uri\x18\x02 \x01(\tH\x00\x42\x0e\n\x0c\x61udio_source\"U\n\x11RecognizeResponse\x12@\n\x07results\x18\x02 \x03(\x0b\x32/.google.cloud.speech.v1.SpeechRecognitionResult\"\xb1\x02\n\x1aStreamingRecognizeResponse\x12!\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x12.google.rpc.Status\x12\x43\n\x07results\x18\x02 \x03(\x0b\x32\x32.google.cloud.speech.v1.StreamingRecognitionResult\x12]\n\x11speech_event_type\x18\x04 \x01(\x0e\x32\x42.google.cloud.speech.v1.StreamingRecognizeResponse.SpeechEventType\"L\n\x0fSpeechEventType\x12\x1c\n\x18SPEECH_EVENT_UNSPECIFIED\x10\x00\x12\x1b\n\x17\x45ND_OF_SINGLE_UTTERANCE\x10\x01\"\xe1\x03\n\x1aStreamingRecognitionResult\x12J\n\x0c\x61lternatives\x18\x01 \x03(\x0b\x32\x34.google.cloud.speech.v1.SpeechRecognitionAlternative\x12\x10\n\x08is_final\x18\x02 \x01(\x08\x12\x11\n\tstability\x18\x03 \x01(\x02\x12m\n\x19result_finalization_cause\x18\x04 \x01(\x0e\x32J.google.cloud.speech.v1.StreamingRecognitionResult.ResultFinalizationCause\x12;\n\x07lattice\x18\x05 \x03(\x0b\x32*.google.cloud.speech.v1.RecognitionLattice\"\xa5\x01\n\x17ResultFinalizationCause\x12)\n%RESULT_FINALIZATION_CAUSE_UNSPECIFIED\x10\x00\x12\x0b\n\x07SUCCESS\x10\x01\x12\x14\n\x10NO_INPUT_TIMEOUT\x10\x02\x12\x13\n\x0fSUCCESS_MAXTIME\x10\x03\x12\x11\n\rPARTIAL_MATCH\x10\x04\x12\x14\n\x10NO_MATCH_MAXTIME\x10\x05\"\xa2\x01\n\x17SpeechRecognitionResult\x12J\n\x0c\x61lternatives\x18\x01 \x03(\x0b\x32\x34.google.cloud.speech.v1.SpeechRecognitionAlternative\x12;\n\x07lattice\x18\x05 \x03(\x0b\x32*.google.cloud.speech.v1.RecognitionLattice\"w\n\x1cSpeechRecognitionAlternative\x12\x12\n\ntranscript\x18\x01 \x01(\t\x12\x12\n\nconfidence\x18\x02 \x01(\x02\x12/\n\x05words\x18\x03 \x03(\x0b\x32 .google.cloud.speech.v1.WordInfo\"t\n\x08WordInfo\x12-\n\nstart_time\x18\x01 \x01(\x0b\x32\x19.google.protobuf.Duration\x12+\n\x08\x65nd_time\x18\x02 \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x0c\n\x04word\x18\x03 \x01(\t\"]\n\x12RecognitionLattice\x12\x13\n\x0b\x66inal_nodes\x18\x01 \x03(\x05\x12\x32\n\x05\x65\x64ges\x18\x02 \x03(\x0b\x32#.google.cloud.speech.v1.LatticeEdge\"\x83\x01\n\x0bLatticeEdge\x12\x12\n\nstart_node\x18\x01 \x01(\x05\x12\x10\n\x08\x65nd_node\x18\x02 \x01(\x05\x12\x0e\n\x06symbol\x18\x03 \x01(\t\x12\x15\n\rlanguage_cost\x18\x04 \x01(\x02\x12\x15\n\racoustic_cost\x18\x05 \x01(\x02\x12\x10\n\x08\x64uration\x18\x06 \x01(\x05\x32\x90\x02\n\x06Speech\x12\x81\x01\n\tRecognize\x12(.google.cloud.speech.v1.RecognizeRequest\x1a).google.cloud.speech.v1.RecognizeResponse\"\x1f\x82\xd3\xe4\x93\x02\x19\"\x14/v1/speech:recognize:\x01*\x12\x81\x01\n\x12StreamingRecognize\x12\x31.google.cloud.speech.v1.StreamingRecognizeRequest\x1a\x32.google.cloud.speech.v1.StreamingRecognizeResponse\"\x00(\x01\x30\x01\x42l\n\x1a\x63om.google.cloud.speech.v1B\x0bSpeechProtoP\x01Z<google.golang.org/genproto/googleapis/cloud/speech/v1;speech\xf8\x01\x01\x62\x06proto3') + , + dependencies=[google_dot_api_dot_annotations__pb2.DESCRIPTOR,google_dot_protobuf_dot_duration__pb2.DESCRIPTOR,google_dot_rpc_dot_status__pb2.DESCRIPTOR,]) + + + +_RECOGNITIONCONFIG_AUDIOENCODING = _descriptor.EnumDescriptor( + name='AudioEncoding', + full_name='google.cloud.speech.v1.RecognitionConfig.AudioEncoding', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='ENCODING_UNSPECIFIED', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LINEAR16', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='FLAC', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='MULAW', index=3, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='AMR', index=4, number=4, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='AMR_WB', index=5, number=5, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='OGG_OPUS', index=6, number=6, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SPEEX_WITH_HEADER_BYTE', index=7, number=7, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='MP3', index=8, number=8, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=1001, + serialized_end=1149, +) +_sym_db.RegisterEnumDescriptor(_RECOGNITIONCONFIG_AUDIOENCODING) + +_STREAMINGRECOGNIZERESPONSE_SPEECHEVENTTYPE = _descriptor.EnumDescriptor( + name='SpeechEventType', + full_name='google.cloud.speech.v1.StreamingRecognizeResponse.SpeechEventType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='SPEECH_EVENT_UNSPECIFIED', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='END_OF_SINGLE_UTTERANCE', index=1, number=1, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=1615, + serialized_end=1691, +) +_sym_db.RegisterEnumDescriptor(_STREAMINGRECOGNIZERESPONSE_SPEECHEVENTTYPE) + +_STREAMINGRECOGNITIONRESULT_RESULTFINALIZATIONCAUSE = _descriptor.EnumDescriptor( + name='ResultFinalizationCause', + full_name='google.cloud.speech.v1.StreamingRecognitionResult.ResultFinalizationCause', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='RESULT_FINALIZATION_CAUSE_UNSPECIFIED', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SUCCESS', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='NO_INPUT_TIMEOUT', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SUCCESS_MAXTIME', index=3, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='PARTIAL_MATCH', index=4, number=4, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='NO_MATCH_MAXTIME', index=5, number=5, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=2010, + serialized_end=2175, +) +_sym_db.RegisterEnumDescriptor(_STREAMINGRECOGNITIONRESULT_RESULTFINALIZATIONCAUSE) + + +_RECOGNIZEREQUEST = _descriptor.Descriptor( + name='RecognizeRequest', + full_name='google.cloud.speech.v1.RecognizeRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='config', full_name='google.cloud.speech.v1.RecognizeRequest.config', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='audio', full_name='google.cloud.speech.v1.RecognizeRequest.audio', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=135, + serialized_end=269, +) + + +_STREAMINGRECOGNIZEREQUEST = _descriptor.Descriptor( + name='StreamingRecognizeRequest', + full_name='google.cloud.speech.v1.StreamingRecognizeRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='streaming_config', full_name='google.cloud.speech.v1.StreamingRecognizeRequest.streaming_config', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='audio_content', full_name='google.cloud.speech.v1.StreamingRecognizeRequest.audio_content', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='streaming_request', full_name='google.cloud.speech.v1.StreamingRecognizeRequest.streaming_request', + index=0, containing_type=None, fields=[]), + ], + serialized_start=272, + serialized_end=425, +) + + +_STREAMINGRECOGNITIONCONFIG = _descriptor.Descriptor( + name='StreamingRecognitionConfig', + full_name='google.cloud.speech.v1.StreamingRecognitionConfig', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='config', full_name='google.cloud.speech.v1.StreamingRecognitionConfig.config', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='single_utterance', full_name='google.cloud.speech.v1.StreamingRecognitionConfig.single_utterance', index=1, + number=2, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='interim_results', full_name='google.cloud.speech.v1.StreamingRecognitionConfig.interim_results', index=2, + number=3, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=428, + serialized_end=566, +) + + +_RECOGNITIONCONFIG = _descriptor.Descriptor( + name='RecognitionConfig', + full_name='google.cloud.speech.v1.RecognitionConfig', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='encoding', full_name='google.cloud.speech.v1.RecognitionConfig.encoding', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='sample_rate_hertz', full_name='google.cloud.speech.v1.RecognitionConfig.sample_rate_hertz', index=1, + number=2, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='language_code', full_name='google.cloud.speech.v1.RecognitionConfig.language_code', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='max_alternatives', full_name='google.cloud.speech.v1.RecognitionConfig.max_alternatives', index=3, + number=4, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='profanity_filter', full_name='google.cloud.speech.v1.RecognitionConfig.profanity_filter', index=4, + number=5, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='speech_contexts', full_name='google.cloud.speech.v1.RecognitionConfig.speech_contexts', index=5, + number=6, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='enable_word_time_offsets', full_name='google.cloud.speech.v1.RecognitionConfig.enable_word_time_offsets', index=6, + number=8, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='enable_automatic_punctuation', full_name='google.cloud.speech.v1.RecognitionConfig.enable_automatic_punctuation', index=7, + number=11, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='config_fields', full_name='google.cloud.speech.v1.RecognitionConfig.config_fields', index=8, + number=12, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='model', full_name='google.cloud.speech.v1.RecognitionConfig.model', index=9, + number=13, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='use_enhanced', full_name='google.cloud.speech.v1.RecognitionConfig.use_enhanced', index=10, + number=14, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _RECOGNITIONCONFIG_AUDIOENCODING, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=569, + serialized_end=1149, +) + + +_SPEECHCONTEXT = _descriptor.Descriptor( + name='SpeechContext', + full_name='google.cloud.speech.v1.SpeechContext', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='phrases', full_name='google.cloud.speech.v1.SpeechContext.phrases', index=0, + number=1, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1151, + serialized_end=1183, +) + + +_CONFIGFIELD = _descriptor.Descriptor( + name='ConfigField', + full_name='google.cloud.speech.v1.ConfigField', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='key', full_name='google.cloud.speech.v1.ConfigField.key', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='value', full_name='google.cloud.speech.v1.ConfigField.value', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1185, + serialized_end=1226, +) + + +_RECOGNITIONAUDIO = _descriptor.Descriptor( + name='RecognitionAudio', + full_name='google.cloud.speech.v1.RecognitionAudio', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='content', full_name='google.cloud.speech.v1.RecognitionAudio.content', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='uri', full_name='google.cloud.speech.v1.RecognitionAudio.uri', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='audio_source', full_name='google.cloud.speech.v1.RecognitionAudio.audio_source', + index=0, containing_type=None, fields=[]), + ], + serialized_start=1228, + serialized_end=1296, +) + + +_RECOGNIZERESPONSE = _descriptor.Descriptor( + name='RecognizeResponse', + full_name='google.cloud.speech.v1.RecognizeResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='results', full_name='google.cloud.speech.v1.RecognizeResponse.results', index=0, + number=2, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1298, + serialized_end=1383, +) + + +_STREAMINGRECOGNIZERESPONSE = _descriptor.Descriptor( + name='StreamingRecognizeResponse', + full_name='google.cloud.speech.v1.StreamingRecognizeResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='error', full_name='google.cloud.speech.v1.StreamingRecognizeResponse.error', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='results', full_name='google.cloud.speech.v1.StreamingRecognizeResponse.results', index=1, + number=2, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='speech_event_type', full_name='google.cloud.speech.v1.StreamingRecognizeResponse.speech_event_type', index=2, + number=4, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _STREAMINGRECOGNIZERESPONSE_SPEECHEVENTTYPE, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1386, + serialized_end=1691, +) + + +_STREAMINGRECOGNITIONRESULT = _descriptor.Descriptor( + name='StreamingRecognitionResult', + full_name='google.cloud.speech.v1.StreamingRecognitionResult', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='alternatives', full_name='google.cloud.speech.v1.StreamingRecognitionResult.alternatives', index=0, + number=1, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='is_final', full_name='google.cloud.speech.v1.StreamingRecognitionResult.is_final', index=1, + number=2, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='stability', full_name='google.cloud.speech.v1.StreamingRecognitionResult.stability', index=2, + number=3, type=2, cpp_type=6, label=1, + has_default_value=False, default_value=float(0), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='result_finalization_cause', full_name='google.cloud.speech.v1.StreamingRecognitionResult.result_finalization_cause', index=3, + number=4, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='lattice', full_name='google.cloud.speech.v1.StreamingRecognitionResult.lattice', index=4, + number=5, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _STREAMINGRECOGNITIONRESULT_RESULTFINALIZATIONCAUSE, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1694, + serialized_end=2175, +) + + +_SPEECHRECOGNITIONRESULT = _descriptor.Descriptor( + name='SpeechRecognitionResult', + full_name='google.cloud.speech.v1.SpeechRecognitionResult', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='alternatives', full_name='google.cloud.speech.v1.SpeechRecognitionResult.alternatives', index=0, + number=1, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='lattice', full_name='google.cloud.speech.v1.SpeechRecognitionResult.lattice', index=1, + number=5, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2178, + serialized_end=2340, +) + + +_SPEECHRECOGNITIONALTERNATIVE = _descriptor.Descriptor( + name='SpeechRecognitionAlternative', + full_name='google.cloud.speech.v1.SpeechRecognitionAlternative', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='transcript', full_name='google.cloud.speech.v1.SpeechRecognitionAlternative.transcript', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='confidence', full_name='google.cloud.speech.v1.SpeechRecognitionAlternative.confidence', index=1, + number=2, type=2, cpp_type=6, label=1, + has_default_value=False, default_value=float(0), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='words', full_name='google.cloud.speech.v1.SpeechRecognitionAlternative.words', index=2, + number=3, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2342, + serialized_end=2461, +) + + +_WORDINFO = _descriptor.Descriptor( + name='WordInfo', + full_name='google.cloud.speech.v1.WordInfo', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='start_time', full_name='google.cloud.speech.v1.WordInfo.start_time', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='end_time', full_name='google.cloud.speech.v1.WordInfo.end_time', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='word', full_name='google.cloud.speech.v1.WordInfo.word', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2463, + serialized_end=2579, +) + + +_RECOGNITIONLATTICE = _descriptor.Descriptor( + name='RecognitionLattice', + full_name='google.cloud.speech.v1.RecognitionLattice', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='final_nodes', full_name='google.cloud.speech.v1.RecognitionLattice.final_nodes', index=0, + number=1, type=5, cpp_type=1, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='edges', full_name='google.cloud.speech.v1.RecognitionLattice.edges', index=1, + number=2, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2581, + serialized_end=2674, +) + + +_LATTICEEDGE = _descriptor.Descriptor( + name='LatticeEdge', + full_name='google.cloud.speech.v1.LatticeEdge', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='start_node', full_name='google.cloud.speech.v1.LatticeEdge.start_node', index=0, + number=1, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='end_node', full_name='google.cloud.speech.v1.LatticeEdge.end_node', index=1, + number=2, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='symbol', full_name='google.cloud.speech.v1.LatticeEdge.symbol', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='language_cost', full_name='google.cloud.speech.v1.LatticeEdge.language_cost', index=3, + number=4, type=2, cpp_type=6, label=1, + has_default_value=False, default_value=float(0), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='acoustic_cost', full_name='google.cloud.speech.v1.LatticeEdge.acoustic_cost', index=4, + number=5, type=2, cpp_type=6, label=1, + has_default_value=False, default_value=float(0), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='duration', full_name='google.cloud.speech.v1.LatticeEdge.duration', index=5, + number=6, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2677, + serialized_end=2808, +) + +_RECOGNIZEREQUEST.fields_by_name['config'].message_type = _RECOGNITIONCONFIG +_RECOGNIZEREQUEST.fields_by_name['audio'].message_type = _RECOGNITIONAUDIO +_STREAMINGRECOGNIZEREQUEST.fields_by_name['streaming_config'].message_type = _STREAMINGRECOGNITIONCONFIG +_STREAMINGRECOGNIZEREQUEST.oneofs_by_name['streaming_request'].fields.append( + _STREAMINGRECOGNIZEREQUEST.fields_by_name['streaming_config']) +_STREAMINGRECOGNIZEREQUEST.fields_by_name['streaming_config'].containing_oneof = _STREAMINGRECOGNIZEREQUEST.oneofs_by_name['streaming_request'] +_STREAMINGRECOGNIZEREQUEST.oneofs_by_name['streaming_request'].fields.append( + _STREAMINGRECOGNIZEREQUEST.fields_by_name['audio_content']) +_STREAMINGRECOGNIZEREQUEST.fields_by_name['audio_content'].containing_oneof = _STREAMINGRECOGNIZEREQUEST.oneofs_by_name['streaming_request'] +_STREAMINGRECOGNITIONCONFIG.fields_by_name['config'].message_type = _RECOGNITIONCONFIG +_RECOGNITIONCONFIG.fields_by_name['encoding'].enum_type = _RECOGNITIONCONFIG_AUDIOENCODING +_RECOGNITIONCONFIG.fields_by_name['speech_contexts'].message_type = _SPEECHCONTEXT +_RECOGNITIONCONFIG.fields_by_name['config_fields'].message_type = _CONFIGFIELD +_RECOGNITIONCONFIG_AUDIOENCODING.containing_type = _RECOGNITIONCONFIG +_RECOGNITIONAUDIO.oneofs_by_name['audio_source'].fields.append( + _RECOGNITIONAUDIO.fields_by_name['content']) +_RECOGNITIONAUDIO.fields_by_name['content'].containing_oneof = _RECOGNITIONAUDIO.oneofs_by_name['audio_source'] +_RECOGNITIONAUDIO.oneofs_by_name['audio_source'].fields.append( + _RECOGNITIONAUDIO.fields_by_name['uri']) +_RECOGNITIONAUDIO.fields_by_name['uri'].containing_oneof = _RECOGNITIONAUDIO.oneofs_by_name['audio_source'] +_RECOGNIZERESPONSE.fields_by_name['results'].message_type = _SPEECHRECOGNITIONRESULT +_STREAMINGRECOGNIZERESPONSE.fields_by_name['error'].message_type = google_dot_rpc_dot_status__pb2._STATUS +_STREAMINGRECOGNIZERESPONSE.fields_by_name['results'].message_type = _STREAMINGRECOGNITIONRESULT +_STREAMINGRECOGNIZERESPONSE.fields_by_name['speech_event_type'].enum_type = _STREAMINGRECOGNIZERESPONSE_SPEECHEVENTTYPE +_STREAMINGRECOGNIZERESPONSE_SPEECHEVENTTYPE.containing_type = _STREAMINGRECOGNIZERESPONSE +_STREAMINGRECOGNITIONRESULT.fields_by_name['alternatives'].message_type = _SPEECHRECOGNITIONALTERNATIVE +_STREAMINGRECOGNITIONRESULT.fields_by_name['result_finalization_cause'].enum_type = _STREAMINGRECOGNITIONRESULT_RESULTFINALIZATIONCAUSE +_STREAMINGRECOGNITIONRESULT.fields_by_name['lattice'].message_type = _RECOGNITIONLATTICE +_STREAMINGRECOGNITIONRESULT_RESULTFINALIZATIONCAUSE.containing_type = _STREAMINGRECOGNITIONRESULT +_SPEECHRECOGNITIONRESULT.fields_by_name['alternatives'].message_type = _SPEECHRECOGNITIONALTERNATIVE +_SPEECHRECOGNITIONRESULT.fields_by_name['lattice'].message_type = _RECOGNITIONLATTICE +_SPEECHRECOGNITIONALTERNATIVE.fields_by_name['words'].message_type = _WORDINFO +_WORDINFO.fields_by_name['start_time'].message_type = google_dot_protobuf_dot_duration__pb2._DURATION +_WORDINFO.fields_by_name['end_time'].message_type = google_dot_protobuf_dot_duration__pb2._DURATION +_RECOGNITIONLATTICE.fields_by_name['edges'].message_type = _LATTICEEDGE +DESCRIPTOR.message_types_by_name['RecognizeRequest'] = _RECOGNIZEREQUEST +DESCRIPTOR.message_types_by_name['StreamingRecognizeRequest'] = _STREAMINGRECOGNIZEREQUEST +DESCRIPTOR.message_types_by_name['StreamingRecognitionConfig'] = _STREAMINGRECOGNITIONCONFIG +DESCRIPTOR.message_types_by_name['RecognitionConfig'] = _RECOGNITIONCONFIG +DESCRIPTOR.message_types_by_name['SpeechContext'] = _SPEECHCONTEXT +DESCRIPTOR.message_types_by_name['ConfigField'] = _CONFIGFIELD +DESCRIPTOR.message_types_by_name['RecognitionAudio'] = _RECOGNITIONAUDIO +DESCRIPTOR.message_types_by_name['RecognizeResponse'] = _RECOGNIZERESPONSE +DESCRIPTOR.message_types_by_name['StreamingRecognizeResponse'] = _STREAMINGRECOGNIZERESPONSE +DESCRIPTOR.message_types_by_name['StreamingRecognitionResult'] = _STREAMINGRECOGNITIONRESULT +DESCRIPTOR.message_types_by_name['SpeechRecognitionResult'] = _SPEECHRECOGNITIONRESULT +DESCRIPTOR.message_types_by_name['SpeechRecognitionAlternative'] = _SPEECHRECOGNITIONALTERNATIVE +DESCRIPTOR.message_types_by_name['WordInfo'] = _WORDINFO +DESCRIPTOR.message_types_by_name['RecognitionLattice'] = _RECOGNITIONLATTICE +DESCRIPTOR.message_types_by_name['LatticeEdge'] = _LATTICEEDGE +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +RecognizeRequest = _reflection.GeneratedProtocolMessageType('RecognizeRequest', (_message.Message,), dict( + DESCRIPTOR = _RECOGNIZEREQUEST, + __module__ = 'dictation_asr_pb2' + # @@protoc_insertion_point(class_scope:google.cloud.speech.v1.RecognizeRequest) + )) +_sym_db.RegisterMessage(RecognizeRequest) + +StreamingRecognizeRequest = _reflection.GeneratedProtocolMessageType('StreamingRecognizeRequest', (_message.Message,), dict( + DESCRIPTOR = _STREAMINGRECOGNIZEREQUEST, + __module__ = 'dictation_asr_pb2' + # @@protoc_insertion_point(class_scope:google.cloud.speech.v1.StreamingRecognizeRequest) + )) +_sym_db.RegisterMessage(StreamingRecognizeRequest) + +StreamingRecognitionConfig = _reflection.GeneratedProtocolMessageType('StreamingRecognitionConfig', (_message.Message,), dict( + DESCRIPTOR = _STREAMINGRECOGNITIONCONFIG, + __module__ = 'dictation_asr_pb2' + # @@protoc_insertion_point(class_scope:google.cloud.speech.v1.StreamingRecognitionConfig) + )) +_sym_db.RegisterMessage(StreamingRecognitionConfig) + +RecognitionConfig = _reflection.GeneratedProtocolMessageType('RecognitionConfig', (_message.Message,), dict( + DESCRIPTOR = _RECOGNITIONCONFIG, + __module__ = 'dictation_asr_pb2' + # @@protoc_insertion_point(class_scope:google.cloud.speech.v1.RecognitionConfig) + )) +_sym_db.RegisterMessage(RecognitionConfig) + +SpeechContext = _reflection.GeneratedProtocolMessageType('SpeechContext', (_message.Message,), dict( + DESCRIPTOR = _SPEECHCONTEXT, + __module__ = 'dictation_asr_pb2' + # @@protoc_insertion_point(class_scope:google.cloud.speech.v1.SpeechContext) + )) +_sym_db.RegisterMessage(SpeechContext) + +ConfigField = _reflection.GeneratedProtocolMessageType('ConfigField', (_message.Message,), dict( + DESCRIPTOR = _CONFIGFIELD, + __module__ = 'dictation_asr_pb2' + # @@protoc_insertion_point(class_scope:google.cloud.speech.v1.ConfigField) + )) +_sym_db.RegisterMessage(ConfigField) + +RecognitionAudio = _reflection.GeneratedProtocolMessageType('RecognitionAudio', (_message.Message,), dict( + DESCRIPTOR = _RECOGNITIONAUDIO, + __module__ = 'dictation_asr_pb2' + # @@protoc_insertion_point(class_scope:google.cloud.speech.v1.RecognitionAudio) + )) +_sym_db.RegisterMessage(RecognitionAudio) + +RecognizeResponse = _reflection.GeneratedProtocolMessageType('RecognizeResponse', (_message.Message,), dict( + DESCRIPTOR = _RECOGNIZERESPONSE, + __module__ = 'dictation_asr_pb2' + # @@protoc_insertion_point(class_scope:google.cloud.speech.v1.RecognizeResponse) + )) +_sym_db.RegisterMessage(RecognizeResponse) + +StreamingRecognizeResponse = _reflection.GeneratedProtocolMessageType('StreamingRecognizeResponse', (_message.Message,), dict( + DESCRIPTOR = _STREAMINGRECOGNIZERESPONSE, + __module__ = 'dictation_asr_pb2' + # @@protoc_insertion_point(class_scope:google.cloud.speech.v1.StreamingRecognizeResponse) + )) +_sym_db.RegisterMessage(StreamingRecognizeResponse) + +StreamingRecognitionResult = _reflection.GeneratedProtocolMessageType('StreamingRecognitionResult', (_message.Message,), dict( + DESCRIPTOR = _STREAMINGRECOGNITIONRESULT, + __module__ = 'dictation_asr_pb2' + # @@protoc_insertion_point(class_scope:google.cloud.speech.v1.StreamingRecognitionResult) + )) +_sym_db.RegisterMessage(StreamingRecognitionResult) + +SpeechRecognitionResult = _reflection.GeneratedProtocolMessageType('SpeechRecognitionResult', (_message.Message,), dict( + DESCRIPTOR = _SPEECHRECOGNITIONRESULT, + __module__ = 'dictation_asr_pb2' + # @@protoc_insertion_point(class_scope:google.cloud.speech.v1.SpeechRecognitionResult) + )) +_sym_db.RegisterMessage(SpeechRecognitionResult) + +SpeechRecognitionAlternative = _reflection.GeneratedProtocolMessageType('SpeechRecognitionAlternative', (_message.Message,), dict( + DESCRIPTOR = _SPEECHRECOGNITIONALTERNATIVE, + __module__ = 'dictation_asr_pb2' + # @@protoc_insertion_point(class_scope:google.cloud.speech.v1.SpeechRecognitionAlternative) + )) +_sym_db.RegisterMessage(SpeechRecognitionAlternative) + +WordInfo = _reflection.GeneratedProtocolMessageType('WordInfo', (_message.Message,), dict( + DESCRIPTOR = _WORDINFO, + __module__ = 'dictation_asr_pb2' + # @@protoc_insertion_point(class_scope:google.cloud.speech.v1.WordInfo) + )) +_sym_db.RegisterMessage(WordInfo) + +RecognitionLattice = _reflection.GeneratedProtocolMessageType('RecognitionLattice', (_message.Message,), dict( + DESCRIPTOR = _RECOGNITIONLATTICE, + __module__ = 'dictation_asr_pb2' + # @@protoc_insertion_point(class_scope:google.cloud.speech.v1.RecognitionLattice) + )) +_sym_db.RegisterMessage(RecognitionLattice) + +LatticeEdge = _reflection.GeneratedProtocolMessageType('LatticeEdge', (_message.Message,), dict( + DESCRIPTOR = _LATTICEEDGE, + __module__ = 'dictation_asr_pb2' + # @@protoc_insertion_point(class_scope:google.cloud.speech.v1.LatticeEdge) + )) +_sym_db.RegisterMessage(LatticeEdge) + + +DESCRIPTOR.has_options = True +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\032com.google.cloud.speech.v1B\013SpeechProtoP\001Z<google.golang.org/genproto/googleapis/cloud/speech/v1;speech\370\001\001')) + +_SPEECH = _descriptor.ServiceDescriptor( + name='Speech', + full_name='google.cloud.speech.v1.Speech', + file=DESCRIPTOR, + index=0, + options=None, + serialized_start=2811, + serialized_end=3083, + methods=[ + _descriptor.MethodDescriptor( + name='Recognize', + full_name='google.cloud.speech.v1.Speech.Recognize', + index=0, + containing_service=None, + input_type=_RECOGNIZEREQUEST, + output_type=_RECOGNIZERESPONSE, + options=_descriptor._ParseOptions(descriptor_pb2.MethodOptions(), _b('\202\323\344\223\002\031\"\024/v1/speech:recognize:\001*')), + ), + _descriptor.MethodDescriptor( + name='StreamingRecognize', + full_name='google.cloud.speech.v1.Speech.StreamingRecognize', + index=1, + containing_service=None, + input_type=_STREAMINGRECOGNIZEREQUEST, + output_type=_STREAMINGRECOGNIZERESPONSE, + options=None, + ), +]) +_sym_db.RegisterServiceDescriptor(_SPEECH) + +DESCRIPTOR.services_by_name['Speech'] = _SPEECH + +# @@protoc_insertion_point(module_scope) diff --git a/docker/techmo_asr/python/service/dictation_asr_pb2_grpc.py b/docker/techmo_asr/python/service/dictation_asr_pb2_grpc.py new file mode 100644 index 0000000000000000000000000000000000000000..e2386638af58ee8eb044077a470c7df4237840bf --- /dev/null +++ b/docker/techmo_asr/python/service/dictation_asr_pb2_grpc.py @@ -0,0 +1,76 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +import grpc + +from . import dictation_asr_pb2 as dictation__asr__pb2 + + +class SpeechStub(object): + """Service that implements Google Cloud Speech API extended by Techmo. + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.Recognize = channel.unary_unary( + '/google.cloud.speech.v1.Speech/Recognize', + request_serializer=dictation__asr__pb2.RecognizeRequest.SerializeToString, + response_deserializer=dictation__asr__pb2.RecognizeResponse.FromString, + ) + self.StreamingRecognize = channel.stream_stream( + '/google.cloud.speech.v1.Speech/StreamingRecognize', + request_serializer=dictation__asr__pb2.StreamingRecognizeRequest.SerializeToString, + response_deserializer=dictation__asr__pb2.StreamingRecognizeResponse.FromString, + ) + + +class SpeechServicer(object): + """Service that implements Google Cloud Speech API extended by Techmo. + """ + + def Recognize(self, request, context): + """Performs synchronous speech recognition: receive results after all audio + has been sent and processed. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def StreamingRecognize(self, request_iterator, context): + """Performs asynchronous speech recognition: receive results via the + google.longrunning.Operations interface. Returns either an + `Operation.error` or an `Operation.response` which contains + a `LongRunningRecognizeResponse` message. + rpc LongRunningRecognize(LongRunningRecognizeRequest) returns (google.longrunning.Operation) { + option (google.api.http) = { + post: "/v1/speech:longrunningrecognize" + body: "*" + }; + } + + Performs bidirectional streaming speech recognition: receive results while + sending audio. This method is only available via the gRPC API (not REST). + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_SpeechServicer_to_server(servicer, server): + rpc_method_handlers = { + 'Recognize': grpc.unary_unary_rpc_method_handler( + servicer.Recognize, + request_deserializer=dictation__asr__pb2.RecognizeRequest.FromString, + response_serializer=dictation__asr__pb2.RecognizeResponse.SerializeToString, + ), + 'StreamingRecognize': grpc.stream_stream_rpc_method_handler( + servicer.StreamingRecognize, + request_deserializer=dictation__asr__pb2.StreamingRecognizeRequest.FromString, + response_serializer=dictation__asr__pb2.StreamingRecognizeResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'google.cloud.speech.v1.Speech', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) diff --git a/docker/techmo_asr/python/service/dictation_settings.py b/docker/techmo_asr/python/service/dictation_settings.py new file mode 100755 index 0000000000000000000000000000000000000000..a63ff6bc8bf8fa3fa1cd074112967d3c44638f78 --- /dev/null +++ b/docker/techmo_asr/python/service/dictation_settings.py @@ -0,0 +1,35 @@ +class DictationSettings: + """Default settings for Techmo Dictation ASR (timeouts and thresholds)""" + + def __init__(self, args): + # use configuration directly + self.args = args + + def session_id(self): + return self.args.session_id + + def grpc_timeout(self): + return self.args.grpc_timeout + + def max_alternatives(self): + return self.args.max_alternatives + + def time_offsets(self): + return self.args.time_offsets + + def single_utterance(self): + return self.args.single_utterance + + def interim_results(self): + return self.args.interim_results + + def timeouts_map(self): + return { + "no-input-timeout": str(self.args.no_input_timeout), + "speech-complete-timeout": str(self.args.speech_complete_timeout), + "speech-incomplete-timeout": str(self.args.speech_incomplete_timeout), + "recognition-timeout": str(self.args.recognition_timeout), + } + + def context_phrase(self): + return self.args.context_phrase diff --git a/docker/techmo_asr/python/service/streaming_recognizer.py b/docker/techmo_asr/python/service/streaming_recognizer.py new file mode 100755 index 0000000000000000000000000000000000000000..46fd61e6258a81336d6299ab77ea7bda44a2fed4 --- /dev/null +++ b/docker/techmo_asr/python/service/streaming_recognizer.py @@ -0,0 +1,159 @@ +import os +import threading +from . import dictation_asr_pb2 as dictation_asr_pb2 +from . import dictation_asr_pb2_grpc as dictation_asr_pb2_grpc +import grpc + + +class RequestIterator: + """Thread-safe request iterator for streaming recognizer.""" + + def __init__(self, audio_stream, settings): + # Iterator data + self.audio_stream = audio_stream + self.audio_generator = self.audio_stream.generator() + + self.settings = settings + + self.request_builder = { + True: self._initial_request, + False: self._normal_request + } + # Iterator state + self.lock = threading.Lock() + self.is_initial_request = True + self.eos = False # indicates whether end of stream message was send (request to stop iterator) + + def _initial_request(self): + req = StreamingRecognizer.build_configuration_request(self.audio_stream.frame_rate(), self.settings) + self.is_initial_request = False + return req + + def _normal_request(self): + data = next(self.audio_generator) + if data == None: + raise StopIteration + + return dictation_asr_pb2.StreamingRecognizeRequest(audio_content=data) + + def __iter__(self): + return self + + def __next__(self): + with self.lock: + return self.request_builder[self.is_initial_request]() + + +class StreamingRecognizer: + def __init__(self, address, ssl_directory, settings_args): + # Use ArgumentParser to parse settings + self.service = dictation_asr_pb2_grpc.SpeechStub(StreamingRecognizer.create_channel(address, ssl_directory)) + self.settings = settings_args + + def recognize(self, audio): + requests_iterator = RequestIterator(audio, self.settings) + return self.recognize_audio_content(requests_iterator) + + def recognize_audio_content(self, requests_iterator): + time_offsets = self.settings.time_offsets() + + timeout=None + if self.settings.grpc_timeout() > 0: + timeout = self.settings.grpc_timeout() / 1000 # milliseconds to seconds + metadata = [] + if self.settings.session_id(): + metadata = [('session_id', self.settings.session_id())] + + recognitions = self.service.StreamingRecognize(requests_iterator, timeout=timeout, metadata=metadata) + + confirmed_results = [] + alignment = [] + confidence = 1.0 + + for recognition in recognitions: + if recognition.error.code: + print(u"Received error response: ({}) {}".format(recognition.error.code, recognition.error.message)) + requests_iterator.audio_stream.close() + + elif recognition.speech_event_type != dictation_asr_pb2.StreamingRecognizeResponse.SPEECH_EVENT_UNSPECIFIED: + print(u"Received speech event type: {}".format( + dictation_asr_pb2.StreamingRecognizeResponse.SpeechEventType.Name(recognition.speech_event_type))) + requests_iterator.audio_stream.close() + + # process response type + elif recognition.results is not None and len(recognition.results) > 0: + first = recognition.results[0] + if first.is_final: + if time_offsets: + for word in first.alternatives[0].words: + if word.word != '<eps>': + confirmed_results.append(word.word) + alignment.append([word.start_time, word.end_time]) + else: + confirmed_results.append(first.alternatives[0].transcript) + confidence = min(confidence, first.alternatives[0].confidence) + else: + print(u"Temporal results - {}".format(first)) + + # build final results + final_alignment = [[]] + final_transc = ' '.join(confirmed_results) + + if time_offsets and alignment: + final_alignment = alignment + + return [{ + 'transcript': final_transc, + 'alignment': final_alignment, + 'confidence': confidence + }] # array with one element + + @staticmethod + def create_channel(address, ssl_directory): + if not ssl_directory: + return grpc.insecure_channel(address) + + def read_file(path): + with open(path, 'rb') as file: + return file.read() + + return grpc.secure_channel(address, grpc.ssl_channel_credentials( + read_file(os.path.join(ssl_directory, 'ca.crt')), + read_file(os.path.join(ssl_directory, 'client.key')), + read_file(os.path.join(ssl_directory, 'client.crt')), + )) + + @staticmethod + def build_recognition_config(sampling_rate, settings): + recognition_config = dictation_asr_pb2.RecognitionConfig( + encoding='LINEAR16', # one of LINEAR16, FLAC, MULAW, AMR, AMR_WB + sample_rate_hertz=sampling_rate, # the rate in hertz + # See https://g.co/cloud/speech/docs/languages for a list of supported languages. + language_code='pl-PL', # a BCP-47 language tag + enable_word_time_offsets=settings.time_offsets(), # if true, return recognized word time offsets + max_alternatives=1, # maximum number of returned hypotheses + ) + if (settings.context_phrase()): + speech_context = recognition_config.speech_contexts.add() + speech_context.phrases.append(settings.context_phrase()) + + return recognition_config + + @staticmethod + def build_configuration_request(sampling_rate, settings): + config_req = dictation_asr_pb2.StreamingRecognizeRequest( + streaming_config=dictation_asr_pb2.StreamingRecognitionConfig( + config=StreamingRecognizer.build_recognition_config(sampling_rate, settings), + single_utterance=settings.single_utterance(), + interim_results=settings.interim_results() + ) + # no audio data in first request (config only) + ) + # timeout settings + timeouts = settings.timeouts_map() + for settings_key in timeouts: + cf = config_req.streaming_config.config.config_fields.add() + cf.key = settings_key + cf.value = "{}".format(timeouts[settings_key]) + + return config_req diff --git a/docker/techmo_asr/python/setup.sh b/docker/techmo_asr/python/setup.sh new file mode 100755 index 0000000000000000000000000000000000000000..79f6e07e02db96768d0b9b99fcedf44852b479ec --- /dev/null +++ b/docker/techmo_asr/python/setup.sh @@ -0,0 +1,107 @@ +#!/bin/bash +# coding=utf-8 + +set -euo pipefail +IFS=$'\n\t' + +install_package () { + # $1 - package name + # $2 - if == "sudo" use sudo + if [ $(dpkg-query -W -f='${Status}' "$1" 2>/dev/null | grep -c "ok installed") -eq 0 ]; + then + while true; do + read -p "The required package $1 is not installed. Do you want to install it now? [y/n]" yn + case $yn in + [Yy]*) + if [[ $# -eq 2 ]] && [[ $2 == "sudo" ]]; + then + sudo apt-get update && sudo apt-get install -y "$1"; + else + apt-get update && apt-get install -y "$1"; + fi; + break ;; + [Nn]*) + echo "Permission to install the required package has not been granted. Exiting..."; + exit 0 ;; + esac + done + fi +} + +# check Python version + +python3_missing="false" +command -v python3 >/dev/null 2>&1 || python3_missing="true" + +if [[ "$python3_missing" == true ]]; then + echo "Unable to find Python 3! Install Python 3 and run setup again." + exit 1 +fi + +python_version_output="$(python3 --version)" +python_version_detailed="${python_version_output##* }" +python_version="${python_version_detailed%.*}" + +if [[ ! "$python_version" =~ ^(3\.5|3\.6|3\.7|3\.8|3\.9)$ ]]; then + echo "Cannot find required Python version! Supported versions are: 3.5, 3.6, 3.7, 3.8, 3.9"; + exit 0 +fi + +# check if sudo is installed + +sudo_str="" +if [ $(dpkg-query -W -f='${Status}' sudo 2>/dev/null | grep -c "ok installed") -ne 0 ]; then + sudo_str="sudo" +fi + +# install required packages + +install_package "python3-dev" "${sudo_str}" +install_package "portaudio19-dev" "${sudo_str}" +install_package "python3-pip" "${sudo_str}" + +# check if virtualenv >= 16.2 is installed + +set +e +virtualenv_version=$(virtualenv --version) 2>&1 > /dev/null +virtualenv_is_installed=$? +set -e +if [ "$virtualenv_is_installed" -ne 0 ]; +then + while true; do + read -p "The required package virtualenv is not installed. Do you want to install it now? [y/n]" yn + case $yn in + [Yy]*) + pip3 install virtualenv==16.2; + break ;; + [Nn]*) + echo "Permission to install the required package has not been granted. Exiting..."; + exit 0 ;; + esac + done +else + # check virtualenv version + version=$(echo $virtualenv_version | cut -f1 -d.) + subversion=$(echo $virtualenv_version | cut -f2 -d.) + + if [[ "$version" -lt 16 || "$version" -eq 16 && "$subversion" -lt 2 ]]; + then + while true; do + read -p "Installed version of virtualenv package ($virtualenv_version) is too old. Do you want to install newer version now? [y/n]" yn + case $yn in + [Yy]*) + pip3 install virtualenv==16.2; + break ;; + [Nn]*) + echo "Permission to install the required package has not been granted. Exiting..."; + exit 0 ;; + esac + done + fi +fi + +virtualenv -p python3 .env +source .env/bin/activate +pip install -r requirements.txt + +echo "Setup finished!" \ No newline at end of file diff --git a/docker/techmo_asr/python/start_tunneling.sh b/docker/techmo_asr/python/start_tunneling.sh new file mode 100755 index 0000000000000000000000000000000000000000..b569a160ada50ee07df93c346570d2ec07d20363 --- /dev/null +++ b/docker/techmo_asr/python/start_tunneling.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +echo 'start call for start tunneling' +ssh -i /keys/techmo_rsa_key -p 9222 -f -N -L 12321:156.17.135.34:12321 -o StrictHostKeyChecking=no -4 mwatroba@jankocon.clarin-pl.eu +echo 'finish call for start tunneling' diff --git a/docker/techmo_asr/python/utils/audio_source.py b/docker/techmo_asr/python/utils/audio_source.py new file mode 100755 index 0000000000000000000000000000000000000000..0b6bdb259a2790ddc10e51eca415d43b44800fce --- /dev/null +++ b/docker/techmo_asr/python/utils/audio_source.py @@ -0,0 +1,67 @@ +from pydub import AudioSegment +import os + + +class AudioStream(object): + + def __init__(self, audio_path): + if not os.path.exists(audio_path): + raise ValueError("Wave file does not exist at: {}".format(audio_path)) + + self.audio_segment = AudioSegment.from_wav(audio_path) + self.audio_path = audio_path + + if self.audio_segment.channels != 1: + raise ValueError("Only mono waves are allowed. {} contains: {} channels".format(audio_path, self.audio_segment.channels)) + if self.audio_segment.sample_width != 2: + raise ValueError( + "Only 16bit samples are allowed. {} has: {} bit samples".format(audio_path, self.audio_segment.sample_width * 8)) + + self.data_index = 0 + self.audio = self.audio_segment.raw_data + + frame_len = 200 # ms + sample_width = 2 # 16bit + self.frame_samples_size = (self.audio_segment.frame_rate // 1000) * frame_len * sample_width + + def __iter__(self): + return self + + def __next__(self): + if self.data_index >= len(self.audio): + raise StopIteration() + + end_sample = self.data_index + self.frame_samples_size + if end_sample >= len(self.audio): + end_sample = len(self.audio) + + data = self.audio[self.data_index: end_sample] + self.data_index = end_sample + + return data + + def __enter__(self): + self.data_index = 0 + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + pass + + def frame_rate(self): + return self.audio_segment.frame_rate + + def session_id(self): + return os.path.basename(self.audio_path) + + def close(self): + self.data_index = len(self.audio) + 1 # mark end-of-stream + + def generator(self): + while self.data_index < len(self.audio): + end_sample = self.data_index + self.frame_samples_size + if end_sample >= len(self.audio): + end_sample = len(self.audio) + + data = self.audio[self.data_index: end_sample] + self.data_index = end_sample + yield data diff --git a/docker/techmo_asr/python/utils/mic_source.py b/docker/techmo_asr/python/utils/mic_source.py new file mode 100644 index 0000000000000000000000000000000000000000..6577db0e24ce592c9823fb371ac5581ae078dd59 --- /dev/null +++ b/docker/techmo_asr/python/utils/mic_source.py @@ -0,0 +1,80 @@ +import pyaudio +import queue + + +class MicrophoneStream(object): + """Opens a recording stream as a generator yielding the audio chunks.""" + """It's directly copied from GOOGLE example: + https://cloud.google.com/speech/docs/streaming-recognize#speech-streaming-recognize-python """ + + def __init__(self, rate, chunk): + self._rate = rate + self._chunk = chunk + + # Create a thread-safe buffer of audio data + self._buff = queue.Queue() + self.closed = True + + def __enter__(self): + self._audio_interface = pyaudio.PyAudio() + self._audio_stream = self._audio_interface.open( + format=pyaudio.paInt16, + # The API currently only supports 1-channel (mono) audio + # https://goo.gl/z757pE + channels=1, rate=self._rate, + input=True, frames_per_buffer=self._chunk, + # Run the audio stream asynchronously to fill the buffer object. + # This is necessary so that the input device's buffer doesn't + # overflow while the calling thread makes network requests, etc. + stream_callback=self._fill_buffer, + ) + + self.closed = False + + return self + + def __exit__(self, type, value, traceback): + self._audio_stream.stop_stream() + self._audio_stream.close() + self.closed = True + # Signal the generator to terminate so that the client's + # streaming_recognize method will not block the process termination. + self._buff.put(None) + self._audio_interface.terminate() + + def _fill_buffer(self, in_data, frame_count, time_info, status_flags): + """Continuously collect data from the audio stream, into the buffer.""" + self._buff.put(in_data) + return None, pyaudio.paContinue + + def close(self): + self.closed = True + + def frame_rate(self): + return self._rate + + def session_id(self): + return "sarmata-pyclient-mic" + + def generator(self): + while not self.closed: + # Use a blocking get() to ensure there's at least one chunk of + # data, and stop iteration if the chunk is None, indicating the + # end of the audio stream. + chunk = self._buff.get() + if chunk is None: + return + data = [chunk] + + # Now consume whatever other data's still buffered. + while True: + try: + chunk = self._buff.get(block=False) + if chunk is None: + return + data.append(chunk) + except queue.Empty: + break + + yield b''.join(data) +# [END audio_stream] \ No newline at end of file diff --git a/examples/__init__.py b/examples/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/examples/import_dataset/__init__.py b/examples/import_dataset/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/examples/import_dataset/luna/__init__.py b/examples/import_dataset/luna/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/examples/import_dataset/luna/import_luna.py b/examples/import_dataset/luna/import_luna.py new file mode 100644 index 0000000000000000000000000000000000000000..cd07f7d43efe11fad3c1d0cd82fa09160b40b0b2 --- /dev/null +++ b/examples/import_dataset/luna/import_luna.py @@ -0,0 +1,180 @@ +from typing import Tuple, List +from xml.etree import ElementTree + +from examples.import_dataset.luna.luna_record_provider import LunaRecordProvider +from sziszapangma.integration.path_filter import ExtensionPathFilter +from sziszapangma.model.model import Word, SingleAnnotation +from sziszapangma.model.model_creators import create_new_word, create_new_single_annotation, \ + create_new_span_annotation, create_new_document +from sziszapangma.model.relation_manager import RelationManager + + +class LunaAdapter: + _record_provider: LunaRecordProvider + + def __init__(self, record_provider: LunaRecordProvider): + self._record_provider = record_provider + + @staticmethod + def save_words( + words_path: str, + relation_manager: RelationManager + ) -> Tuple[List[Word], List[SingleAnnotation]]: + xml_tree = ElementTree.parse(words_path) + root_element = xml_tree.getroot() + words = [] + annotations = [] + for word_element in root_element: + if word_element.tag == "word": + word = create_new_word(text=word_element.attrib["word"]) + relation_manager.save_item(word) + word_annotations = [ + create_new_single_annotation( + annotation_type="lemma", value=word_element.attrib["lemma"], + reference_id=word['id'] + ), + create_new_single_annotation( + annotation_type="pos", value=word_element.attrib["POS"], + reference_id=word['id'] + ), + create_new_single_annotation( + annotation_type="morph", value=word_element.attrib["morph"], + reference_id=word['id'] + ), + ] + for word_annotation in word_annotations: + relation_manager.save_item(word_annotation) + relation_manager.save_relation(word, word_annotation) + words.append(word) + annotations.extend(word_annotations) + document = create_new_document([word['id'] for word in words]) + relation_manager.save_item(document) + for word in words: + relation_manager.save_relation(word, document) + return words, annotations + + @staticmethod + def parse_id_expression(word_id: str) -> int: + return int(word_id[5:]) + + def get_word_ids_list(self, words: List[Word], word_ids: str) -> List[str]: + if word_ids == "empty": + return [] + splitted = word_ids.split("..") + if len(splitted) == 1: + return [words[self.parse_id_expression(word_ids) - 1]['id']] + else: + index_form = self.parse_id_expression(splitted[0]) - 1 + index_to = self.parse_id_expression(splitted[1]) + return [word['id'] for word in words[index_form:index_to]] + + def read_concepts( + self, + words: List[Word], concept_path: str, relation_manager: RelationManager + ) -> None: + xml_tree = ElementTree.parse(concept_path) + root_element = xml_tree.getroot() + for word_element in root_element: + if word_element.tag == "concept": + word_ids_to_relation = self.get_word_ids_list(words, word_element.attrib["span"]) + relation = create_new_span_annotation('concept', word_ids_to_relation) + relation_manager.save_item(relation) + concept_value = { + "attribute": word_element.attrib["attribute"], + "value": word_element.attrib["value"], + } + annotation = create_new_single_annotation( + annotation_type="concept", value=concept_value, reference_id=relation['id'] + ) + relation_manager.save_item(annotation) + relation_manager.save_relation(annotation, relation) + for word in words: + if word['id'] in word_ids_to_relation: + relation_manager.save_relation(word, relation) + + def read_chunks(self, + words: List[Word], chunks_path: str, + relation_manager: RelationManager + ) -> None: + xml_tree = ElementTree.parse(chunks_path) + root_element = xml_tree.getroot() + for word_element in root_element: + if word_element.tag == "chunk": + word_ids_to_relation = self.get_word_ids_list(words, word_element.attrib["span"]) + relation = create_new_span_annotation('chunk', elements=word_ids_to_relation) + concept_value = { + "cat": word_element.attrib["span"], + # zmienić na id słowa w zbiorze + "main": word_element.attrib["main"] + if "main" in word_element.attrib + else None, + } + annotation = create_new_single_annotation( + annotation_type="chunk", value=concept_value, reference_id=relation['id'] + ) + relation_manager.save_item(relation) + relation_manager.save_item(annotation) + relation_manager.save_relation(relation, annotation) + for word in words: + if word['id'] in word_ids_to_relation: + relation_manager.save_relation(word, relation) + + def read_turns( + self, + words: List[Word], turns_path: str, + relation_manager: RelationManager + ) -> None: + xml_tree = ElementTree.parse(turns_path) + root_element = xml_tree.getroot() + for word_element in root_element: + if word_element.tag == "Turn": + word_ids_to_relation = self.get_word_ids_list(words, word_element.attrib["words"]) + relation = create_new_span_annotation(name='turn', elements=word_ids_to_relation) + turn_metadata = { + "speaker": word_element.attrib["speaker"], + "startTime": word_element.attrib["startTime"], + "endTime": word_element.attrib["endTime"], + } + annotation = create_new_single_annotation( + annotation_type="turn", value=turn_metadata, reference_id=relation['id'] + ) + relation_manager.save_item(relation) + relation_manager.save_item(annotation) + relation_manager.save_relation(relation, annotation) + for word in words: + if word['id'] in word_ids_to_relation: + relation_manager.save_relation(word, relation) + + def import_record(self, record_id: str): + print(f'record {record_id}') + relation_manager = self._record_provider.get_relation_manager(record_id) + basic_path = self._record_provider.get_path(record_id)[:-4] + + words_path = f"{basic_path}_words.xml" + concept_path = f"{basic_path}_attvalue.xml" + chunks_path = f"{basic_path}_chunks.xml" + turn_path = f"{basic_path}_turns.xml" + + words, single_annotations = self.save_words(words_path, relation_manager) + print('save_words') + self.read_concepts(words, concept_path, relation_manager) + print('read_concepts') + self.read_chunks(words, chunks_path, relation_manager) + print('read_chunks') + self.read_turns(words, turn_path, relation_manager) + print('read_turns') + relation_manager.commit() + + +if __name__ == "__main__": + luna_directory = '/Users/marcinwatroba/Desktop/asr_datasets/LUNA/LUNA.PL' + luna_record_provider = LunaRecordProvider(ExtensionPathFilter( + root_directory=luna_directory, + extension='wav' + )) + for it in list(luna_record_provider.get_all_records())[:1]: + relation_manager = luna_record_provider.get_relation_manager(it) + document = [itt for itt in relation_manager.get_all_items() if itt['type'] == 'Document'][0] + document_words = [relation_manager.get_item_by_id(item_id) + for item_id in document['word_ids']] + print(document_words) diff --git a/examples/import_dataset/luna/luna_record_provider.py b/examples/import_dataset/luna/luna_record_provider.py new file mode 100644 index 0000000000000000000000000000000000000000..56d30d38f0c7c4efc3619a9ea38a104a7c6e7c48 --- /dev/null +++ b/examples/import_dataset/luna/luna_record_provider.py @@ -0,0 +1,35 @@ +from typing import Dict, Set + +from sziszapangma.integration.path_filter import PathFilter +from sziszapangma.integration.record_id_iterator import RecordIdIterator +from sziszapangma.integration.record_path_provider import RecordPathProvider +from sziszapangma.integration.relation_manager_provider import RelationManagerProvider +from sziszapangma.model.relation_manager import RelationManager, FileRelationManager + + +class LunaRecordProvider(RecordIdIterator, RecordPathProvider, RelationManagerProvider): + _path_by_id: Dict[str, str] + + def __init__(self, path_filter: PathFilter): + self._path_by_id = dict({ + self._get_id(it): it + for it in path_filter.get_list_of_files() + }) + + def get_all_records(self) -> Set[str]: + return set(self._path_by_id.keys()) + + def get_path(self, record_id: str) -> str: + return self._path_by_id[record_id] + + def get_item_file_path(self, record_id: str, file) -> str: + return self._path_by_id[record_id] + + def get_relation_manager(self, record_id: str) -> RelationManager: + basic_path = self.get_path(record_id)[:-4] + return FileRelationManager(f'{basic_path}_ab_relations.csv', f'{basic_path}_ab_items.json') + + @staticmethod + def _get_id(record_file_path: str) -> str: + path = record_file_path.replace('.wav', '') + return '/'.join(path.split('/')[-6:]) diff --git a/examples/import_dataset/luna/relation_manager_provider.py b/examples/import_dataset/luna/relation_manager_provider.py new file mode 100644 index 0000000000000000000000000000000000000000..eb8241d19cbfcd32650f2fd366efbccf4c268655 --- /dev/null +++ b/examples/import_dataset/luna/relation_manager_provider.py @@ -0,0 +1,13 @@ +from examples.import_dataset.luna.luna_record_provider import LunaRecordProvider +from sziszapangma.model.relation_manager import RelationManager, FileRelationManager + + +class RelationManagerProvider: + _luna_record_provider: LunaRecordProvider + + def __init__(self, luna_record_provider: LunaRecordProvider): + self._luna_record_provider = luna_record_provider + + def get_relation_manager(self, record_id: str) -> RelationManager: + basic_path = self._luna_record_provider.get_path(record_id)[:-4] + return FileRelationManager(f'{basic_path}_relations.csv', f'{basic_path}_items.json') diff --git a/poetry.lock b/poetry.lock index 75d65c7fcc9eb370280cb84a668251f08fb39f8f..67d21324c466ae10b65e433b8ce9d0f339edca23 100644 --- a/poetry.lock +++ b/poetry.lock @@ -52,7 +52,7 @@ d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] [[package]] name = "certifi" -version = "2021.5.30" +version = "2021.10.8" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false @@ -60,7 +60,7 @@ python-versions = "*" [[package]] name = "charset-normalizer" -version = "2.0.4" +version = "2.0.9" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." category = "main" optional = false @@ -71,7 +71,7 @@ unicode_backport = ["unicodedata2"] [[package]] name = "click" -version = "8.0.1" +version = "8.0.3" description = "Composable command line interface toolkit" category = "main" optional = false @@ -88,21 +88,9 @@ category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -[[package]] -name = "fasttext" -version = "0.9.2" -description = "fasttext Python bindings" -category = "main" -optional = false -python-versions = "*" - -[package.dependencies] -numpy = "*" -pybind11 = ">=2.2" - [[package]] name = "flask" -version = "2.0.1" +version = "2.0.2" description = "A simple framework for building complex web applications." category = "main" optional = false @@ -120,18 +108,18 @@ dotenv = ["python-dotenv"] [[package]] name = "flask-httpauth" -version = "4.4.0" -description = "Basic and Digest HTTP authentication for Flask routes" +version = "4.5.0" +description = "HTTP authentication for Flask routes" category = "main" optional = false python-versions = "*" [package.dependencies] -Flask = "*" +flask = "*" [[package]] name = "idna" -version = "3.2" +version = "3.3" description = "Internationalized Domain Names in Applications (IDNA)" category = "main" optional = false @@ -139,7 +127,7 @@ python-versions = ">=3.5" [[package]] name = "isort" -version = "5.9.3" +version = "5.10.1" description = "A Python utility / library to sort Python imports." category = "dev" optional = false @@ -161,7 +149,7 @@ python-versions = ">=3.6" [[package]] name = "jinja2" -version = "3.0.1" +version = "3.0.3" description = "A very fast and expressive template engine." category = "main" optional = false @@ -183,7 +171,7 @@ python-versions = ">=3.6" [[package]] name = "more-itertools" -version = "8.8.0" +version = "8.12.0" description = "More routines for operating on iterables, beyond itertools" category = "dev" optional = false @@ -223,25 +211,30 @@ python-versions = ">=3.7" [[package]] name = "packaging" -version = "21.0" +version = "21.3" description = "Core utilities for Python packages" category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] -pyparsing = ">=2.0.2" +pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" [[package]] name = "pandas" -version = "1.3.1" +version = "1.3.5" description = "Powerful data structures for data analysis, time series, and statistics" category = "main" optional = false python-versions = ">=3.7.1" [package.dependencies] -numpy = ">=1.17.3" +numpy = [ + {version = ">=1.17.3", markers = "platform_machine != \"aarch64\" and platform_machine != \"arm64\" and python_version < \"3.10\""}, + {version = ">=1.19.2", markers = "platform_machine == \"aarch64\" and python_version < \"3.10\""}, + {version = ">=1.20.0", markers = "platform_machine == \"arm64\" and python_version < \"3.10\""}, + {version = ">=1.21.0", markers = "python_version >= \"3.10\""}, +] python-dateutil = ">=2.7.3" pytz = ">=2017.3" @@ -289,22 +282,11 @@ tomlkit = ">=0.6.0,<1.0.0" [[package]] name = "py" -version = "1.10.0" +version = "1.11.0" description = "library with cross-python path, ini-parsing, io, code, log facilities" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - -[[package]] -name = "pybind11" -version = "2.7.0" -description = "Seamless operability between C++11 and Python" -category = "main" -optional = false -python-versions = "!=3.0,!=3.1,!=3.2,!=3.3,!=3.4,>=2.7" - -[package.extras] -global = ["pybind11-global (==2.7.0)"] +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "pyflakes" @@ -316,7 +298,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pymongo" -version = "3.12.0" +version = "3.12.3" description = "Python driver for MongoDB <http://www.mongodb.org>" category = "main" optional = false @@ -334,11 +316,14 @@ zstd = ["zstandard"] [[package]] name = "pyparsing" -version = "2.4.7" +version = "3.0.6" description = "Python parsing module" category = "dev" optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = ">=3.6" + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "pytest" @@ -375,7 +360,7 @@ six = ">=1.5" [[package]] name = "pytz" -version = "2021.1" +version = "2021.3" description = "World timezone definitions, modern and historical" category = "main" optional = false @@ -383,7 +368,7 @@ python-versions = "*" [[package]] name = "regex" -version = "2021.7.6" +version = "2021.11.10" description = "Alternative regular expression module, to replace re." category = "dev" optional = false @@ -425,11 +410,11 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "tomlkit" -version = "0.7.2" +version = "0.8.0" description = "Style preserving TOML library" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.6,<4.0" [[package]] name = "typed-ast" @@ -441,7 +426,7 @@ python-versions = "*" [[package]] name = "typing-extensions" -version = "3.10.0.0" +version = "3.10.0.2" description = "Backported and Experimental Type Hints for Python 3.5+" category = "dev" optional = false @@ -449,7 +434,7 @@ python-versions = "*" [[package]] name = "urllib3" -version = "1.26.6" +version = "1.26.7" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false @@ -470,7 +455,7 @@ python-versions = "*" [[package]] name = "werkzeug" -version = "2.0.1" +version = "2.0.2" description = "The comprehensive WSGI web application library." category = "main" optional = false @@ -485,7 +470,7 @@ developer = [] [metadata] lock-version = "1.1" python-versions = "^3.8" -content-hash = "6c2a6af3437d43d9d55a0468d823a6da5abb2bbec9936e76ccb7729f0a014057" +content-hash = "bab8ca229cd4148ad31bc571be09a6da007f8c00cf95d0a4f52dc11ad1ad9887" [metadata.files] appdirs = [ @@ -504,55 +489,68 @@ black = [ {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"}, ] certifi = [ - {file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"}, - {file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"}, + {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, + {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, ] charset-normalizer = [ - {file = "charset-normalizer-2.0.4.tar.gz", hash = "sha256:f23667ebe1084be45f6ae0538e4a5a865206544097e4e8bbcacf42cd02a348f3"}, - {file = "charset_normalizer-2.0.4-py3-none-any.whl", hash = "sha256:0c8911edd15d19223366a194a513099a302055a962bca2cec0f54b8b63175d8b"}, + {file = "charset-normalizer-2.0.9.tar.gz", hash = "sha256:b0b883e8e874edfdece9c28f314e3dd5badf067342e42fb162203335ae61aa2c"}, + {file = "charset_normalizer-2.0.9-py3-none-any.whl", hash = "sha256:1eecaa09422db5be9e29d7fc65664e6c33bd06f9ced7838578ba40d58bdf3721"}, ] click = [ - {file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"}, - {file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"}, + {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"}, + {file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"}, ] colorama = [ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] -fasttext = [ - {file = "fasttext-0.9.2.tar.gz", hash = "sha256:665556f1f6dcb4fcbe25fa8ebcd4f71b18fa96a090de09d88d97a60cbd29dcb5"}, -] flask = [ - {file = "Flask-2.0.1-py3-none-any.whl", hash = "sha256:a6209ca15eb63fc9385f38e452704113d679511d9574d09b2cf9183ae7d20dc9"}, - {file = "Flask-2.0.1.tar.gz", hash = "sha256:1c4c257b1892aec1398784c63791cbaa43062f1f7aeb555c4da961b20ee68f55"}, + {file = "Flask-2.0.2-py3-none-any.whl", hash = "sha256:cb90f62f1d8e4dc4621f52106613488b5ba826b2e1e10a33eac92f723093ab6a"}, + {file = "Flask-2.0.2.tar.gz", hash = "sha256:7b2fb8e934ddd50731893bdcdb00fc8c0315916f9fcd50d22c7cc1a95ab634e2"}, ] flask-httpauth = [ - {file = "Flask-HTTPAuth-4.4.0.tar.gz", hash = "sha256:bcaaa7a35a3cba0b2eafd4f113b3016bf70eb78087456d96484c3c18928b813a"}, - {file = "Flask_HTTPAuth-4.4.0-py2.py3-none-any.whl", hash = "sha256:d9131122cdc5709dda63790f6e9b3142d8101447d424b0b95ffd4ee279f49539"}, + {file = "Flask-HTTPAuth-4.5.0.tar.gz", hash = "sha256:395040fda2854df800d15e84bc4a81a5f32f1d4a5e91eee554936f36f330aa29"}, + {file = "Flask_HTTPAuth-4.5.0-py3-none-any.whl", hash = "sha256:e16067ba3378ea366edf8de4b9d55f38c0a0cbddefcc0f777a54b3fce1d99392"}, ] idna = [ - {file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a"}, - {file = "idna-3.2.tar.gz", hash = "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"}, + {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, + {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, ] isort = [ - {file = "isort-5.9.3-py3-none-any.whl", hash = "sha256:e17d6e2b81095c9db0a03a8025a957f334d6ea30b26f9ec70805411e5c7c81f2"}, - {file = "isort-5.9.3.tar.gz", hash = "sha256:9c2ea1e62d871267b78307fe511c0838ba0da28698c5732d54e2790bf3ba9899"}, + {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, + {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, ] itsdangerous = [ {file = "itsdangerous-2.0.1-py3-none-any.whl", hash = "sha256:5174094b9637652bdb841a3029700391451bd092ba3db90600dea710ba28e97c"}, {file = "itsdangerous-2.0.1.tar.gz", hash = "sha256:9e724d68fc22902a1435351f84c3fb8623f303fffcc566a4cb952df8c572cff0"}, ] jinja2 = [ - {file = "Jinja2-3.0.1-py3-none-any.whl", hash = "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4"}, - {file = "Jinja2-3.0.1.tar.gz", hash = "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4"}, + {file = "Jinja2-3.0.3-py3-none-any.whl", hash = "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8"}, + {file = "Jinja2-3.0.3.tar.gz", hash = "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"}, ] markupsafe = [ + {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, @@ -561,14 +559,27 @@ markupsafe = [ {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"}, {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee"}, {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, @@ -578,13 +589,19 @@ markupsafe = [ {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1"}, {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, ] more-itertools = [ - {file = "more-itertools-8.8.0.tar.gz", hash = "sha256:83f0308e05477c68f56ea3a888172c78ed5d5b3c282addb67508e7ba6c8f813a"}, - {file = "more_itertools-8.8.0-py3-none-any.whl", hash = "sha256:2cf89ec599962f2ddc4d568a05defc40e0a587fbc10d5989713638864c36be4d"}, + {file = "more-itertools-8.12.0.tar.gz", hash = "sha256:7dc6ad46f05f545f900dd59e8dfb4e84a4827b97b3cfecb175ea0c7d247f6064"}, + {file = "more_itertools-8.12.0-py3-none-any.whl", hash = "sha256:43e6dd9942dffd72661a2c4ef383ad7da1e6a3e968a927ad7a6083ab410a688b"}, ] mypy = [ {file = "mypy-0.812-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:a26f8ec704e5a7423c8824d425086705e381b4f1dfdef6e3a1edab7ba174ec49"}, @@ -645,29 +662,35 @@ numpy = [ {file = "numpy-1.21.1.zip", hash = "sha256:dff4af63638afcc57a3dfb9e4b26d434a7a602d225b42d746ea7fe2edf1342fd"}, ] packaging = [ - {file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"}, - {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"}, + {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, + {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, ] pandas = [ - {file = "pandas-1.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:1ee8418d0f936ff2216513aa03e199657eceb67690995d427a4a7ecd2e68f442"}, - {file = "pandas-1.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d9acfca191140a518779d1095036d842d5e5bc8e8ad8b5eaad1aff90fe1870d"}, - {file = "pandas-1.3.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e323028ab192fcfe1e8999c012a0fa96d066453bb354c7e7a4a267b25e73d3c8"}, - {file = "pandas-1.3.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9d06661c6eb741ae633ee1c57e8c432bb4203024e263fe1a077fa3fda7817fdb"}, - {file = "pandas-1.3.1-cp37-cp37m-win32.whl", hash = "sha256:23c7452771501254d2ae23e9e9dac88417de7e6eff3ce64ee494bb94dc88c300"}, - {file = "pandas-1.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7150039e78a81eddd9f5a05363a11cadf90a4968aac6f086fd83e66cf1c8d1d6"}, - {file = "pandas-1.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5c09a2538f0fddf3895070579082089ff4ae52b6cb176d8ec7a4dacf7e3676c1"}, - {file = "pandas-1.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:905fc3e0fcd86b0a9f1f97abee7d36894698d2592b22b859f08ea5a8fe3d3aab"}, - {file = "pandas-1.3.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ee927c70794e875a59796fab8047098aa59787b1be680717c141cd7873818ae"}, - {file = "pandas-1.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c976e023ed580e60a82ccebdca8e1cc24d8b1fbb28175eb6521025c127dab66"}, - {file = "pandas-1.3.1-cp38-cp38-win32.whl", hash = "sha256:22f3fcc129fb482ef44e7df2a594f0bd514ac45aabe50da1a10709de1b0f9d84"}, - {file = "pandas-1.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:45656cd59ae9745a1a21271a62001df58342b59c66d50754390066db500a8362"}, - {file = "pandas-1.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:114c6789d15862508900a25cb4cb51820bfdd8595ea306bab3b53cd19f990b65"}, - {file = "pandas-1.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:527c43311894aff131dea99cf418cd723bfd4f0bcf3c3da460f3b57e52a64da5"}, - {file = "pandas-1.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb3b33dde260b1766ea4d3c6b8fbf6799cee18d50a2a8bc534cf3550b7c819a"}, - {file = "pandas-1.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c28760932283d2c9f6fa5e53d2f77a514163b9e67fd0ee0879081be612567195"}, - {file = "pandas-1.3.1-cp39-cp39-win32.whl", hash = "sha256:be12d77f7e03c40a2466ed00ccd1a5f20a574d3c622fe1516037faa31aa448aa"}, - {file = "pandas-1.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:9e1fe6722cbe27eb5891c1977bca62d456c19935352eea64d33956db46139364"}, - {file = "pandas-1.3.1.tar.gz", hash = "sha256:341935a594db24f3ff07d1b34d1d231786aa9adfa84b76eab10bf42907c8aed3"}, + {file = "pandas-1.3.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:62d5b5ce965bae78f12c1c0df0d387899dd4211ec0bdc52822373f13a3a022b9"}, + {file = "pandas-1.3.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:adfeb11be2d54f275142c8ba9bf67acee771b7186a5745249c7d5a06c670136b"}, + {file = "pandas-1.3.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:60a8c055d58873ad81cae290d974d13dd479b82cbb975c3e1fa2cf1920715296"}, + {file = "pandas-1.3.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd541ab09e1f80a2a1760032d665f6e032d8e44055d602d65eeea6e6e85498cb"}, + {file = "pandas-1.3.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2651d75b9a167cc8cc572cf787ab512d16e316ae00ba81874b560586fa1325e0"}, + {file = "pandas-1.3.5-cp310-cp310-win_amd64.whl", hash = "sha256:aaf183a615ad790801fa3cf2fa450e5b6d23a54684fe386f7e3208f8b9bfbef6"}, + {file = "pandas-1.3.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:344295811e67f8200de2390093aeb3c8309f5648951b684d8db7eee7d1c81fb7"}, + {file = "pandas-1.3.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:552020bf83b7f9033b57cbae65589c01e7ef1544416122da0c79140c93288f56"}, + {file = "pandas-1.3.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5cce0c6bbeb266b0e39e35176ee615ce3585233092f685b6a82362523e59e5b4"}, + {file = "pandas-1.3.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d28a3c65463fd0d0ba8bbb7696b23073efee0510783340a44b08f5e96ffce0c"}, + {file = "pandas-1.3.5-cp37-cp37m-win32.whl", hash = "sha256:a62949c626dd0ef7de11de34b44c6475db76995c2064e2d99c6498c3dba7fe58"}, + {file = "pandas-1.3.5-cp37-cp37m-win_amd64.whl", hash = "sha256:8025750767e138320b15ca16d70d5cdc1886e8f9cc56652d89735c016cd8aea6"}, + {file = "pandas-1.3.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fe95bae4e2d579812865db2212bb733144e34d0c6785c0685329e5b60fcb85dd"}, + {file = "pandas-1.3.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f261553a1e9c65b7a310302b9dbac31cf0049a51695c14ebe04e4bfd4a96f02"}, + {file = "pandas-1.3.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b6dbec5f3e6d5dc80dcfee250e0a2a652b3f28663492f7dab9a24416a48ac39"}, + {file = "pandas-1.3.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3bc49af96cd6285030a64779de5b3688633a07eb75c124b0747134a63f4c05f"}, + {file = "pandas-1.3.5-cp38-cp38-win32.whl", hash = "sha256:b6b87b2fb39e6383ca28e2829cddef1d9fc9e27e55ad91ca9c435572cdba51bf"}, + {file = "pandas-1.3.5-cp38-cp38-win_amd64.whl", hash = "sha256:a395692046fd8ce1edb4c6295c35184ae0c2bbe787ecbe384251da609e27edcb"}, + {file = "pandas-1.3.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bd971a3f08b745a75a86c00b97f3007c2ea175951286cdda6abe543e687e5f2f"}, + {file = "pandas-1.3.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37f06b59e5bc05711a518aa10beaec10942188dccb48918bb5ae602ccbc9f1a0"}, + {file = "pandas-1.3.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c21778a688d3712d35710501f8001cdbf96eb70a7c587a3d5613573299fdca6"}, + {file = "pandas-1.3.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3345343206546545bc26a05b4602b6a24385b5ec7c75cb6059599e3d56831da2"}, + {file = "pandas-1.3.5-cp39-cp39-win32.whl", hash = "sha256:c69406a2808ba6cf580c2255bcf260b3f214d2664a3a4197d0e640f573b46fd3"}, + {file = "pandas-1.3.5-cp39-cp39-win_amd64.whl", hash = "sha256:32e1a26d5ade11b547721a72f9bfc4bd113396947606e00d5b4a5b79b3dcb006"}, + {file = "pandas-1.3.5.tar.gz", hash = "sha256:1e4285f5de1012de20ca46b188ccf33521bff61ba5c5ebd78b4fb28e5416a9f1"}, ] pastel = [ {file = "pastel-0.2.1-py2.py3-none-any.whl", hash = "sha256:4349225fcdf6c2bb34d483e523475de5bb04a5c10ef711263452cb37d7dd4364"}, @@ -686,120 +709,125 @@ poethepoet = [ {file = "poethepoet-0.10.0.tar.gz", hash = "sha256:70b97cb194b978dc464c70793e85e6f746cddf82b84a38bfb135946ad71ae19c"}, ] py = [ - {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, - {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, -] -pybind11 = [ - {file = "pybind11-2.7.0-py2.py3-none-any.whl", hash = "sha256:71dfd6e61f6aef3e24eda3b9770a0d53072346871f9f5a0510598ec86b5f9dc2"}, - {file = "pybind11-2.7.0.tar.gz", hash = "sha256:3e2a9a94396fbb27e75acf28d3de26e029576be1d4b38acc846ae08ef0eb3033"}, + {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, + {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, ] pyflakes = [ {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"}, {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, ] pymongo = [ - {file = "pymongo-3.12.0-cp27-cp27m-macosx_10_14_intel.whl", hash = "sha256:072ba7cb65c8aa4d5c5659bf6722ee85781c9d7816dc00679b8b6f3dff1ddafc"}, - {file = "pymongo-3.12.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:d6e11ffd43184d529d6752d6dcb62b994f903038a17ea2168ef1910c96324d26"}, - {file = "pymongo-3.12.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:7412a36798966624dc4c57d64aa43c2d1100b348abd98daaac8e99e57d87e1d7"}, - {file = "pymongo-3.12.0-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e8a82e35d52ad6f867e88096a1a2b9bdc7ec4d5e65c7b4976a248bf2d1a32a93"}, - {file = "pymongo-3.12.0-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:dcd3d0009fbb6e454d729f8b22d0063bd9171c31a55e0f0271119bd4f2700023"}, - {file = "pymongo-3.12.0-cp27-cp27m-win32.whl", hash = "sha256:1bc6fe7279ff40c6818db002bf5284aa03ec181ea1b1ceaeee33c289d412afa7"}, - {file = "pymongo-3.12.0-cp27-cp27m-win_amd64.whl", hash = "sha256:e2b7670c0c8c6b501464150dd49dd0d6be6cb7f049e064124911cec5514fa19e"}, - {file = "pymongo-3.12.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:316c1b8723afa9870567cd6dff35d440b2afeda53aa13da6c5ab85f98ed6f5ca"}, - {file = "pymongo-3.12.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:255a35bf29185f44b412e31a927d9dcedda7c2c380127ecc4fbf2f61b72fa978"}, - {file = "pymongo-3.12.0-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ffbae429ba9e42d0582d3ac63fdb410338892468a2107d8ff68228ec9a39a0ed"}, - {file = "pymongo-3.12.0-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c188db6cf9e14dbbb42f5254292be96f05374a35e7dfa087cc2140f0ff4f10f6"}, - {file = "pymongo-3.12.0-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:6fb3f85870ae26896bb44e67db94045f2ebf00c5d41e6b66cdcbb5afd644fc18"}, - {file = "pymongo-3.12.0-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:aaa038eafb7186a4abbb311fcf20724be9363645882bbce540bef4797e812a7a"}, - {file = "pymongo-3.12.0-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:7d98ce3c42921bb91566121b658e0d9d59a9082a9bd6f473190607ff25ab637f"}, - {file = "pymongo-3.12.0-cp34-cp34m-win32.whl", hash = "sha256:b0a0cf39f589e52d801fdef418305562bc030cdf8929217463c8433c65fd5c2f"}, - {file = "pymongo-3.12.0-cp34-cp34m-win_amd64.whl", hash = "sha256:ceae3ab9e11a27aaab42878f1d203600dfd24f0e43678b47298219a0f10c0d30"}, - {file = "pymongo-3.12.0-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:5e574664f1468872cd40f74e4811e22b1aa4de9399d6bcfdf1ee6ea94c017fcf"}, - {file = "pymongo-3.12.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73b400fdc22de84bae0dbf1a22613928a41612ec0a3d6ed47caf7ad4d3d0f2ff"}, - {file = "pymongo-3.12.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:cbf8672edeb7b7128c4a939274801f0e32bbf5159987815e3d1eace625264a46"}, - {file = "pymongo-3.12.0-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:a634a4730ce0b0934ed75e45beba730968e12b4dafbb22f69b3b2f616d9e644e"}, - {file = "pymongo-3.12.0-cp35-cp35m-manylinux2014_i686.whl", hash = "sha256:c55782a55f4a013a78ac5b6ee4b8731a192dea7ab09f1b6b3044c96d5128edd4"}, - {file = "pymongo-3.12.0-cp35-cp35m-manylinux2014_ppc64le.whl", hash = "sha256:11f9e0cfc84ade088a38df2708d0b958bb76360181df1b2e1e1a41beaa57952b"}, - {file = "pymongo-3.12.0-cp35-cp35m-manylinux2014_s390x.whl", hash = "sha256:186104a94d39b8412f8e3de385acd990a628346a4402d4f3a288a82b8660bd22"}, - {file = "pymongo-3.12.0-cp35-cp35m-manylinux2014_x86_64.whl", hash = "sha256:70761fd3c576b027eec882b43ee0a8e5b22ff9c20cdf4d0400e104bc29e53e34"}, - {file = "pymongo-3.12.0-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:333bfad77aa9cd11711febfb75eed0bb537a1d022e1c252714dad38993590240"}, - {file = "pymongo-3.12.0-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:fa8957e9a1b202cb45e6b839c241cd986c897be1e722b81d2f32e9c6aeee80b0"}, - {file = "pymongo-3.12.0-cp35-cp35m-win32.whl", hash = "sha256:4ba0def4abef058c0e5101e05e3d5266e6fffb9795bbf8be0fe912a7361a0209"}, - {file = "pymongo-3.12.0-cp35-cp35m-win_amd64.whl", hash = "sha256:a0e5dff6701fa615f165306e642709e1c1550d5b237c5a7a6ea299886828bd50"}, - {file = "pymongo-3.12.0-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:b542d56ed1b8d5cf3bb36326f814bd2fbe8812dfd2582b80a15689ea433c0e35"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a325600c83e61e3c9cebc0c2b1c8c4140fa887f789085075e8f44c8ff2547eb9"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:48d5bc80ab0af6b60c4163c5617f5cd23f2f880d7600940870ea5055816af024"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c5cab230e7cabdae9ff23c12271231283efefb944c1b79bed79a91beb65ba547"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:d73e10772152605f6648ba4410318594f1043bbfe36d2fadee7c4b8912eff7c5"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:b1c4874331ab960429caca81acb9d2932170d66d6d6f87e65dc4507a85aca152"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:a3566acfbcde46911c52810374ecc0354fdb841284a3efef6ff7105bc007e9a8"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:b3b5b3cbc3fdf4fcfa292529df2a85b5d9c7053913a739d3069af1e12e12219f"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd3854148005c808c485c754a184c71116372263709958b42aefbef2e5dd373a"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f55c1ddcc1f6050b07d468ce594f55dbf6107b459e16f735d26818d7be1e9538"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ced944dcdd561476deef7cb7bfd4987c69fffbfeff6d02ca4d5d4fd592d559b7"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78ecb8d42f50d393af912bfb1fb1dcc9aabe9967973efb49ee577e8f1cea494c"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1970cfe2aec1bf74b40cf30c130ad10cd968941694630386db33e1d044c22a2e"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b8bf42d3b32f586f4c9e37541769993783a534ad35531ce8a4379f6fa664fba9"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:bc9ac81e73573516070d24ce15da91281922811f385645df32bd3c8a45ab4684"}, - {file = "pymongo-3.12.0-cp36-cp36m-win32.whl", hash = "sha256:d04ca462cb99077e6c059e97c072957caf2918e6e4191e3161c01c439e0193de"}, - {file = "pymongo-3.12.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f2acf9bbcd514e901f82c4ca6926bbd2ae61716728f110b4343eb0a69612d018"}, - {file = "pymongo-3.12.0-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:b754240daafecd9d5fce426b0fbaaed03f4ebb130745c8a4ae9231fffb8d75e5"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:af586e85144023686fb0af09c8cdf672484ea182f352e7ceead3d832de381e1b"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fe5872ce6f9627deac8314bdffd3862624227c3de4c17ef0cc78bbf0402999eb"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:f6977a520bd96e097c8a37a8cbb9faa1ea99d21bf84190195056e25f688af73d"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:2dbfbbded947a83a3dffc2bd1ec4750c17e40904692186e2c55a3ad314ca0222"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:a752ecd1a26000a6d67be7c9a2e93801994a8b3f866ac95b672fbc00225ca91a"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:1bab889ae7640eba739f67fcbf8eff252dddc60d4495e6ddd3a87cd9a95fdb52"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:f94c7d22fb36b184734dded7345a04ec5f95130421c775b8b0c65044ef073f34"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec5ca7c0007ce268048bbe0ffc6846ed1616cf3d8628b136e81d5e64ff3f52a2"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7c72d08acdf573455b2b9d2b75b8237654841d63a48bc2327dc102c6ee89b75a"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b6ea08758b6673610b3c5bdf47189286cf9c58b1077558706a2f6f8744922527"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46d5ec90276f71af3a29917b30f2aec2315a2759b5f8d45b3b63a07ca8a070a3"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:625befa3bc9b40746a749115cc6a15bf20b9bd7597ca55d646205b479a2c99c7"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d1131562ddc2ea8a446f66c2648d7dabec2b3816fc818528eb978a75a6d23b2e"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:eee42a1cc06565f6b21caa1f504ec15e07de7ebfd520ab57f8cb3308bc118e22"}, - {file = "pymongo-3.12.0-cp37-cp37m-win32.whl", hash = "sha256:94d38eba4d1b5eb3e6bfece0651b855a35c44f32fd91f512ab4ba41b8c0d3e66"}, - {file = "pymongo-3.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:e018a4921657c2d3f89c720b7b90b9182e277178a04a7e9542cc79d7d787ca51"}, - {file = "pymongo-3.12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7c6a9948916a7bbcc6d3a9f6fb75db1acb5546078023bfb3db6efabcd5a67527"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e9faf8d4712d5ea301d74abfcf6dafe4b7f4af7936e91f283b0ad7bf69ed3e3a"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cc2894fe91f31a513860238ede69fe47fada21f9e7ddfe73f7f9fef93a971e41"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:053b4ebf91c7395d1fcd2ce6a9edff0024575b7b2de6781554a4114448a8adc9"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:39dafa2eaf577d1969f289dc9a44501859a1897eb45bd589e93ce843fc610800"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:246ec420e4c8744fceb4e259f906211b9c198e1f345e6158dcd7cbad3737e11e"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:208debdcf76ed39ebf24f38509f50dc1c100e31e8653817fedb8e1f867850a13"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:18290649759f9db660972442aa606f845c368db9b08c4c73770f6da14113569b"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:657ad80de8ec9ed656f28844efc801a0802961e8c6a85038d97ff6f555ef4919"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b772bab31cbd9cb911e41e1a611ebc9497f9a32a7348e2747c38210f75c00f41"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2399a85b54f68008e483b2871f4a458b4c980469c7fe921595ede073e4844f1e"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e66780f14c2efaf989cd3ac613b03ee6a8e3a0ba7b96c0bb14adca71a427e55"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02dc0b0f48ed3cd06c13b7e31b066bf91e00dac5f8147b0a0a45f9009bfab857"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:070a4ef689c9438a999ec3830e69b208ff0d12251846e064d947f97d819d1d05"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:db93608a246da44d728842b8fa9e45aa9782db76955f634a707739a8d53ff544"}, - {file = "pymongo-3.12.0-cp38-cp38-win32.whl", hash = "sha256:5af390fa9faf56c93252dab09ea57cd020c9123aa921b63a0ed51832fdb492e7"}, - {file = "pymongo-3.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:a2239556ff7241584ce57be1facf25081669bb457a9e5cbe68cce4aae6567aa1"}, - {file = "pymongo-3.12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cda9e628b1315beec8341e8c04aac9a0b910650b05e0751e42e399d5694aeacb"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:845a8b83798b2fb11b09928413cb32692866bfbc28830a433d9fa4c8c3720dd0"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:da8288bc4a7807c6715416deed1c57d94d5e03e93537889e002bf985be503f1a"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:a9ba2a63777027b06b116e1ea8248e66fd1bedc2c644f93124b81a91ddbf6d88"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:9a13661681d17e43009bb3e85e837aa1ec5feeea1e3654682a01b8821940f8b3"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:6b89dc51206e4971c5568c797991eaaef5dc2a6118d67165858ad11752dba055"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:701e08457183da70ed96b35a6b43e6ba1df0b47c837b063cde39a1fbe1aeda81"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:e7a33322e08021c37e89cae8ff06327503e8a1719e97c69f32c31cbf6c30d72c"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd1f49f949a658c4e8f81ed73f9aad25fcc7d4f62f767f591e749e30038c4e1d"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6d055f01b83b1a4df8bb0c61983d3bdffa913764488910af3620e5c2450bf83"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd6ff2192f34bd622883c745a56f492b1c9ccd44e14953e8051c33024a2947d5"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19d4bd0fc29aa405bb1781456c9cfff9fceabb68543741eb17234952dbc2bbb0"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:24f8aeec4d6b894a6128844e50ff423dd02462ee83addf503c598ee3a80ddf3d"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0b6055e0ef451ff73c93d0348d122a0750dddf323b9361de5835dac2f6cf7fc1"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6261bee7c5abadeac7497f8f1c43e521da78dd13b0a2439f526a7b0fc3788824"}, - {file = "pymongo-3.12.0-cp39-cp39-win32.whl", hash = "sha256:2e92aa32300a0b5e4175caec7769f482b292769807024a86d674b3f19b8e3755"}, - {file = "pymongo-3.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:3ce83f17f641a62a4dfb0ba1b8a3c1ced7c842f511b5450d90c030c7828e3693"}, - {file = "pymongo-3.12.0-py2.7-macosx-10.14-intel.egg", hash = "sha256:d1740776b70367277323fafb76bcf09753a5cc9824f5d705bac22a34ff3668ea"}, - {file = "pymongo-3.12.0.tar.gz", hash = "sha256:b88d1742159bc93a078733f9789f563cef26f5e370eba810476a71aa98e5fbc2"}, + {file = "pymongo-3.12.3-cp27-cp27m-macosx_10_14_intel.whl", hash = "sha256:c164eda0be9048f83c24b9b2656900041e069ddf72de81c17d874d0c32f6079f"}, + {file = "pymongo-3.12.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:a055d29f1302892a9389a382bed10a3f77708bcf3e49bfb76f7712fa5f391cc6"}, + {file = "pymongo-3.12.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:8c7ad5cab282f53b9d78d51504330d1c88c83fbe187e472c07e6908a0293142e"}, + {file = "pymongo-3.12.3-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a766157b195a897c64945d4ff87b050bb0e763bb78f3964e996378621c703b00"}, + {file = "pymongo-3.12.3-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c8d6bf6fcd42cde2f02efb8126812a010c297eacefcd090a609639d2aeda6185"}, + {file = "pymongo-3.12.3-cp27-cp27m-win32.whl", hash = "sha256:5fdffb0cfeb4dc8646a5381d32ec981ae8472f29c695bf09e8f7a8edb2db12ca"}, + {file = "pymongo-3.12.3-cp27-cp27m-win_amd64.whl", hash = "sha256:648fcfd8e019b122b7be0e26830a3a2224d57c3e934f19c1e53a77b8380e6675"}, + {file = "pymongo-3.12.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:3f0ac6e0203bd88863649e6ed9c7cfe53afab304bc8225f2597c4c0a74e4d1f0"}, + {file = "pymongo-3.12.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:71c0db2c313ea8a80825fb61b7826b8015874aec29ee6364ade5cb774fe4511b"}, + {file = "pymongo-3.12.3-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5b779e87300635b8075e8d5cfd4fdf7f46078cd7610c381d956bca5556bb8f97"}, + {file = "pymongo-3.12.3-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:351a2efe1c9566c348ad0076f4bf541f4905a0ebe2d271f112f60852575f3c16"}, + {file = "pymongo-3.12.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0a02313e71b7c370c43056f6b16c45effbb2d29a44d24403a3d5ba6ed322fa3f"}, + {file = "pymongo-3.12.3-cp310-cp310-manylinux1_i686.whl", hash = "sha256:d3082e5c4d7b388792124f5e805b469109e58f1ab1eb1fbd8b998e8ab766ffb7"}, + {file = "pymongo-3.12.3-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:514e78d20d8382d5b97f32b20c83d1d0452c302c9a135f0a9022236eb9940fda"}, + {file = "pymongo-3.12.3-cp310-cp310-manylinux2014_i686.whl", hash = "sha256:b1b5be40ebf52c3c67ee547e2c4435ed5bc6352f38d23e394520b686641a6be4"}, + {file = "pymongo-3.12.3-cp310-cp310-manylinux2014_ppc64le.whl", hash = "sha256:58db209da08a502ce6948841d522dcec80921d714024354153d00b054571993c"}, + {file = "pymongo-3.12.3-cp310-cp310-manylinux2014_s390x.whl", hash = "sha256:5296e5e69243ffd76bd919854c4da6630ae52e46175c804bc4c0e050d937b705"}, + {file = "pymongo-3.12.3-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:51d1d061df3995c2332ae78f036492cc188cb3da8ef122caeab3631a67bb477e"}, + {file = "pymongo-3.12.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:463b974b7f49d65a16ca1435bc1c25a681bb7d630509dd23b2e819ed36da0b7f"}, + {file = "pymongo-3.12.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e099b79ccf7c40f18b149a64d3d10639980035f9ceb223169dd806ff1bb0d9cc"}, + {file = "pymongo-3.12.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:27e5ea64332385385b75414888ce9d1a9806be8616d7cef4ef409f4f256c6d06"}, + {file = "pymongo-3.12.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed7d11330e443aeecab23866055e08a5a536c95d2c25333aeb441af2dbac38d2"}, + {file = "pymongo-3.12.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93111fd4e08fa889c126aa8baf5c009a941880a539c87672e04583286517450a"}, + {file = "pymongo-3.12.3-cp310-cp310-win32.whl", hash = "sha256:2301051701b27aff2cbdf83fae22b7ca883c9563dfd088033267291b46196643"}, + {file = "pymongo-3.12.3-cp310-cp310-win_amd64.whl", hash = "sha256:c7e8221278e5f9e2b6d3893cfc3a3e46c017161a57bb0e6f244826e4cee97916"}, + {file = "pymongo-3.12.3-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:7b4a9fcd95e978cd3c96cdc2096aa54705266551422cf0883c12a4044def31c6"}, + {file = "pymongo-3.12.3-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:06b64cdf5121f86b78a84e61b8f899b6988732a8d304b503ea1f94a676221c06"}, + {file = "pymongo-3.12.3-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:c8f7dd025cb0bf19e2f60a64dfc24b513c8330e0cfe4a34ccf941eafd6194d9e"}, + {file = "pymongo-3.12.3-cp34-cp34m-win32.whl", hash = "sha256:ab23b0545ec71ea346bf50a5d376d674f56205b729980eaa62cdb7871805014b"}, + {file = "pymongo-3.12.3-cp34-cp34m-win_amd64.whl", hash = "sha256:1b5cb75d2642ff7db823f509641f143f752c0d1ab03166cafea1e42e50469834"}, + {file = "pymongo-3.12.3-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:fc2048d13ff427605fea328cbe5369dce549b8c7657b0e22051a5b8831170af6"}, + {file = "pymongo-3.12.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c5f83bb59d0ff60c6fdb1f8a7b0288fbc4640b1f0fd56f5ae2387749c35d34e3"}, + {file = "pymongo-3.12.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6632b1c63d58cddc72f43ab9f17267354ddce563dd5e11eadabd222dcc808808"}, + {file = "pymongo-3.12.3-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3fedad05147b40ff8a93fcd016c421e6c159f149a2a481cfa0b94bfa3e473bab"}, + {file = "pymongo-3.12.3-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:208a61db8b8b647fb5b1ff3b52b4ed6dbced01eac3b61009958adb203596ee99"}, + {file = "pymongo-3.12.3-cp35-cp35m-win32.whl", hash = "sha256:3100a2352bdded6232b385ceda0c0a4624598c517d52c2d8cf014b7abbebd84d"}, + {file = "pymongo-3.12.3-cp35-cp35m-win_amd64.whl", hash = "sha256:3492ae1f97209c66af70e863e6420e6301cecb0a51a5efa701058aa73a8ca29e"}, + {file = "pymongo-3.12.3-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:87e18f29bac4a6be76a30e74de9c9005475e27100acf0830679420ce1fd9a6fd"}, + {file = "pymongo-3.12.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:b3e08aef4ea05afbc0a70cd23c13684e7f5e074f02450964ec5cfa1c759d33d2"}, + {file = "pymongo-3.12.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:e66b3c9f8b89d4fd58a59c04fdbf10602a17c914fbaaa5e6ea593f1d54b06362"}, + {file = "pymongo-3.12.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:5d67dbc8da2dac1644d71c1839d12d12aa333e266a9964d5b1a49feed036bc94"}, + {file = "pymongo-3.12.3-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:a351986d6c9006308f163c359ced40f80b6cffb42069f3e569b979829951038d"}, + {file = "pymongo-3.12.3-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:5296669bff390135528001b4e48d33a7acaffcd361d98659628ece7f282f11aa"}, + {file = "pymongo-3.12.3-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:9d5b66d457d2c5739c184a777455c8fde7ab3600a56d8bbebecf64f7c55169e1"}, + {file = "pymongo-3.12.3-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:1c771f1a8b3cd2d697baaf57e9cfa4ae42371cacfbea42ea01d9577c06d92f96"}, + {file = "pymongo-3.12.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81a3ebc33b1367f301d1c8eda57eec4868e951504986d5d3fe437479dcdac5b2"}, + {file = "pymongo-3.12.3-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cf113a46d81cff0559d57aa66ffa473d57d1a9496f97426318b6b5b14fdec1c"}, + {file = "pymongo-3.12.3-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64b9122be1c404ce4eb367ad609b590394587a676d84bfed8e03c3ce76d70560"}, + {file = "pymongo-3.12.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c6c71e198b36f0f0dfe354f06d3655ecfa30d69493a1da125a9a54668aad652"}, + {file = "pymongo-3.12.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33ab8c031f788609924e329003088831045f683931932a52a361d4a955b7dce2"}, + {file = "pymongo-3.12.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e2b4c95c47fb81b19ea77dc1c50d23af3eba87c9628fcc2e03d44124a3d336ea"}, + {file = "pymongo-3.12.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4e0a3ea7fd01cf0a36509f320226bd8491e0f448f00b8cb89f601c109f6874e1"}, + {file = "pymongo-3.12.3-cp36-cp36m-win32.whl", hash = "sha256:dfec57f15f53d677b8e4535695ff3f37df7f8fe431f2efa8c3c8c4025b53d1eb"}, + {file = "pymongo-3.12.3-cp36-cp36m-win_amd64.whl", hash = "sha256:c22591cff80188dd8543be0b559d0c807f7288bd353dc0bcfe539b4588b3a5cd"}, + {file = "pymongo-3.12.3-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:7738147cd9dbd6d18d5593b3491b4620e13b61de975fd737283e4ad6c255c273"}, + {file = "pymongo-3.12.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:be1f10145f7ea76e3e836fdc5c8429c605675bdcddb0bca9725ee6e26874c00c"}, + {file = "pymongo-3.12.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:295a5beaecb7bf054c1c6a28749ed72b19f4d4b61edcd8a0815d892424baf780"}, + {file = "pymongo-3.12.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:320f8734553c50cffe8a8e1ae36dfc7d7be1941c047489db20a814d2a170d7b5"}, + {file = "pymongo-3.12.3-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:5d20072d81cbfdd8e15e6a0c91fc7e3a4948c71e0adebfc67d3b4bcbe8602711"}, + {file = "pymongo-3.12.3-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:2c46a0afef69d61938a6fe32c3afd75b91dec3ab3056085dc72abbeedcc94166"}, + {file = "pymongo-3.12.3-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:5f530f35e1a57d4360eddcbed6945aecdaee2a491cd3f17025e7b5f2eea88ee7"}, + {file = "pymongo-3.12.3-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:6526933760ee1e6090db808f1690a111ec409699c1990efc96f134d26925c37f"}, + {file = "pymongo-3.12.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95d15cf81cd2fb926f2a6151a9f94c7aacc102b415e72bc0e040e29332b6731c"}, + {file = "pymongo-3.12.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0d52a70350ec3dfc39b513df12b03b7f4c8f8ec6873bbf958299999db7b05eb1"}, + {file = "pymongo-3.12.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9252c991e8176b5a2fa574c5ab9a841679e315f6e576eb7cf0bd958f3e39b0ad"}, + {file = "pymongo-3.12.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:145d78c345a38011497e55aff22c0f8edd40ee676a6810f7e69563d68a125e83"}, + {file = "pymongo-3.12.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a8e0a086dbbee406cc6f603931dfe54d1cb2fba585758e06a2de01037784b737"}, + {file = "pymongo-3.12.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f6d5443104f89a840250087863c91484a72f254574848e951d1bdd7d8b2ce7c9"}, + {file = "pymongo-3.12.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6f93dbfa5a461107bc3f5026e0d5180499e13379e9404f07a9f79eb5e9e1303d"}, + {file = "pymongo-3.12.3-cp37-cp37m-win32.whl", hash = "sha256:c9d212e2af72d5c8d082775a43eb726520e95bf1c84826440f74225843975136"}, + {file = "pymongo-3.12.3-cp37-cp37m-win_amd64.whl", hash = "sha256:320a1fe403dd83a35709fcf01083d14bc1462e9789b711201349a9158db3a87e"}, + {file = "pymongo-3.12.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a1ba93be779a9b8e5e44f5c133dc1db4313661cead8a2fd27661e6cb8d942ee9"}, + {file = "pymongo-3.12.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:4294f2c1cd069b793e31c2e6d7ac44b121cf7cedccd03ebcc30f3fc3417b314a"}, + {file = "pymongo-3.12.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:845b178bd127bb074835d2eac635b980c58ec5e700ebadc8355062df708d5a71"}, + {file = "pymongo-3.12.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:176fdca18391e1206c32fb1d8265628a84d28333c20ad19468d91e3e98312cd1"}, + {file = "pymongo-3.12.3-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:28bfd5244d32faf3e49b5a8d1fab0631e922c26e8add089312e4be19fb05af50"}, + {file = "pymongo-3.12.3-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:f38b35ecd2628bf0267761ed659e48af7e620a7fcccfccf5774e7308fb18325c"}, + {file = "pymongo-3.12.3-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:cebb3d8bcac4a6b48be65ebbc5c9881ed4a738e27bb96c86d9d7580a1fb09e05"}, + {file = "pymongo-3.12.3-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:80710d7591d579442c67a3bc7ae9dcba9ff95ea8414ac98001198d894fc4ff46"}, + {file = "pymongo-3.12.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89d7baa847383b9814de640c6f1a8553d125ec65e2761ad146ea2e75a7ad197c"}, + {file = "pymongo-3.12.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:602284e652bb56ca8760f8e88a5280636c5b63d7946fca1c2fe0f83c37dffc64"}, + {file = "pymongo-3.12.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bfc2d763d05ec7211313a06e8571236017d3e61d5fef97fcf34ec4b36c0b6556"}, + {file = "pymongo-3.12.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a6e4dccae8ef5dd76052647d78f02d5d0ffaff1856277d951666c54aeba3ad2"}, + {file = "pymongo-3.12.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1fc4d3985868860b6585376e511bb32403c5ffb58b0ed913496c27fd791deea"}, + {file = "pymongo-3.12.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e4e5d163e6644c2bc84dd9f67bfa89288c23af26983d08fefcc2cbc22f6e57e6"}, + {file = "pymongo-3.12.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:8d92c6bb9174d47c2257528f64645a00bbc6324a9ff45a626192797aff01dc14"}, + {file = "pymongo-3.12.3-cp38-cp38-win32.whl", hash = "sha256:b0db9a4691074c347f5d7ee830ab3529bc5ad860939de21c1f9c403daf1eda9a"}, + {file = "pymongo-3.12.3-cp38-cp38-win_amd64.whl", hash = "sha256:d81047341ab56061aa4b6823c54d4632579c3b16e675089e8f520e9b918a133b"}, + {file = "pymongo-3.12.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:07398d8a03545b98282f459f2603a6bb271f4448d484ed7f411121a519a7ea48"}, + {file = "pymongo-3.12.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:b7df0d99e189b7027d417d4bfd9b8c53c9c7ed5a0a1495d26a6f547d820eca88"}, + {file = "pymongo-3.12.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:a283425e6a474facd73072d8968812d1d9058490a5781e022ccf8895500b83ce"}, + {file = "pymongo-3.12.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:2577b8161eeae4dd376d13100b2137d883c10bb457dd08935f60c9f9d4b5c5f6"}, + {file = "pymongo-3.12.3-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:517b09b1dd842390a965a896d1327c55dfe78199c9f5840595d40facbcd81854"}, + {file = "pymongo-3.12.3-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:2567885ff0c8c7c0887ba6cefe4ae4af96364a66a7069f924ce0cd12eb971d04"}, + {file = "pymongo-3.12.3-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:71c5c200fd37a5322706080b09c3ec8907cf01c377a7187f354fc9e9e13abc73"}, + {file = "pymongo-3.12.3-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:14dee106a10b77224bba5efeeb6aee025aabe88eb87a2b850c46d3ee55bdab4a"}, + {file = "pymongo-3.12.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f340a2a908644ea6cccd399be0fb308c66e05d2800107345f9f0f0d59e1731c4"}, + {file = "pymongo-3.12.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b4c535f524c9d8c86c3afd71d199025daa070859a2bdaf94a298120b0de16db"}, + {file = "pymongo-3.12.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8455176fd1b86de97d859fed4ae0ef867bf998581f584c7a1a591246dfec330f"}, + {file = "pymongo-3.12.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf254a1a95e95fdf4eaa25faa1ea450a6533ed7a997f9f8e49ab971b61ea514d"}, + {file = "pymongo-3.12.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a8a3540e21213cb8ce232e68a7d0ee49cdd35194856c50b8bd87eeb572fadd42"}, + {file = "pymongo-3.12.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0e7a5d0b9077e8c3e57727f797ee8adf12e1d5e7534642230d98980d160d1320"}, + {file = "pymongo-3.12.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0be605bfb8461384a4cb81e80f51eb5ca1b89851f2d0e69a75458c788a7263a4"}, + {file = "pymongo-3.12.3-cp39-cp39-win32.whl", hash = "sha256:2157d68f85c28688e8b723bbe70c8013e0aba5570e08c48b3562f74d33fc05c4"}, + {file = "pymongo-3.12.3-cp39-cp39-win_amd64.whl", hash = "sha256:dfa217bf8cf3ff6b30c8e6a89014e0c0e7b50941af787b970060ae5ba04a4ce5"}, + {file = "pymongo-3.12.3-py2.7-macosx-10.14-intel.egg", hash = "sha256:d81299f63dc33cc172c26faf59cc54dd795fc6dd5821a7676cca112a5ee8bbd6"}, + {file = "pymongo-3.12.3.tar.gz", hash = "sha256:0a89cadc0062a5e53664dde043f6c097172b8c1c5f0094490095282ff9995a5f"}, ] pyparsing = [ - {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, - {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, + {file = "pyparsing-3.0.6-py3-none-any.whl", hash = "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4"}, + {file = "pyparsing-3.0.6.tar.gz", hash = "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81"}, ] pytest = [ {file = "pytest-5.4.3-py3-none-any.whl", hash = "sha256:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1"}, @@ -810,51 +838,84 @@ python-dateutil = [ {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, ] pytz = [ - {file = "pytz-2021.1-py2.py3-none-any.whl", hash = "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"}, - {file = "pytz-2021.1.tar.gz", hash = "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da"}, + {file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"}, + {file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"}, ] regex = [ - {file = "regex-2021.7.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e6a1e5ca97d411a461041d057348e578dc344ecd2add3555aedba3b408c9f874"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:6afe6a627888c9a6cfbb603d1d017ce204cebd589d66e0703309b8048c3b0854"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ccb3d2190476d00414aab36cca453e4596e8f70a206e2aa8db3d495a109153d2"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:ed693137a9187052fc46eedfafdcb74e09917166362af4cc4fddc3b31560e93d"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:99d8ab206a5270c1002bfcf25c51bf329ca951e5a169f3b43214fdda1f0b5f0d"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:b85ac458354165405c8a84725de7bbd07b00d9f72c31a60ffbf96bb38d3e25fa"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:3f5716923d3d0bfb27048242a6e0f14eecdb2e2a7fac47eda1d055288595f222"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5983c19d0beb6af88cb4d47afb92d96751fb3fa1784d8785b1cdf14c6519407"}, - {file = "regex-2021.7.6-cp36-cp36m-win32.whl", hash = "sha256:c92831dac113a6e0ab28bc98f33781383fe294df1a2c3dfd1e850114da35fd5b"}, - {file = "regex-2021.7.6-cp36-cp36m-win_amd64.whl", hash = "sha256:791aa1b300e5b6e5d597c37c346fb4d66422178566bbb426dd87eaae475053fb"}, - {file = "regex-2021.7.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:59506c6e8bd9306cd8a41511e32d16d5d1194110b8cfe5a11d102d8b63cf945d"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:564a4c8a29435d1f2256ba247a0315325ea63335508ad8ed938a4f14c4116a5d"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:59c00bb8dd8775473cbfb967925ad2c3ecc8886b3b2d0c90a8e2707e06c743f0"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:9a854b916806c7e3b40e6616ac9e85d3cdb7649d9e6590653deb5b341a736cec"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:db2b7df831c3187a37f3bb80ec095f249fa276dbe09abd3d35297fc250385694"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:173bc44ff95bc1e96398c38f3629d86fa72e539c79900283afa895694229fe6a"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:15dddb19823f5147e7517bb12635b3c82e6f2a3a6b696cc3e321522e8b9308ad"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ddeabc7652024803666ea09f32dd1ed40a0579b6fbb2a213eba590683025895"}, - {file = "regex-2021.7.6-cp37-cp37m-win32.whl", hash = "sha256:f080248b3e029d052bf74a897b9d74cfb7643537fbde97fe8225a6467fb559b5"}, - {file = "regex-2021.7.6-cp37-cp37m-win_amd64.whl", hash = "sha256:d8bbce0c96462dbceaa7ac4a7dfbbee92745b801b24bce10a98d2f2b1ea9432f"}, - {file = "regex-2021.7.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:edd1a68f79b89b0c57339bce297ad5d5ffcc6ae7e1afdb10f1947706ed066c9c"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux1_i686.whl", hash = "sha256:422dec1e7cbb2efbbe50e3f1de36b82906def93ed48da12d1714cabcd993d7f0"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cbe23b323988a04c3e5b0c387fe3f8f363bf06c0680daf775875d979e376bd26"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:0eb2c6e0fcec5e0f1d3bcc1133556563222a2ffd2211945d7b1480c1b1a42a6f"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:1c78780bf46d620ff4fff40728f98b8afd8b8e35c3efd638c7df67be2d5cddbf"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:bc84fb254a875a9f66616ed4538542fb7965db6356f3df571d783f7c8d256edd"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:598c0a79b4b851b922f504f9f39a863d83ebdfff787261a5ed061c21e67dd761"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:875c355360d0f8d3d827e462b29ea7682bf52327d500a4f837e934e9e4656068"}, - {file = "regex-2021.7.6-cp38-cp38-win32.whl", hash = "sha256:e586f448df2bbc37dfadccdb7ccd125c62b4348cb90c10840d695592aa1b29e0"}, - {file = "regex-2021.7.6-cp38-cp38-win_amd64.whl", hash = "sha256:2fe5e71e11a54e3355fa272137d521a40aace5d937d08b494bed4529964c19c4"}, - {file = "regex-2021.7.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6110bab7eab6566492618540c70edd4d2a18f40ca1d51d704f1d81c52d245026"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4f64fc59fd5b10557f6cd0937e1597af022ad9b27d454e182485f1db3008f417"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:89e5528803566af4df368df2d6f503c84fbfb8249e6631c7b025fe23e6bd0cde"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:2366fe0479ca0e9afa534174faa2beae87847d208d457d200183f28c74eaea59"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f9392a4555f3e4cb45310a65b403d86b589adc773898c25a39184b1ba4db8985"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:2bceeb491b38225b1fee4517107b8491ba54fba77cf22a12e996d96a3c55613d"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:f98dc35ab9a749276f1a4a38ab3e0e2ba1662ce710f6530f5b0a6656f1c32b58"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:319eb2a8d0888fa6f1d9177705f341bc9455a2c8aca130016e52c7fe8d6c37a3"}, - {file = "regex-2021.7.6-cp39-cp39-win32.whl", hash = "sha256:eaf58b9e30e0e546cdc3ac06cf9165a1ca5b3de8221e9df679416ca667972035"}, - {file = "regex-2021.7.6-cp39-cp39-win_amd64.whl", hash = "sha256:4c9c3155fe74269f61e27617529b7f09552fbb12e44b1189cebbdb24294e6e1c"}, - {file = "regex-2021.7.6.tar.gz", hash = "sha256:8394e266005f2d8c6f0bc6780001f7afa3ef81a7a2111fa35058ded6fce79e4d"}, + {file = "regex-2021.11.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9345b6f7ee578bad8e475129ed40123d265464c4cfead6c261fd60fc9de00bcf"}, + {file = "regex-2021.11.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:416c5f1a188c91e3eb41e9c8787288e707f7d2ebe66e0a6563af280d9b68478f"}, + {file = "regex-2021.11.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0538c43565ee6e703d3a7c3bdfe4037a5209250e8502c98f20fea6f5fdf2965"}, + {file = "regex-2021.11.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee1227cf08b6716c85504aebc49ac827eb88fcc6e51564f010f11a406c0a667"}, + {file = "regex-2021.11.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6650f16365f1924d6014d2ea770bde8555b4a39dc9576abb95e3cd1ff0263b36"}, + {file = "regex-2021.11.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30ab804ea73972049b7a2a5c62d97687d69b5a60a67adca07eb73a0ddbc9e29f"}, + {file = "regex-2021.11.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68a067c11463de2a37157930d8b153005085e42bcb7ad9ca562d77ba7d1404e0"}, + {file = "regex-2021.11.10-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:162abfd74e88001d20cb73ceaffbfe601469923e875caf9118333b1a4aaafdc4"}, + {file = "regex-2021.11.10-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b9ed0b1e5e0759d6b7f8e2f143894b2a7f3edd313f38cf44e1e15d360e11749b"}, + {file = "regex-2021.11.10-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:473e67837f786404570eae33c3b64a4b9635ae9f00145250851a1292f484c063"}, + {file = "regex-2021.11.10-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2fee3ed82a011184807d2127f1733b4f6b2ff6ec7151d83ef3477f3b96a13d03"}, + {file = "regex-2021.11.10-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:d5fd67df77bab0d3f4ea1d7afca9ef15c2ee35dfb348c7b57ffb9782a6e4db6e"}, + {file = "regex-2021.11.10-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5d408a642a5484b9b4d11dea15a489ea0928c7e410c7525cd892f4d04f2f617b"}, + {file = "regex-2021.11.10-cp310-cp310-win32.whl", hash = "sha256:98ba568e8ae26beb726aeea2273053c717641933836568c2a0278a84987b2a1a"}, + {file = "regex-2021.11.10-cp310-cp310-win_amd64.whl", hash = "sha256:780b48456a0f0ba4d390e8b5f7c661fdd218934388cde1a974010a965e200e12"}, + {file = "regex-2021.11.10-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:dba70f30fd81f8ce6d32ddeef37d91c8948e5d5a4c63242d16a2b2df8143aafc"}, + {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1f54b9b4b6c53369f40028d2dd07a8c374583417ee6ec0ea304e710a20f80a0"}, + {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fbb9dc00e39f3e6c0ef48edee202f9520dafb233e8b51b06b8428cfcb92abd30"}, + {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666abff54e474d28ff42756d94544cdfd42e2ee97065857413b72e8a2d6a6345"}, + {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5537f71b6d646f7f5f340562ec4c77b6e1c915f8baae822ea0b7e46c1f09b733"}, + {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2e07c6a26ed4bea91b897ee2b0835c21716d9a469a96c3e878dc5f8c55bb23"}, + {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ca5f18a75e1256ce07494e245cdb146f5a9267d3c702ebf9b65c7f8bd843431e"}, + {file = "regex-2021.11.10-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:74cbeac0451f27d4f50e6e8a8f3a52ca074b5e2da9f7b505c4201a57a8ed6286"}, + {file = "regex-2021.11.10-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:3598893bde43091ee5ca0a6ad20f08a0435e93a69255eeb5f81b85e81e329264"}, + {file = "regex-2021.11.10-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:50a7ddf3d131dc5633dccdb51417e2d1910d25cbcf842115a3a5893509140a3a"}, + {file = "regex-2021.11.10-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:61600a7ca4bcf78a96a68a27c2ae9389763b5b94b63943d5158f2a377e09d29a"}, + {file = "regex-2021.11.10-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:563d5f9354e15e048465061509403f68424fef37d5add3064038c2511c8f5e00"}, + {file = "regex-2021.11.10-cp36-cp36m-win32.whl", hash = "sha256:93a5051fcf5fad72de73b96f07d30bc29665697fb8ecdfbc474f3452c78adcf4"}, + {file = "regex-2021.11.10-cp36-cp36m-win_amd64.whl", hash = "sha256:b483c9d00a565633c87abd0aaf27eb5016de23fed952e054ecc19ce32f6a9e7e"}, + {file = "regex-2021.11.10-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fff55f3ce50a3ff63ec8e2a8d3dd924f1941b250b0aac3d3d42b687eeff07a8e"}, + {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e32d2a2b02ccbef10145df9135751abea1f9f076e67a4e261b05f24b94219e36"}, + {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:53db2c6be8a2710b359bfd3d3aa17ba38f8aa72a82309a12ae99d3c0c3dcd74d"}, + {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2207ae4f64ad3af399e2d30dde66f0b36ae5c3129b52885f1bffc2f05ec505c8"}, + {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5ca078bb666c4a9d1287a379fe617a6dccd18c3e8a7e6c7e1eb8974330c626a"}, + {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd33eb9bdcfbabab3459c9ee651d94c842bc8a05fabc95edf4ee0c15a072495e"}, + {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:05b7d6d7e64efe309972adab77fc2af8907bb93217ec60aa9fe12a0dad35874f"}, + {file = "regex-2021.11.10-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:42b50fa6666b0d50c30a990527127334d6b96dd969011e843e726a64011485da"}, + {file = "regex-2021.11.10-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6e1d2cc79e8dae442b3fa4a26c5794428b98f81389af90623ffcc650ce9f6732"}, + {file = "regex-2021.11.10-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:0416f7399e918c4b0e074a0f66e5191077ee2ca32a0f99d4c187a62beb47aa05"}, + {file = "regex-2021.11.10-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:ce298e3d0c65bd03fa65ffcc6db0e2b578e8f626d468db64fdf8457731052942"}, + {file = "regex-2021.11.10-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:dc07f021ee80510f3cd3af2cad5b6a3b3a10b057521d9e6aaeb621730d320c5a"}, + {file = "regex-2021.11.10-cp37-cp37m-win32.whl", hash = "sha256:e71255ba42567d34a13c03968736c5d39bb4a97ce98188fafb27ce981115beec"}, + {file = "regex-2021.11.10-cp37-cp37m-win_amd64.whl", hash = "sha256:07856afef5ffcc052e7eccf3213317fbb94e4a5cd8177a2caa69c980657b3cb4"}, + {file = "regex-2021.11.10-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ba05430e819e58544e840a68b03b28b6d328aff2e41579037e8bab7653b37d83"}, + {file = "regex-2021.11.10-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7f301b11b9d214f83ddaf689181051e7f48905568b0c7017c04c06dfd065e244"}, + {file = "regex-2021.11.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aaa4e0705ef2b73dd8e36eeb4c868f80f8393f5f4d855e94025ce7ad8525f50"}, + {file = "regex-2021.11.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:788aef3549f1924d5c38263104dae7395bf020a42776d5ec5ea2b0d3d85d6646"}, + {file = "regex-2021.11.10-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f8af619e3be812a2059b212064ea7a640aff0568d972cd1b9e920837469eb3cb"}, + {file = "regex-2021.11.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85bfa6a5413be0ee6c5c4a663668a2cad2cbecdee367630d097d7823041bdeec"}, + {file = "regex-2021.11.10-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f23222527b307970e383433daec128d769ff778d9b29343fb3496472dc20dabe"}, + {file = "regex-2021.11.10-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:da1a90c1ddb7531b1d5ff1e171b4ee61f6345119be7351104b67ff413843fe94"}, + {file = "regex-2021.11.10-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f5be7805e53dafe94d295399cfbe5227f39995a997f4fd8539bf3cbdc8f47ca8"}, + {file = "regex-2021.11.10-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a955b747d620a50408b7fdf948e04359d6e762ff8a85f5775d907ceced715129"}, + {file = "regex-2021.11.10-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:139a23d1f5d30db2cc6c7fd9c6d6497872a672db22c4ae1910be22d4f4b2068a"}, + {file = "regex-2021.11.10-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:ca49e1ab99593438b204e00f3970e7a5f70d045267051dfa6b5f4304fcfa1dbf"}, + {file = "regex-2021.11.10-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:96fc32c16ea6d60d3ca7f63397bff5c75c5a562f7db6dec7d412f7c4d2e78ec0"}, + {file = "regex-2021.11.10-cp38-cp38-win32.whl", hash = "sha256:0617383e2fe465732af4509e61648b77cbe3aee68b6ac8c0b6fe934db90be5cc"}, + {file = "regex-2021.11.10-cp38-cp38-win_amd64.whl", hash = "sha256:a3feefd5e95871872673b08636f96b61ebef62971eab044f5124fb4dea39919d"}, + {file = "regex-2021.11.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f7f325be2804246a75a4f45c72d4ce80d2443ab815063cdf70ee8fb2ca59ee1b"}, + {file = "regex-2021.11.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:537ca6a3586931b16a85ac38c08cc48f10fc870a5b25e51794c74df843e9966d"}, + {file = "regex-2021.11.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eef2afb0fd1747f33f1ee3e209bce1ed582d1896b240ccc5e2697e3275f037c7"}, + {file = "regex-2021.11.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:432bd15d40ed835a51617521d60d0125867f7b88acf653e4ed994a1f8e4995dc"}, + {file = "regex-2021.11.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b43c2b8a330a490daaef5a47ab114935002b13b3f9dc5da56d5322ff218eeadb"}, + {file = "regex-2021.11.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:962b9a917dd7ceacbe5cd424556914cb0d636001e393b43dc886ba31d2a1e449"}, + {file = "regex-2021.11.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fa8c626d6441e2d04b6ee703ef2d1e17608ad44c7cb75258c09dd42bacdfc64b"}, + {file = "regex-2021.11.10-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3c5fb32cc6077abad3bbf0323067636d93307c9fa93e072771cf9a64d1c0f3ef"}, + {file = "regex-2021.11.10-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:cd410a1cbb2d297c67d8521759ab2ee3f1d66206d2e4328502a487589a2cb21b"}, + {file = "regex-2021.11.10-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e6096b0688e6e14af6a1b10eaad86b4ff17935c49aa774eac7c95a57a4e8c296"}, + {file = "regex-2021.11.10-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:529801a0d58809b60b3531ee804d3e3be4b412c94b5d267daa3de7fadef00f49"}, + {file = "regex-2021.11.10-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0f594b96fe2e0821d026365f72ac7b4f0b487487fb3d4aaf10dd9d97d88a9737"}, + {file = "regex-2021.11.10-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2409b5c9cef7054dde93a9803156b411b677affc84fca69e908b1cb2c540025d"}, + {file = "regex-2021.11.10-cp39-cp39-win32.whl", hash = "sha256:3b5df18db1fccd66de15aa59c41e4f853b5df7550723d26aa6cb7f40e5d9da5a"}, + {file = "regex-2021.11.10-cp39-cp39-win_amd64.whl", hash = "sha256:83ee89483672b11f8952b158640d0c0ff02dc43d9cb1b70c1564b49abe92ce29"}, + {file = "regex-2021.11.10.tar.gz", hash = "sha256:f341ee2df0999bfdf7a95e448075effe0db212a59387de1a70690e4acb03d4c6"}, ] requests = [ {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"}, @@ -869,8 +930,8 @@ toml = [ {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] tomlkit = [ - {file = "tomlkit-0.7.2-py2.py3-none-any.whl", hash = "sha256:173ad840fa5d2aac140528ca1933c29791b79a374a0861a80347f42ec9328117"}, - {file = "tomlkit-0.7.2.tar.gz", hash = "sha256:d7a454f319a7e9bd2e249f239168729327e4dd2d27b17dc68be264ad1ce36754"}, + {file = "tomlkit-0.8.0-py3-none-any.whl", hash = "sha256:b824e3466f1d475b2b5f1c392954c6cb7ea04d64354ff7300dc7c14257dc85db"}, + {file = "tomlkit-0.8.0.tar.gz", hash = "sha256:29e84a855712dfe0e88a48f6d05c21118dbafb283bb2eed614d46f80deb8e9a1"}, ] typed-ast = [ {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6"}, @@ -905,19 +966,19 @@ typed-ast = [ {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"}, ] typing-extensions = [ - {file = "typing_extensions-3.10.0.0-py2-none-any.whl", hash = "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497"}, - {file = "typing_extensions-3.10.0.0-py3-none-any.whl", hash = "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"}, - {file = "typing_extensions-3.10.0.0.tar.gz", hash = "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342"}, + {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, + {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, + {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, ] urllib3 = [ - {file = "urllib3-1.26.6-py2.py3-none-any.whl", hash = "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4"}, - {file = "urllib3-1.26.6.tar.gz", hash = "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f"}, + {file = "urllib3-1.26.7-py2.py3-none-any.whl", hash = "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"}, + {file = "urllib3-1.26.7.tar.gz", hash = "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece"}, ] wcwidth = [ {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, ] werkzeug = [ - {file = "Werkzeug-2.0.1-py3-none-any.whl", hash = "sha256:6c1ec500dcdba0baa27600f6a22f6333d8b662d22027ff9f6202e3367413caa8"}, - {file = "Werkzeug-2.0.1.tar.gz", hash = "sha256:1de1db30d010ff1af14a009224ec49ab2329ad2cde454c8a708130642d579c42"}, + {file = "Werkzeug-2.0.2-py3-none-any.whl", hash = "sha256:63d3dc1cf60e7b7e35e97fa9861f7397283b75d765afcaefd993d6046899de8f"}, + {file = "Werkzeug-2.0.2.tar.gz", hash = "sha256:aa2bb6fc8dee8d6c504c0ac1e7f5f7dc5810a9903e793b6f715a9f015bdadb9a"}, ] diff --git a/pyproject.toml b/pyproject.toml index 73e5ed939519a5216f0221971d5ba7aae993e013..136e373cc8db96871a2f7c1e5f6bb96ec902b324 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ python = "^3.8" numpy = "^1.20.1" requests = "^2.25.1" pandas = "^1.2.4" -fasttext = "^0.9.2" +#fasttext = "^0.9.2" pymongo = "^3.11.4" Flask = "^2.0.1" Flask-HTTPAuth = "^4.4.0" diff --git a/sziszapangma/__pycache__/__init__.cpython-38.pyc b/sziszapangma/__pycache__/__init__.cpython-38.pyc index b2d1b765c9654646bac7bac6fa6b91ae5f037e20..c5430061dec094f0029e62e5e40384fecf89ef8c 100644 Binary files a/sziszapangma/__pycache__/__init__.cpython-38.pyc and b/sziszapangma/__pycache__/__init__.cpython-38.pyc differ diff --git a/sziszapangma/core/alignment/alignment_calculator.py b/sziszapangma/core/alignment/alignment_calculator.py index 0ebc6c3d74258fa51a8c1b3833cfe4a759c77987..b8411ed7c358a5c02668d1794f95f51bd299d875 100644 --- a/sziszapangma/core/alignment/alignment_calculator.py +++ b/sziszapangma/core/alignment/alignment_calculator.py @@ -9,7 +9,7 @@ from sziszapangma.core.alignment.alignment_step import AlignmentStep from sziszapangma.core.alignment.distance_matrix_calculator import DistanceCalculator from sziszapangma.core.alignment.step_type import StepType from sziszapangma.core.alignment.step_words import StepWords -from sziszapangma.core.alignment.word import Word +from sziszapangma.model.model import Word class AlignmentCalculator(ABC): diff --git a/sziszapangma/core/alignment/alignment_util.py b/sziszapangma/core/alignment/alignment_util.py index d90721ed7b93fe8d6f81f35cec88b687a150c21c..5c2c850462b7d42795f5af06af9e09ad821b50c6 100644 --- a/sziszapangma/core/alignment/alignment_util.py +++ b/sziszapangma/core/alignment/alignment_util.py @@ -4,13 +4,13 @@ import numpy as np import pandas as pd from sziszapangma.core.alignment.alignment_step import AlignmentStep -from sziszapangma.core.alignment.word import Word +from sziszapangma.model.model import Word class AlignmentUtil: @staticmethod def _optional_str_to_str(word: Optional[Word]) -> str: - return word.value if word is not None else "" + return word['text'] if word is not None else "" @staticmethod def _wer_step_to_pandas_row_lit(step: AlignmentStep) -> Tuple[str, str, str, float]: diff --git a/sziszapangma/core/alignment/distance_matrix_calculator.py b/sziszapangma/core/alignment/distance_matrix_calculator.py index 9bbec7f81275180d31b94df0367857ca86c20aaa..7c1f5bebec2c664e66ce989422dc68ef9b4674bf 100644 --- a/sziszapangma/core/alignment/distance_matrix_calculator.py +++ b/sziszapangma/core/alignment/distance_matrix_calculator.py @@ -4,8 +4,8 @@ from typing import List import numpy as np import numpy.typing as npt -from sziszapangma.core.alignment.word import Word from sziszapangma.core.transformer.embedding_transformer import EmbeddingTransformer +from sziszapangma.model.model import Word class DistanceCalculator(ABC): @@ -22,7 +22,7 @@ class DistanceCalculator(ABC): class BinaryDistanceCalculator(DistanceCalculator): def calculate_distance_for_words(self, word1: Word, word2: Word) -> float: - return 0 if word1.value == word2.value else 1 + return 0 if word1['text'] == word2['text'] else 1 def calculate_distance_matrix( self, reference: List[Word], hypothesis: List[Word] @@ -46,8 +46,8 @@ class CosineDistanceCalculator(DistanceCalculator): def calculate_distance_for_words(self, word1: Word, word2: Word) -> float: return self.cosine_distance_between_words_embeddings( - self._embedding_transformer.get_embedding(word1.value), - self._embedding_transformer.get_embedding(word2.value), + self._embedding_transformer.get_embedding(word1['text']), + self._embedding_transformer.get_embedding(word2['text']), ) @staticmethod @@ -74,14 +74,14 @@ class CosineDistanceCalculator(DistanceCalculator): self, reference: List[Word], hypothesis: List[Word] ) -> npt.NDArray[np.float64]: embeddings_dict = self._embedding_transformer.get_embeddings( - list(set(it.value for it in (reference + hypothesis))) + list(set(it['text'] for it in (reference + hypothesis))) ) return np.array( [ [ self.cosine_distance_between_words_embeddings( - embeddings_dict[reference_word.value], - embeddings_dict[hypothesis_word.value], + embeddings_dict[reference_word['text']], + embeddings_dict[hypothesis_word['text']], ) for hypothesis_word in hypothesis ] diff --git a/sziszapangma/core/alignment/step_words.py b/sziszapangma/core/alignment/step_words.py index 067466f5318d20fd3d785ce9c1106403ac130574..1aba6fc7a02f706220752662d0143fc692fe2e87 100644 --- a/sziszapangma/core/alignment/step_words.py +++ b/sziszapangma/core/alignment/step_words.py @@ -1,7 +1,7 @@ from dataclasses import dataclass from typing import Optional -from sziszapangma.core.alignment.word import Word +from sziszapangma.model.model import Word @dataclass(frozen=True) diff --git a/sziszapangma/core/alignment/word.py b/sziszapangma/core/alignment/word.py deleted file mode 100644 index 49ebbd4ab038985214d3e9d5e0309f5489fa56af..0000000000000000000000000000000000000000 --- a/sziszapangma/core/alignment/word.py +++ /dev/null @@ -1,17 +0,0 @@ -from __future__ import annotations - -import uuid -from dataclasses import dataclass - - -@dataclass(frozen=True) -class Word: - id: str - value: str - - @classmethod - def from_string(cls, string: str) -> Word: - return cls(str(uuid.uuid4()), string) - - def to_lower(self) -> Word: - return Word(self.id, self.value.lower()) diff --git a/sziszapangma/core/transformer/__pycache__/fasttext_embedding_transformer.cpython-38.pyc b/sziszapangma/core/transformer/__pycache__/fasttext_embedding_transformer.cpython-38.pyc deleted file mode 100644 index 98f0ba0759805530444137824e7fdf6c14ecc1c8..0000000000000000000000000000000000000000 Binary files a/sziszapangma/core/transformer/__pycache__/fasttext_embedding_transformer.cpython-38.pyc and /dev/null differ diff --git a/sziszapangma/core/transformer/fasttext_embedding_transformer.py b/sziszapangma/core/transformer/fasttext_embedding_transformer.py deleted file mode 100644 index 2c40dd0f5d2788922400878f2c27f4fbcce7cac2..0000000000000000000000000000000000000000 --- a/sziszapangma/core/transformer/fasttext_embedding_transformer.py +++ /dev/null @@ -1,23 +0,0 @@ -from typing import Dict, List - -import fasttext -import fasttext.util -import numpy as np -import numpy.typing as npt - -from sziszapangma.core.transformer.embedding_transformer import EmbeddingTransformer - - -class FasttextEmbeddingTransformer(EmbeddingTransformer): - - _model_name: str - - def __init__(self, lang_id: str): - full_model_name = fasttext.util.download_model(lang_id, if_exists="ignore") - self._fasttext_model = fasttext.load_model(full_model_name) - - def get_embedding(self, word: str) -> npt.NDArray[np.float64]: - return np.array(self._fasttext_model.get_word_vector(word)) - - def get_embeddings(self, words: List[str]) -> Dict[str, npt.NDArray[np.float64]]: - return {word: self.get_embedding(word) for word in set(words)} diff --git a/sziszapangma/integration/__pycache__/gold_transcript_processor.cpython-38.pyc b/sziszapangma/integration/__pycache__/gold_transcript_processor.cpython-38.pyc index 035e15e52b368db6f519a04ed2b9bbb79855db88..92bdb644e9c13dd935a97e0eceab9b945e57b691 100644 Binary files a/sziszapangma/integration/__pycache__/gold_transcript_processor.cpython-38.pyc and b/sziszapangma/integration/__pycache__/gold_transcript_processor.cpython-38.pyc differ diff --git a/sziszapangma/integration/__pycache__/path_filter.cpython-38.pyc b/sziszapangma/integration/__pycache__/path_filter.cpython-38.pyc index 12476b326cff42cc21f1c1d17c3d78b9ecbb967c..c41c7eb3674f5dc55a2723bb84bfaa528e31c5a4 100644 Binary files a/sziszapangma/integration/__pycache__/path_filter.cpython-38.pyc and b/sziszapangma/integration/__pycache__/path_filter.cpython-38.pyc differ diff --git a/sziszapangma/integration/__pycache__/record_id_iterator.cpython-38.pyc b/sziszapangma/integration/__pycache__/record_id_iterator.cpython-38.pyc index 8e2264bf3624c27c85f232c56c84110e81319cb1..0763aca101d6f16378fe58009f6cf6ac3e2ccea0 100644 Binary files a/sziszapangma/integration/__pycache__/record_id_iterator.cpython-38.pyc and b/sziszapangma/integration/__pycache__/record_id_iterator.cpython-38.pyc differ diff --git a/sziszapangma/integration/experiment_manager.py b/sziszapangma/integration/experiment_manager.py index 1dd25280ff1fd30577f0980990e230ce1cfb6a8b..5190b121156435b0803e9fbc86ee60dff4ff3d7c 100644 --- a/sziszapangma/integration/experiment_manager.py +++ b/sziszapangma/integration/experiment_manager.py @@ -3,6 +3,7 @@ from typing import List from sziszapangma.integration.repository.experiment_repository import ExperimentRepository from .record_id_iterator import RecordIdIterator +from .relation_manager_provider import RelationManagerProvider from .task.processing_task import ProcessingTask @@ -10,6 +11,7 @@ class ExperimentManager: _experiment_repository: ExperimentRepository _record_id_iterator: RecordIdIterator _processing_tasks: List[ProcessingTask] + _relation_manager_provider: RelationManagerProvider def __init__( self, @@ -24,4 +26,5 @@ class ExperimentManager: def process(self): self._experiment_repository.initialise() for processing_task in self._processing_tasks: - processing_task.process(self._record_id_iterator, self._experiment_repository) + processing_task.process(self._record_id_iterator, self._experiment_repository, + self._relation_manager_provider) diff --git a/sziszapangma/integration/mapper/step_words_mapper.py b/sziszapangma/integration/mapper/step_words_mapper.py index 94edd1128cbcc94c31af2447178738c0fbdf8000..6cb1511dda793089863dffb426bee5b58a96664e 100644 --- a/sziszapangma/integration/mapper/step_words_mapper.py +++ b/sziszapangma/integration/mapper/step_words_mapper.py @@ -1,7 +1,6 @@ from typing import Any, Dict from sziszapangma.core.alignment.step_words import StepWords -from sziszapangma.integration.mapper.word_mapper import WordMapper class StepWordsMapper: @@ -9,18 +8,15 @@ class StepWordsMapper: def to_json_dict(step_words: StepWords) -> Dict[str, Any]: to_return = dict() if step_words.hypothesis_word is not None: - to_return["hypothesis_word"] = WordMapper.to_json_dict(step_words.hypothesis_word) + to_return["hypothesis_word"] = step_words.hypothesis_word if step_words.reference_word is not None: - to_return["reference_word"] = WordMapper.to_json_dict(step_words.reference_word) + to_return["reference_word"] = step_words.reference_word return to_return @staticmethod def from_json_dict(input_json_dict: Dict[str, Any]) -> StepWords: - return StepWords( - None - if "reference_word" not in input_json_dict - else WordMapper.from_json_dict(input_json_dict["reference_word"]), - None - if "hypothesis_word" not in input_json_dict - else WordMapper.from_json_dict(input_json_dict["hypothesis_word"]), - ) + reference_word = None if "reference_word" not in input_json_dict \ + else input_json_dict["reference_word"] + hypothesis_word = None if "hypothesis_word" not in input_json_dict \ + else input_json_dict["hypothesis_word"] + return StepWords(reference_word, hypothesis_word) diff --git a/sziszapangma/integration/mapper/word_mapper.py b/sziszapangma/integration/mapper/word_mapper.py deleted file mode 100644 index 30d3d6adbe7a14bc868eca99c43421b0d99b88c3..0000000000000000000000000000000000000000 --- a/sziszapangma/integration/mapper/word_mapper.py +++ /dev/null @@ -1,16 +0,0 @@ -from typing import Dict - -from sziszapangma.core.alignment.word import Word - -_ID = "id" -_VALUE = "value" - - -class WordMapper: - @staticmethod - def to_json_dict(word: Word) -> Dict[str, str]: - return {_ID: word.id, _VALUE: word.value} - - @staticmethod - def from_json_dict(input_json_dict: Dict[str, str]) -> Word: - return Word(input_json_dict[_ID], input_json_dict[_VALUE]) diff --git a/sziszapangma/integration/relation_manager_provider.py b/sziszapangma/integration/relation_manager_provider.py new file mode 100644 index 0000000000000000000000000000000000000000..a92fb1132e986c11b940923fcacf37e83d0f749b --- /dev/null +++ b/sziszapangma/integration/relation_manager_provider.py @@ -0,0 +1,10 @@ +from abc import ABC, abstractmethod + +from sziszapangma.model.relation_manager import RelationManager + + +class RelationManagerProvider(ABC): + + @abstractmethod + def get_relation_manager(self, record_id: str) -> RelationManager: + pass diff --git a/sziszapangma/integration/repository/__pycache__/experiment_repository.cpython-38.pyc b/sziszapangma/integration/repository/__pycache__/experiment_repository.cpython-38.pyc index d7e187bae3886fd9ea14a4b3f7d734667994e846..6cb018db21eee03da8a9dd6115dbd67446c02b87 100644 Binary files a/sziszapangma/integration/repository/__pycache__/experiment_repository.cpython-38.pyc and b/sziszapangma/integration/repository/__pycache__/experiment_repository.cpython-38.pyc differ diff --git a/sziszapangma/integration/task/__pycache__/gold_transcript_task.cpython-38.pyc b/sziszapangma/integration/task/__pycache__/gold_transcript_task.cpython-38.pyc deleted file mode 100644 index 3c45e39c7669d1eb90145199e976c60239df6b92..0000000000000000000000000000000000000000 Binary files a/sziszapangma/integration/task/__pycache__/gold_transcript_task.cpython-38.pyc and /dev/null differ diff --git a/sziszapangma/integration/task/asr_task.py b/sziszapangma/integration/task/asr_task.py index 88d104961a2336c0aa4d80abeb13c970a0137967..f93045c269a183d64f43f1546c9d887f8a3c055b 100644 --- a/sziszapangma/integration/task/asr_task.py +++ b/sziszapangma/integration/task/asr_task.py @@ -1,9 +1,9 @@ -from sziszapangma.core.alignment.word import Word from sziszapangma.integration.asr_processor import AsrProcessor -from sziszapangma.integration.mapper.word_mapper import WordMapper from sziszapangma.integration.record_path_provider import RecordPathProvider from sziszapangma.integration.repository.experiment_repository import ExperimentRepository from sziszapangma.integration.task.processing_task import ProcessingTask +from sziszapangma.model.model_creators import create_new_word +from sziszapangma.model.relation_manager import RelationManager class AsrTask(ProcessingTask): @@ -30,12 +30,13 @@ class AsrTask(ProcessingTask): return asr_value is not None and "transcription" in asr_value def run_single_process( - self, record_id: str, experiment_repository: ExperimentRepository + self, record_id: str, experiment_repository: ExperimentRepository, + relation_manager: RelationManager ) -> None: file_record_path = self._record_path_provider.get_path(record_id) asr_result = self._asr_processor.call_recognise(file_record_path) asr_result["transcription"] = [ - WordMapper.to_json_dict(Word.from_string(it)) for it in asr_result["transcription"] + create_new_word(it) for it in asr_result["transcription"] ] experiment_repository.update_property_for_key( record_id, self._asr_property_name, asr_result diff --git a/sziszapangma/integration/task/classic_wer_metric_task.py b/sziszapangma/integration/task/classic_wer_metric_task.py index 9a0b63b3b57d35e5823927fb5636e7c9ad48a355..e3cbc2e8321012b283a1309c70becf724931cd66 100644 --- a/sziszapangma/integration/task/classic_wer_metric_task.py +++ b/sziszapangma/integration/task/classic_wer_metric_task.py @@ -2,12 +2,13 @@ from typing import Any, Dict, List from sziszapangma.core.alignment.alignment_classic_calculator import AlignmentClassicCalculator from sziszapangma.core.alignment.alignment_step import AlignmentStep -from sziszapangma.core.alignment.word import Word from sziszapangma.core.wer.wer_calculator import WerCalculator from sziszapangma.integration.mapper.alignment_step_mapper import AlignmentStepMapper -from sziszapangma.integration.mapper.word_mapper import WordMapper from sziszapangma.integration.repository.experiment_repository import ExperimentRepository from sziszapangma.integration.task.processing_task import ProcessingTask +from sziszapangma.integration.task.task_util import TaskUtil +from sziszapangma.model.model import Word +from sziszapangma.model.relation_manager import RelationManager _CLASSIC_WER = "classic_wer" @@ -42,10 +43,9 @@ class ClassicWerMetricTask(ProcessingTask): is not None ) - def run_single_process(self, record_id: str, experiment_repository: ExperimentRepository): - gold_transcript = experiment_repository.get_property_for_key( - record_id, self._gold_transcript_property_name - ) + def run_single_process(self, record_id: str, experiment_repository: ExperimentRepository, + relation_manager: RelationManager): + gold_transcript = TaskUtil.get_words_from_record(relation_manager) asr_result = experiment_repository.get_property_for_key(record_id, self._asr_property_name) if gold_transcript is not None and asr_result is not None and "transcription" in asr_result: alignment_steps = self._get_alignment(gold_transcript, asr_result["transcription"]) @@ -59,16 +59,12 @@ class ClassicWerMetricTask(ProcessingTask): ) def _get_alignment( - self, gold_transcript: List[Dict[str, Any]], asr_result: List[Dict[str, Any]] + self, + gold_transcript: List[Word], + asr_transcript: List[Word] ) -> List[AlignmentStep]: - gold_transcript_words = [ - # WordMapper.from_json_dict(word_dict) - Word(word_dict["id"], word_dict["word"]) - for word_dict in gold_transcript - ] - asr_words = [WordMapper.from_json_dict(word_dict).to_lower() for word_dict in asr_result] return self._alignment_classic_calculator.calculate_alignment( - reference=gold_transcript_words, hypothesis=asr_words + reference=gold_transcript, hypothesis=asr_transcript ) def calculate_metrics(self, alignment_steps: List[AlignmentStep]) -> Dict[str, Any]: diff --git a/sziszapangma/integration/task/embedding_wer_metrics_task.py b/sziszapangma/integration/task/embedding_wer_metrics_task.py index 81b5d92c729d9da62830a478293cedc4eb63f4d1..426cb8d8df62594b8147dfa75de7ef5c6857f8e5 100644 --- a/sziszapangma/integration/task/embedding_wer_metrics_task.py +++ b/sziszapangma/integration/task/embedding_wer_metrics_task.py @@ -1,15 +1,13 @@ -from typing import Dict, List - from sziszapangma.core.alignment.alignment_embedding_calculator import AlignmentEmbeddingCalculator from sziszapangma.core.alignment.alignment_soft_calculator import AlignmentSoftCalculator -from sziszapangma.core.alignment.word import Word from sziszapangma.core.transformer.cached_embedding_transformer import CachedEmbeddingTransformer from sziszapangma.core.transformer.embedding_transformer import EmbeddingTransformer from sziszapangma.core.wer.wer_calculator import WerCalculator from sziszapangma.integration.mapper.alignment_step_mapper import AlignmentStepMapper -from sziszapangma.integration.mapper.word_mapper import WordMapper from sziszapangma.integration.repository.experiment_repository import ExperimentRepository from sziszapangma.integration.task.processing_task import ProcessingTask +from sziszapangma.integration.task.task_util import TaskUtil +from sziszapangma.model.relation_manager import RelationManager _SOFT_WER = "soft_wer" _EMBEDDING_WER = "embedding_wer" @@ -53,24 +51,19 @@ class EmbeddingWerMetricsTask(ProcessingTask): is not None ) - def run_single_process(self, record_id: str, experiment_repository: ExperimentRepository): - gold_transcript = experiment_repository.get_property_for_key( - record_id, self._gold_transcript_property_name - ) + def run_single_process(self, record_id: str, experiment_repository: ExperimentRepository, + relation_manager: RelationManager): + gold_transcript = TaskUtil.get_words_from_record(relation_manager) asr_result = experiment_repository.get_property_for_key(record_id, self._asr_property_name) if gold_transcript is not None and asr_result is not None and "transcription" in asr_result: - gold_transcript_words = self._map_words_to_domain_gold_transcript(gold_transcript) - asr_words = [ - it - for it in self._map_words_to_domain(asr_result["transcription"]) - if len(it.value) > 0 - ] + gold_transcript_lower = TaskUtil.words_to_lower(gold_transcript) + asr_transcript_lower = TaskUtil.words_to_lower(asr_result["transcription"]) soft_alignment = self._alignment_soft_calculator.calculate_alignment( - gold_transcript_words, asr_words + gold_transcript_lower, asr_transcript_lower ) embedding_alignment = self._alignment_embedding_calculator.calculate_alignment( - gold_transcript_words, asr_words + gold_transcript_lower, asr_transcript_lower ) soft_wer = self._wer_calculator.calculate_wer(soft_alignment) @@ -92,13 +85,3 @@ class EmbeddingWerMetricsTask(ProcessingTask): ) self._embedding_transformer.clear() - - @staticmethod - def _map_words_to_domain(input_json_dicts: List[Dict[str, str]]) -> List[Word]: - return [WordMapper.from_json_dict(word_dict).to_lower() for word_dict in input_json_dicts] - - @staticmethod - def _map_words_to_domain_gold_transcript(input_json_dicts: List[Dict[str, str]]) -> List[Word]: - return [ - Word(word_dict["id"], word_dict["word"]).to_lower() for word_dict in input_json_dicts - ] diff --git a/sziszapangma/integration/task/gold_transcript_task.py b/sziszapangma/integration/task/gold_transcript_task.py deleted file mode 100644 index 3d22795683838e0b869d0c73c73f03c2acc64dbc..0000000000000000000000000000000000000000 --- a/sziszapangma/integration/task/gold_transcript_task.py +++ /dev/null @@ -1,34 +0,0 @@ -from sziszapangma.integration.gold_transcript_processor import GoldTranscriptProcessor -from sziszapangma.integration.repository.experiment_repository import ExperimentRepository -from sziszapangma.integration.task.processing_task import ProcessingTask - - -class GoldTranscriptTask(ProcessingTask): - _gold_transcript_processor: GoldTranscriptProcessor - _gold_transcript_property_name: str - - def __init__( - self, - task_name: str, - gold_transcript_processor: GoldTranscriptProcessor, - gold_transcript_property_name: str, - require_update: bool, - ): - super().__init__(task_name, require_update) - self._gold_transcript_processor = gold_transcript_processor - self._gold_transcript_property_name = gold_transcript_property_name - - def skip_for_record(self, record_id: str, experiment_repository: ExperimentRepository) -> bool: - return ( - experiment_repository.get_property_for_key( - record_id, self._gold_transcript_property_name - ) - is not None - ) - - def run_single_process(self, record_id: str, experiment_repository: ExperimentRepository): - experiment_repository.update_property_for_key( - record_id, - self._gold_transcript_property_name, - self._gold_transcript_processor.get_gold_transcript(record_id), - ) diff --git a/sziszapangma/integration/task/processing_task.py b/sziszapangma/integration/task/processing_task.py index 29f55c1f3e93899c33484b9ccfbf14f55d4d993b..8d30526097db531c60e0902942199c2ab742c54b 100644 --- a/sziszapangma/integration/task/processing_task.py +++ b/sziszapangma/integration/task/processing_task.py @@ -2,7 +2,9 @@ import traceback from abc import ABC, abstractmethod from sziszapangma.integration.record_id_iterator import RecordIdIterator +from sziszapangma.integration.relation_manager_provider import RelationManagerProvider from sziszapangma.integration.repository.experiment_repository import ExperimentRepository +from sziszapangma.model.relation_manager import RelationManager class ProcessingTask(ABC): @@ -14,7 +16,8 @@ class ProcessingTask(ABC): self._task_name = task_name @abstractmethod - def run_single_process(self, record_id: str, experiment_repository: ExperimentRepository): + def run_single_process(self, record_id: str, experiment_repository: ExperimentRepository, + relation_manager: RelationManager): pass @abstractmethod @@ -22,7 +25,8 @@ class ProcessingTask(ABC): pass def process( - self, record_id_iterator: RecordIdIterator, experiment_repository: ExperimentRepository + self, record_id_iterator: RecordIdIterator, experiment_repository: ExperimentRepository, + relation_manager_provider: RelationManagerProvider ): records_ids = list(record_id_iterator.get_all_records()) for record_index in range(len(records_ids)): @@ -35,7 +39,8 @@ class ProcessingTask(ABC): if not skip or self._require_update: print(base_log) try: - self.run_single_process(record_id, experiment_repository) + relation_manager = relation_manager_provider.get_relation_manager(record_id) + self.run_single_process(record_id, experiment_repository, relation_manager) except Exception as err: print("Handling run-time error:", err) traceback.print_exc() diff --git a/sziszapangma/integration/task/task_util.py b/sziszapangma/integration/task/task_util.py new file mode 100644 index 0000000000000000000000000000000000000000..71efe4479f0e0f1f9743c676c6d2a3ed25f232f0 --- /dev/null +++ b/sziszapangma/integration/task/task_util.py @@ -0,0 +1,20 @@ +from typing import List + +from sziszapangma.model.model import Word +from sziszapangma.model.relation_manager import RelationManager + + +class TaskUtil: + + @staticmethod + def get_words_from_record(relation_manager: RelationManager) -> List[Word]: + document = [itt for itt in relation_manager.get_all_items() if itt['type'] == 'Document'][0] + return [relation_manager.get_item_by_id(item_id) for item_id in document['word_ids']] + + @staticmethod + def _word_to_lower(word: Word) -> Word: + return Word(id=word['id'], type='Word', text=word['text'].lower()) + + @staticmethod + def words_to_lower(words: List[Word]) -> List[Word]: + return [TaskUtil._word_to_lower(it) for it in words] diff --git a/sziszapangma/model/__init__.py b/sziszapangma/model/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/sziszapangma/model/model.py b/sziszapangma/model/model.py new file mode 100644 index 0000000000000000000000000000000000000000..2bcba172644f7706541a457b594ff94f4d96763d --- /dev/null +++ b/sziszapangma/model/model.py @@ -0,0 +1,40 @@ +from typing import List, TypedDict, Literal, Any, Union + +AnnotationType = Literal["lemma", "pos", "morph", "concept", "chunk", "turn"] +ReferenceType = Literal["Token", "Word", "Document", "SpanAnnotation"] +UUIDableType = Union[AnnotationType, ReferenceType] + + +class UUIDable(TypedDict): + id: str + type: UUIDableType + + +class Token(UUIDable): + text: str + + +class Word(UUIDable): + text: str + + +class Document(UUIDable): + word_ids: List[str] + + +class Annotation(UUIDable): + value: Any + + +class SingleAnnotation(Annotation): + reference_id: str + + +class SpanAnnotation(UUIDable): + name: str + elements: List[str] + + +class RelationAnnotation(UUIDable): + parent: UUIDable + child: UUIDable diff --git a/sziszapangma/model/model_creators.py b/sziszapangma/model/model_creators.py new file mode 100644 index 0000000000000000000000000000000000000000..702e713741ee6588cc954d2af0bbd2727be4ebc1 --- /dev/null +++ b/sziszapangma/model/model_creators.py @@ -0,0 +1,30 @@ +import uuid +from typing import List + +from sziszapangma.model.model import Word, SingleAnnotation, AnnotationType, SpanAnnotation, \ + Document + + +def _get_uuid() -> str: + return str(uuid.uuid4()) + + +def create_new_word(text: str) -> Word: + return Word(id=_get_uuid(), type='Word', text=text) + + +def create_new_single_annotation( + annotation_type: AnnotationType, + value: any, + reference_id: str +) -> SingleAnnotation: + return SingleAnnotation(id=_get_uuid(), type=annotation_type, value=value, + reference_id=reference_id) + + +def create_new_span_annotation(name: str, elements: List[str]) -> SpanAnnotation: + return SpanAnnotation(id=_get_uuid(), type='SpanAnnotation', name=name, elements=elements) + + +def create_new_document(word_ids: List[str]) -> Document: + return Document(id=_get_uuid(), type='Document', word_ids=word_ids) diff --git a/sziszapangma/model/relation_manager.py b/sziszapangma/model/relation_manager.py new file mode 100644 index 0000000000000000000000000000000000000000..d99b20e487614dee1d1be0b28502ce34a6aa5606 --- /dev/null +++ b/sziszapangma/model/relation_manager.py @@ -0,0 +1,110 @@ +import json +import os +from abc import abstractmethod, ABC +from typing import List, TypedDict, Dict + +import pandas as pd + +from sziszapangma.model.model import UUIDable + + +class RelationItem(TypedDict): + first_id: str + first_type: str + second_id: str + second_type: str + + +class RelationManager(ABC): + @abstractmethod + def get_all_relations_for_item(self, item_id: str) -> List[RelationItem]: + pass + + @abstractmethod + def get_item_by_id(self, item_id: str) -> UUIDable: + pass + + @abstractmethod + def get_items_by_query(self, query: str) -> List[UUIDable]: + pass + + @abstractmethod + def save_item(self, item: UUIDable): + pass + + @abstractmethod + def save_relation(self, item1: UUIDable, item2: UUIDable): + pass + + @abstractmethod + def commit(self): + pass + + @abstractmethod + def get_all_items(self) -> List[UUIDable]: + pass + + +class FileRelationManager(RelationManager): + relations_csv_path: str + items_json_path: str + relations_dataframe: pd.DataFrame + items_dict: Dict[str, UUIDable] + + def __init__(self, relations_csv_path: str, items_json_path: str): + self.relations_csv_path = relations_csv_path + self.items_json_path = items_json_path + if os.path.isfile(relations_csv_path): + self.relations_dataframe = pd.read_csv(relations_csv_path) + else: + self.relations_dataframe = pd.DataFrame( + [], columns=["first_id", "first_type", "second_id", "second_type"] + ) + if os.path.isfile(items_json_path): + with open(items_json_path, "r") as f: + self.items_dict = json.loads(f.read()) + else: + self.items_dict = dict() + + def get_all_items(self) -> List[UUIDable]: + return list(self.items_dict.values()) + + def get_items_by_query(self, query: str) -> List[UUIDable]: + return self.relations_dataframe.query(query).to_dict("records") + + def get_all_relations_for_item(self, item_id: str) -> List[RelationItem]: + return self.relations_dataframe[ + self.relations_dataframe["first_id"] == item_id + ].to_dict("records") + + def get_item_by_id(self, item_id) -> UUIDable: + return self.items_dict[item_id] + + def save_item(self, item: UUIDable): + self.items_dict[item.get("id")] = item + + def save_relation(self, item1: UUIDable, item2: UUIDable): + relation_1_2 = { + "first_id": item1["id"], + "first_type": item1["type"], + "second_id": item2["id"], + "second_type": item2["type"], + } + relation_2_1 = { + "first_id": item2["id"], + "first_type": item2["type"], + "second_id": item1["id"], + "second_type": item1["type"], + } + self.relations_dataframe = self.relations_dataframe.append( + relation_1_2, ignore_index=True + ) + self.relations_dataframe = self.relations_dataframe.append( + relation_2_1, ignore_index=True + ) + + def commit(self): + self.relations_dataframe.to_csv(self.relations_csv_path, index=False) + items_json = json.dumps(self.items_dict) + with open(self.items_json_path, "w") as f: + f.write(items_json)