From 042e65974bd6063941242f130c37e12a86e90732 Mon Sep 17 00:00:00 2001 From: Eric Schmidt Date: Mon, 21 Jun 2021 13:08:00 -0700 Subject: [PATCH] samples: adds samples to client library (#68) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * samples: adds samples to client library * fix: remove deprecated field * fix: renamed region tags * 🦉 Updates from OwlBot See https://github.com/googleapis/repo-automation-bots/blob/master/packages/owl-bot/README.md Co-authored-by: Owl Bot --- media-translation/snippets/noxfile.py | 259 ++++++++++++++++++ .../snippets/requirements-test.txt | 1 + media-translation/snippets/requirements.txt | 3 + .../snippets/resources/audio.raw | Bin 0 -> 57958 bytes .../snippets/translate_from_file.py | 71 +++++ .../snippets/translate_from_file_test.py | 28 ++ .../snippets/translate_from_mic.py | 172 ++++++++++++ 7 files changed, 534 insertions(+) create mode 100644 media-translation/snippets/noxfile.py create mode 100644 media-translation/snippets/requirements-test.txt create mode 100644 media-translation/snippets/requirements.txt create mode 100644 media-translation/snippets/resources/audio.raw create mode 100644 media-translation/snippets/translate_from_file.py create mode 100644 media-translation/snippets/translate_from_file_test.py create mode 100644 media-translation/snippets/translate_from_mic.py diff --git a/media-translation/snippets/noxfile.py b/media-translation/snippets/noxfile.py new file mode 100644 index 000000000000..5ff9e1db5808 --- /dev/null +++ b/media-translation/snippets/noxfile.py @@ -0,0 +1,259 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import print_function + +import os +from pathlib import Path +import sys +from typing import Callable, Dict, List, Optional + +import nox + + +# WARNING - WARNING - WARNING - WARNING - WARNING +# WARNING - WARNING - WARNING - WARNING - WARNING +# DO NOT EDIT THIS FILE EVER! +# WARNING - WARNING - WARNING - WARNING - WARNING +# WARNING - WARNING - WARNING - WARNING - WARNING + +# Copy `noxfile_config.py` to your directory and modify it instead. + + +# `TEST_CONFIG` dict is a configuration hook that allows users to +# modify the test configurations. The values here should be in sync +# with `noxfile_config.py`. Users will copy `noxfile_config.py` into +# their directory and modify it. + +TEST_CONFIG = { + # You can opt out from the test for specific Python versions. + 'ignored_versions': ["2.7"], + + # Old samples are opted out of enforcing Python type hints + # All new samples should feature them + 'enforce_type_hints': False, + + # An envvar key for determining the project id to use. Change it + # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a + # build specific Cloud project. You can also use your own string + # to use your own Cloud project. + 'gcloud_project_env': 'GOOGLE_CLOUD_PROJECT', + # 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT', + # If you need to use a specific version of pip, + # change pip_version_override to the string representation + # of the version number, for example, "20.2.4" + "pip_version_override": None, + # A dictionary you want to inject into your test. Don't put any + # secrets here. These values will override predefined values. + 'envs': {}, +} + + +try: + # Ensure we can import noxfile_config in the project's directory. + sys.path.append('.') + from noxfile_config import TEST_CONFIG_OVERRIDE +except ImportError as e: + print("No user noxfile_config found: detail: {}".format(e)) + TEST_CONFIG_OVERRIDE = {} + +# Update the TEST_CONFIG with the user supplied values. +TEST_CONFIG.update(TEST_CONFIG_OVERRIDE) + + +def get_pytest_env_vars() -> Dict[str, str]: + """Returns a dict for pytest invocation.""" + ret = {} + + # Override the GCLOUD_PROJECT and the alias. + env_key = TEST_CONFIG['gcloud_project_env'] + # This should error out if not set. + ret['GOOGLE_CLOUD_PROJECT'] = os.environ[env_key] + + # Apply user supplied envs. + ret.update(TEST_CONFIG['envs']) + return ret + + +# DO NOT EDIT - automatically generated. +# All versions used to tested samples. +ALL_VERSIONS = ["2.7", "3.6", "3.7", "3.8", "3.9"] + +# Any default versions that should be ignored. +IGNORED_VERSIONS = TEST_CONFIG['ignored_versions'] + +TESTED_VERSIONS = sorted([v for v in ALL_VERSIONS if v not in IGNORED_VERSIONS]) + +INSTALL_LIBRARY_FROM_SOURCE = bool(os.environ.get("INSTALL_LIBRARY_FROM_SOURCE", False)) +# +# Style Checks +# + + +def _determine_local_import_names(start_dir: str) -> List[str]: + """Determines all import names that should be considered "local". + + This is used when running the linter to insure that import order is + properly checked. + """ + file_ext_pairs = [os.path.splitext(path) for path in os.listdir(start_dir)] + return [ + basename + for basename, extension in file_ext_pairs + if extension == ".py" + or os.path.isdir(os.path.join(start_dir, basename)) + and basename not in ("__pycache__") + ] + + +# Linting with flake8. +# +# We ignore the following rules: +# E203: whitespace before ‘:’ +# E266: too many leading ‘#’ for block comment +# E501: line too long +# I202: Additional newline in a section of imports +# +# We also need to specify the rules which are ignored by default: +# ['E226', 'W504', 'E126', 'E123', 'W503', 'E24', 'E704', 'E121'] +FLAKE8_COMMON_ARGS = [ + "--show-source", + "--builtin=gettext", + "--max-complexity=20", + "--import-order-style=google", + "--exclude=.nox,.cache,env,lib,generated_pb2,*_pb2.py,*_pb2_grpc.py", + "--ignore=E121,E123,E126,E203,E226,E24,E266,E501,E704,W503,W504,I202", + "--max-line-length=88", +] + + +@nox.session +def lint(session: nox.sessions.Session) -> None: + if not TEST_CONFIG['enforce_type_hints']: + session.install("flake8", "flake8-import-order") + else: + session.install("flake8", "flake8-import-order", "flake8-annotations") + + local_names = _determine_local_import_names(".") + args = FLAKE8_COMMON_ARGS + [ + "--application-import-names", + ",".join(local_names), + "." + ] + session.run("flake8", *args) +# +# Black +# + + +@nox.session +def blacken(session: nox.sessions.Session) -> None: + session.install("black") + python_files = [path for path in os.listdir(".") if path.endswith(".py")] + + session.run("black", *python_files) + +# +# Sample Tests +# + + +PYTEST_COMMON_ARGS = ["--junitxml=sponge_log.xml"] + + +def _session_tests(session: nox.sessions.Session, post_install: Callable = None) -> None: + if TEST_CONFIG["pip_version_override"]: + pip_version = TEST_CONFIG["pip_version_override"] + session.install(f"pip=={pip_version}") + """Runs py.test for a particular project.""" + if os.path.exists("requirements.txt"): + if os.path.exists("constraints.txt"): + session.install("-r", "requirements.txt", "-c", "constraints.txt") + else: + session.install("-r", "requirements.txt") + + if os.path.exists("requirements-test.txt"): + if os.path.exists("constraints-test.txt"): + session.install("-r", "requirements-test.txt", "-c", "constraints-test.txt") + else: + session.install("-r", "requirements-test.txt") + + if INSTALL_LIBRARY_FROM_SOURCE: + session.install("-e", _get_repo_root()) + + if post_install: + post_install(session) + + session.run( + "pytest", + *(PYTEST_COMMON_ARGS + session.posargs), + # Pytest will return 5 when no tests are collected. This can happen + # on travis where slow and flaky tests are excluded. + # See http://doc.pytest.org/en/latest/_modules/_pytest/main.html + success_codes=[0, 5], + env=get_pytest_env_vars() + ) + + +@nox.session(python=ALL_VERSIONS) +def py(session: nox.sessions.Session) -> None: + """Runs py.test for a sample using the specified version of Python.""" + if session.python in TESTED_VERSIONS: + _session_tests(session) + else: + session.skip("SKIPPED: {} tests are disabled for this sample.".format( + session.python + )) + + +# +# Readmegen +# + + +def _get_repo_root() -> Optional[str]: + """ Returns the root folder of the project. """ + # Get root of this repository. Assume we don't have directories nested deeper than 10 items. + p = Path(os.getcwd()) + for i in range(10): + if p is None: + break + if Path(p / ".git").exists(): + return str(p) + # .git is not available in repos cloned via Cloud Build + # setup.py is always in the library's root, so use that instead + # https://github.com/googleapis/synthtool/issues/792 + if Path(p / "setup.py").exists(): + return str(p) + p = p.parent + raise Exception("Unable to detect repository root.") + + +GENERATED_READMES = sorted([x for x in Path(".").rglob("*.rst.in")]) + + +@nox.session +@nox.parametrize("path", GENERATED_READMES) +def readmegen(session: nox.sessions.Session, path: str) -> None: + """(Re-)generates the readme for a sample.""" + session.install("jinja2", "pyyaml") + dir_ = os.path.dirname(path) + + if os.path.exists(os.path.join(dir_, "requirements.txt")): + session.install("-r", os.path.join(dir_, "requirements.txt")) + + in_file = os.path.join(dir_, "README.rst.in") + session.run( + "python", _get_repo_root() + "/scripts/readme-gen/readme_gen.py", in_file + ) diff --git a/media-translation/snippets/requirements-test.txt b/media-translation/snippets/requirements-test.txt new file mode 100644 index 000000000000..95ea1e6a02b0 --- /dev/null +++ b/media-translation/snippets/requirements-test.txt @@ -0,0 +1 @@ +pytest==6.2.4 diff --git a/media-translation/snippets/requirements.txt b/media-translation/snippets/requirements.txt new file mode 100644 index 000000000000..9f0ba480a732 --- /dev/null +++ b/media-translation/snippets/requirements.txt @@ -0,0 +1,3 @@ +google-cloud-media-translation==0.2.0 +pyaudio==0.2.11 +six==1.16.0 \ No newline at end of file diff --git a/media-translation/snippets/resources/audio.raw b/media-translation/snippets/resources/audio.raw new file mode 100644 index 0000000000000000000000000000000000000000..5ebf79d3c9c548f3d08c36e790059f3c2915af37 GIT binary patch literal 57958 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
  • ?dZ^!ab%qlspp&C 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 literal 0 HcmV?d00001 diff --git a/media-translation/snippets/translate_from_file.py b/media-translation/snippets/translate_from_file.py new file mode 100644 index 000000000000..3e746b2be1e4 --- /dev/null +++ b/media-translation/snippets/translate_from_file.py @@ -0,0 +1,71 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Cloud Media Translation sample application. + +Example usage: + python translate_from_file.py resources/audio.raw +""" + +# [START mediatranslation_translate_from_file] +from google.cloud import mediatranslation + + +def translate_from_file(file_path="path/to/your/file"): + client = mediatranslation.SpeechTranslationServiceClient() + + # The `sample_rate_hertz` field is not required for FLAC and WAV (Linear16) + # encoded data. Other audio encodings must provide the sampling rate. + audio_config = mediatranslation.TranslateSpeechConfig( + audio_encoding="linear16", + source_language_code="en-US", + target_language_code="fr-FR", + ) + + streaming_config = mediatranslation.StreamingTranslateSpeechConfig( + audio_config=audio_config, single_utterance=True + ) + + def request_generator(config, audio_file_path): + + # The first request contains the configuration. + # Note that audio_content is explicitly set to None. + yield mediatranslation.StreamingTranslateSpeechRequest(streaming_config=config) + + with open(audio_file_path, "rb") as audio: + while True: + chunk = audio.read(4096) + if not chunk: + break + yield mediatranslation.StreamingTranslateSpeechRequest( + audio_content=chunk + ) + + requests = request_generator(streaming_config, file_path) + responses = client.streaming_translate_speech(requests) + + for response in responses: + # Once the transcription settles, the response contains the + # is_final result. The other results will be for subsequent portions of + # the audio. + print(f"Response: {response}") + result = response.result + translation = result.text_translation_result.translation + + if result.text_translation_result.is_final: + print("\nFinal translation: {0}".format(translation)) + break + + print("\nPartial translation: {0}".format(translation)) + # [END mediatranslation_translate_from_file] diff --git a/media-translation/snippets/translate_from_file_test.py b/media-translation/snippets/translate_from_file_test.py new file mode 100644 index 000000000000..ce7a0ba55f06 --- /dev/null +++ b/media-translation/snippets/translate_from_file_test.py @@ -0,0 +1,28 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import re + +import translate_from_file + +RESOURCES = os.path.join(os.path.dirname(__file__), 'resources') + + +def test_translate_streaming(capsys): + translate_from_file.translate_from_file( + os.path.join(RESOURCES, 'audio.raw')) + out, err = capsys.readouterr() + + assert re.search(r'Partial translation', out, re.DOTALL | re.I) diff --git a/media-translation/snippets/translate_from_mic.py b/media-translation/snippets/translate_from_mic.py new file mode 100644 index 000000000000..3d2e6169566f --- /dev/null +++ b/media-translation/snippets/translate_from_mic.py @@ -0,0 +1,172 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Cloud Media Translation API sample application using a microphone. + +Example usage: + python translate_from_mic.py +""" + +# [START mediatranslation_translate_from_mic] +from __future__ import division + +import itertools + +from google.cloud import mediatranslation as media +import pyaudio +from six.moves import queue + +# Audio recording parameters +RATE = 16000 +CHUNK = int(RATE / 10) # 100ms +SpeechEventType = media.StreamingTranslateSpeechResponse.SpeechEventType + + +class MicrophoneStream: + """Opens a recording stream as a generator yielding the audio chunks.""" + + 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, + 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=None, value=None, traceback=None): + 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 exit(self): + self.__exit__() + + 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) + + +def listen_print_loop(responses): + """Iterates through server responses and prints them. + + The responses passed is a generator that will block until a response + is provided by the server. + """ + translation = '' + for response in responses: + # Once the transcription settles, the response contains the + # END_OF_SINGLE_UTTERANCE event. + if (response.speech_event_type == + SpeechEventType.END_OF_SINGLE_UTTERANCE): + + print(u'\nFinal translation: {0}'.format(translation)) + return 0 + + result = response.result + translation = result.text_translation_result.translation + + print(u'\nPartial translation: {0}'.format(translation)) + + +def do_translation_loop(): + print('Begin speaking...') + + client = media.SpeechTranslationServiceClient() + + speech_config = media.TranslateSpeechConfig( + audio_encoding='linear16', + source_language_code='en-US', + target_language_code='es-ES') + + config = media.StreamingTranslateSpeechConfig( + audio_config=speech_config, single_utterance=True) + + # The first request contains the configuration. + # Note that audio_content is explicitly set to None. + first_request = media.StreamingTranslateSpeechRequest( + streaming_config=config) + + with MicrophoneStream(RATE, CHUNK) as stream: + audio_generator = stream.generator() + mic_requests = (media.StreamingTranslateSpeechRequest( + audio_content=content) + for content in audio_generator) + + requests = itertools.chain(iter([first_request]), mic_requests) + + responses = client.streaming_translate_speech(requests) + + # Print the translation responses as they arrive + result = listen_print_loop(responses) + if result == 0: + stream.exit() + + +def main(): + while True: + print() + option = input('Press any key to translate or \'q\' to quit: ') + + if option.lower() == 'q': + break + + do_translation_loop() + + +if __name__ == '__main__': + main() +# [END mediatranslation_translate_from_mic]