diff --git a/speech/.coveragerc b/speech/.coveragerc index a54b99aa14b7..2806fdeccd1e 100644 --- a/speech/.coveragerc +++ b/speech/.coveragerc @@ -1,5 +1,8 @@ [run] branch = True +omit = + */gapic/* + */proto/* [report] fail_under = 100 diff --git a/speech/google/cloud/gapic/__init__.py b/speech/google/cloud/gapic/__init__.py deleted file mode 100644 index de40ea7ca058..000000000000 --- a/speech/google/cloud/gapic/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__import__('pkg_resources').declare_namespace(__name__) diff --git a/speech/google/cloud/gapic/speech/__init__.py b/speech/google/cloud/gapic/speech/__init__.py deleted file mode 100644 index de40ea7ca058..000000000000 --- a/speech/google/cloud/gapic/speech/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__import__('pkg_resources').declare_namespace(__name__) diff --git a/speech/google/cloud/gapic/speech/v1/speech_client.py b/speech/google/cloud/gapic/speech/v1/speech_client.py deleted file mode 100644 index 46e7f14e1a42..000000000000 --- a/speech/google/cloud/gapic/speech/v1/speech_client.py +++ /dev/null @@ -1,283 +0,0 @@ -# Copyright 2017, Google LLC All rights reserved. -# -# 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. -# -# EDITING INSTRUCTIONS -# This file was generated from the file -# https://github.com/google/googleapis/blob/master/google/cloud/speech/v1/cloud_speech.proto, -# and updates to that file get reflected here through a refresh process. -# For the short term, the refresh process will only be runnable by Google engineers. -# -# The only allowed edits are to method and file documentation. A 3-way -# merge preserves those additions if the generated source changes. -"""Accesses the google.cloud.speech.v1 Speech API.""" - -import collections -import json -import os -import pkg_resources -import platform - -from google.gapic.longrunning import operations_client -from google.gax import api_callable -from google.gax import config -from google.gax import path_template -from google.gax.utils import oneof -import google.gax - -from google.cloud.gapic.speech.v1 import enums -from google.cloud.proto.speech.v1 import cloud_speech_pb2 - - -class SpeechClient(object): - """Service that implements Google Cloud Speech API.""" - - SERVICE_ADDRESS = 'speech.googleapis.com' - """The default address of the service.""" - - DEFAULT_SERVICE_PORT = 443 - """The default port of the service.""" - - # The scopes needed to make gRPC calls to all of the methods defined in - # this service - _ALL_SCOPES = ('https://www.googleapis.com/auth/cloud-platform', ) - - def __init__(self, - service_path=SERVICE_ADDRESS, - port=DEFAULT_SERVICE_PORT, - channel=None, - credentials=None, - ssl_credentials=None, - scopes=None, - client_config=None, - app_name=None, - app_version='', - lib_name=None, - lib_version='', - metrics_headers=()): - """Constructor. - - Args: - service_path (string): The domain name of the API remote host. - port (int): The port on which to connect to the remote host. - channel (:class:`grpc.Channel`): A ``Channel`` instance through - which to make calls. - credentials (object): The authorization credentials to attach to - requests. These credentials identify this application to the - service. - ssl_credentials (:class:`grpc.ChannelCredentials`): A - ``ChannelCredentials`` instance for use with an SSL-enabled - channel. - scopes (list[string]): A list of OAuth2 scopes to attach to requests. - client_config (dict): - A dictionary for call options for each method. See - :func:`google.gax.construct_settings` for the structure of - this data. Falls back to the default config if not specified - or the specified config is missing data points. - app_name (string): The name of the application calling - the service. Recommended for analytics purposes. - app_version (string): The version of the application calling - the service. Recommended for analytics purposes. - lib_name (string): The API library software used for calling - the service. (Unless you are writing an API client itself, - leave this as default.) - lib_version (string): The API library software version used - for calling the service. (Unless you are writing an API client - itself, leave this as default.) - metrics_headers (dict): A dictionary of values for tracking - client library metrics. Ultimately serializes to a string - (e.g. 'foo/1.2.3 bar/3.14.1'). This argument should be - considered private. - - Returns: - A SpeechClient object. - """ - # Unless the calling application specifically requested - # OAuth scopes, request everything. - if scopes is None: - scopes = self._ALL_SCOPES - - # Initialize an empty client config, if none is set. - if client_config is None: - client_config = {} - - # Initialize metrics_headers as an ordered dictionary - # (cuts down on cardinality of the resulting string slightly). - metrics_headers = collections.OrderedDict(metrics_headers) - metrics_headers['gl-python'] = platform.python_version() - - # The library may or may not be set, depending on what is - # calling this client. Newer client libraries set the library name - # and version. - if lib_name: - metrics_headers[lib_name] = lib_version - - # Finally, track the GAPIC package version. - metrics_headers['gapic'] = pkg_resources.get_distribution( - 'google-cloud-speech', ).version - - # Load the configuration defaults. - default_client_config = json.loads( - pkg_resources.resource_string( - __name__, 'speech_client_config.json').decode()) - defaults = api_callable.construct_settings( - 'google.cloud.speech.v1.Speech', - default_client_config, - client_config, - config.STATUS_CODE_NAMES, - metrics_headers=metrics_headers, ) - self.speech_stub = config.create_stub( - cloud_speech_pb2.SpeechStub, - channel=channel, - service_path=service_path, - service_port=port, - credentials=credentials, - scopes=scopes, - ssl_credentials=ssl_credentials) - - self.operations_client = operations_client.OperationsClient( - service_path=service_path, - port=port, - channel=channel, - credentials=credentials, - ssl_credentials=ssl_credentials, - scopes=scopes, - client_config=client_config, - metrics_headers=metrics_headers, ) - - self._recognize = api_callable.create_api_call( - self.speech_stub.Recognize, settings=defaults['recognize']) - self._long_running_recognize = api_callable.create_api_call( - self.speech_stub.LongRunningRecognize, - settings=defaults['long_running_recognize']) - self._streaming_recognize = api_callable.create_api_call( - self.speech_stub.StreamingRecognize, - settings=defaults['streaming_recognize']) - - # Service calls - def recognize(self, config, audio, options=None): - """ - Performs synchronous speech recognition: receive results after all audio - has been sent and processed. - - Example: - >>> from google.cloud.gapic.speech.v1 import speech_client - >>> from google.cloud.gapic.speech.v1 import enums - >>> from google.cloud.proto.speech.v1 import cloud_speech_pb2 - >>> client = speech_client.SpeechClient() - >>> encoding = enums.RecognitionConfig.AudioEncoding.FLAC - >>> sample_rate_hertz = 44100 - >>> language_code = 'en-US' - >>> config = cloud_speech_pb2.RecognitionConfig(encoding=encoding, sample_rate_hertz=sample_rate_hertz, language_code=language_code) - >>> uri = 'gs://bucket_name/file_name.flac' - >>> audio = cloud_speech_pb2.RecognitionAudio(uri=uri) - >>> response = client.recognize(config, audio) - - Args: - config (:class:`google.cloud.proto.speech.v1.cloud_speech_pb2.RecognitionConfig`): *Required* Provides information to the recognizer that specifies how to - process the request. - audio (:class:`google.cloud.proto.speech.v1.cloud_speech_pb2.RecognitionAudio`): *Required* The audio data to be recognized. - options (:class:`google.gax.CallOptions`): Overrides the default - settings for this call, e.g, timeout, retries etc. - - Returns: - A :class:`google.cloud.proto.speech.v1.cloud_speech_pb2.RecognizeResponse` instance. - - Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. - """ - request = cloud_speech_pb2.RecognizeRequest(config=config, audio=audio) - return self._recognize(request, options) - - def long_running_recognize(self, config, audio, options=None): - """ - 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. - - Example: - >>> from google.cloud.gapic.speech.v1 import speech_client - >>> from google.cloud.gapic.speech.v1 import enums - >>> from google.cloud.proto.speech.v1 import cloud_speech_pb2 - >>> client = speech_client.SpeechClient() - >>> encoding = enums.RecognitionConfig.AudioEncoding.FLAC - >>> sample_rate_hertz = 44100 - >>> language_code = 'en-US' - >>> config = cloud_speech_pb2.RecognitionConfig(encoding=encoding, sample_rate_hertz=sample_rate_hertz, language_code=language_code) - >>> uri = 'gs://bucket_name/file_name.flac' - >>> audio = cloud_speech_pb2.RecognitionAudio(uri=uri) - >>> response = client.long_running_recognize(config, audio) - >>> - >>> def callback(operation_future): - >>> # Handle result. - >>> result = operation_future.result() - >>> - >>> response.add_done_callback(callback) - >>> - >>> # Handle metadata. - >>> metadata = response.metadata() - - Args: - config (:class:`google.cloud.proto.speech.v1.cloud_speech_pb2.RecognitionConfig`): *Required* Provides information to the recognizer that specifies how to - process the request. - audio (:class:`google.cloud.proto.speech.v1.cloud_speech_pb2.RecognitionAudio`): *Required* The audio data to be recognized. - options (:class:`google.gax.CallOptions`): Overrides the default - settings for this call, e.g, timeout, retries etc. - - Returns: - A :class:`google.gax._OperationFuture` instance. - - Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. - """ - request = cloud_speech_pb2.LongRunningRecognizeRequest( - config=config, audio=audio) - return google.gax._OperationFuture( - self._long_running_recognize(request, - options), self.operations_client, - cloud_speech_pb2.LongRunningRecognizeResponse, - cloud_speech_pb2.LongRunningRecognizeMetadata, options) - - def streaming_recognize(self, requests, options=None): - """ - Performs bidirectional streaming speech recognition: receive results while - sending audio. This method is only available via the gRPC API (not REST). - - EXPERIMENTAL: This method interface might change in the future. - - Example: - >>> from google.cloud.gapic.speech.v1 import speech_client - >>> from google.cloud.proto.speech.v1 import cloud_speech_pb2 - >>> client = speech_client.SpeechClient() - >>> request = cloud_speech_pb2.StreamingRecognizeRequest() - >>> requests = [request] - >>> for element in client.streaming_recognize(requests): - >>> # process element - >>> pass - - Args: - requests (iterator[:class:`google.cloud.proto.speech.v1.cloud_speech_pb2.StreamingRecognizeRequest`]): The input objects. - options (:class:`google.gax.CallOptions`): Overrides the default - settings for this call, e.g, timeout, retries etc. - - Returns: - iterator[:class:`google.cloud.proto.speech.v1.cloud_speech_pb2.StreamingRecognizeResponse`]. - - Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. - """ - return self._streaming_recognize(requests, options) diff --git a/speech/google/cloud/gapic/speech/v1/speech_client_config.json b/speech/google/cloud/gapic/speech/v1/speech_client_config.json deleted file mode 100644 index bf5c507caf1a..000000000000 --- a/speech/google/cloud/gapic/speech/v1/speech_client_config.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "interfaces": { - "google.cloud.speech.v1.Speech": { - "retry_codes": { - "idempotent": [ - "DEADLINE_EXCEEDED", - "UNAVAILABLE" - ], - "non_idempotent": [] - }, - "retry_params": { - "default": { - "initial_retry_delay_millis": 100, - "retry_delay_multiplier": 1.3, - "max_retry_delay_millis": 60000, - "initial_rpc_timeout_millis": 190000, - "rpc_timeout_multiplier": 1.0, - "max_rpc_timeout_millis": 190000, - "total_timeout_millis": 600000 - } - }, - "methods": { - "Recognize": { - "timeout_millis": 190000, - "retry_codes_name": "idempotent", - "retry_params_name": "default" - }, - "LongRunningRecognize": { - "timeout_millis": 60000, - "retry_codes_name": "non_idempotent", - "retry_params_name": "default" - }, - "StreamingRecognize": { - "timeout_millis": 190000, - "retry_codes_name": "idempotent", - "retry_params_name": "default" - } - } - } - } -} diff --git a/speech/google/cloud/proto/__init__.py b/speech/google/cloud/proto/__init__.py deleted file mode 100644 index de40ea7ca058..000000000000 --- a/speech/google/cloud/proto/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__import__('pkg_resources').declare_namespace(__name__) diff --git a/speech/google/cloud/proto/speech/__init__.py b/speech/google/cloud/proto/speech/__init__.py deleted file mode 100644 index de40ea7ca058..000000000000 --- a/speech/google/cloud/proto/speech/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__import__('pkg_resources').declare_namespace(__name__) diff --git a/speech/google/cloud/proto/speech/v1/__init__.py b/speech/google/cloud/proto/speech/v1/__init__.py deleted file mode 100644 index 8b137891791f..000000000000 --- a/speech/google/cloud/proto/speech/v1/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/speech/tests/unit/__init__.py b/speech/google/cloud/speech.py similarity index 61% rename from speech/tests/unit/__init__.py rename to speech/google/cloud/speech.py index df379f1e9d88..f6be726b5ca4 100644 --- a/speech/tests/unit/__init__.py +++ b/speech/google/cloud/speech.py @@ -1,13 +1,25 @@ -# Copyright 2016 Google LLC +# Copyright 2018 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 +# https://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 absolute_import + +from google.cloud.speech_v1 import SpeechClient +from google.cloud.speech_v1 import enums +from google.cloud.speech_v1 import types + +__all__ = ( + 'enums', + 'types', + 'SpeechClient', +) diff --git a/speech/google/cloud/speech/__init__.py b/speech/google/cloud/speech/__init__.py deleted file mode 100644 index ecb2b7d1b2de..000000000000 --- a/speech/google/cloud/speech/__init__.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2016 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. - -"""Google Cloud Speech API wrapper.""" - - -from pkg_resources import get_distribution -__version__ = get_distribution('google-cloud-speech').version - -from google.cloud.speech.alternative import Alternative -from google.cloud.speech.client import Client -from google.cloud.speech.encoding import Encoding -from google.cloud.speech.operation import Operation - -from google.cloud.speech_v1 import enums -from google.cloud.speech_v1 import SpeechClient -from google.cloud.speech_v1 import types - - -__all__ = ( - # Common - '__version__', - - # Deprecated Manual Layer - 'Alternative', - 'Client', - 'Encoding', - 'Operation', - - # GAPIC & Partial Manual Layer - 'enums', - 'SpeechClient', - 'types', -) diff --git a/speech/google/cloud/speech/_gax.py b/speech/google/cloud/speech/_gax.py deleted file mode 100644 index f243aea5f44f..000000000000 --- a/speech/google/cloud/speech/_gax.py +++ /dev/null @@ -1,435 +0,0 @@ -# Copyright 2016 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. - -"""GAX/GAPIC module for managing Speech API requests.""" - -from google.cloud.gapic.speech.v1.speech_client import SpeechClient -from google.cloud.proto.speech.v1.cloud_speech_pb2 import RecognitionAudio -from google.cloud.proto.speech.v1.cloud_speech_pb2 import ( - RecognitionConfig) -from google.cloud.proto.speech.v1.cloud_speech_pb2 import ( - SpeechContext) -from google.cloud.proto.speech.v1.cloud_speech_pb2 import ( - StreamingRecognitionConfig) -from google.cloud.proto.speech.v1.cloud_speech_pb2 import ( - StreamingRecognizeRequest) -from google.longrunning import operations_grpc - -from google.cloud import _helpers -from google.cloud._http import DEFAULT_USER_AGENT - -from google.cloud.speech import __version__ -from google.cloud.speech.operation import Operation -from google.cloud.speech.result import Result - -OPERATIONS_API_HOST = 'speech.googleapis.com' - - -class GAPICSpeechAPI(object): - """Manage calls through GAPIC wrappers to the Speech API. - - :type client: `~google.cloud.core.client.Client` - :param client: Instance of ``Client``. - """ - def __init__(self, client=None): - self._client = client - credentials = self._client._credentials - channel = _helpers.make_secure_channel( - credentials, DEFAULT_USER_AGENT, - SpeechClient.SERVICE_ADDRESS) - self._gapic_api = SpeechClient( - channel=channel, - lib_name='gccl', - lib_version=__version__, - ) - self._operations_stub = _helpers.make_secure_stub( - credentials, - DEFAULT_USER_AGENT, - operations_grpc.OperationsStub, - OPERATIONS_API_HOST, - ) - - def long_running_recognize(self, sample, language_code, - max_alternatives=None, profanity_filter=None, - speech_contexts=()): - """Long-running Recognize request to Google Speech API. - - .. _long_running_recognize: https://cloud.google.com/speech/reference/\ - rest/v1/speech/longrunningrecognize - - See `long_running_recognize`_. - - :type sample: :class:`~google.cloud.speech.sample.Sample` - :param sample: Instance of ``Sample`` containing audio information. - - :type language_code: str - :param language_code: The language of the supplied audio as - BCP-47 language tag. Example: ``'en-US'``. - - :type max_alternatives: int - :param max_alternatives: (Optional) Maximum number of recognition - hypotheses to be returned. The server may - return fewer than maxAlternatives. - Valid values are 0-30. A value of 0 or 1 - will return a maximum of 1. Defaults to 1 - - :type profanity_filter: bool - :param profanity_filter: If True, the server will attempt to filter - out profanities, replacing all but the - initial character in each filtered word with - asterisks, e.g. ``'f***'``. If False or - omitted, profanities won't be filtered out. - - :type speech_contexts: list - :param speech_contexts: A list of strings (max 50) containing words and - phrases "hints" so that the speech recognition - is more likely to recognize them. This can be - used to improve the accuracy for specific words - and phrases. This can also be used to add new - words to the vocabulary of the recognizer. - - :rtype: :class:`~google.cloud.speech.operation.Operation` - :returns: Instance of ``Operation`` to poll for results. - """ - config = RecognitionConfig( - encoding=sample.encoding, - language_code=language_code, - max_alternatives=max_alternatives, - profanity_filter=profanity_filter, - sample_rate_hertz=sample.sample_rate_hertz, - speech_contexts=[SpeechContext(phrases=speech_contexts)], - ) - - audio = RecognitionAudio(content=sample.content, - uri=sample.source_uri) - api = self._gapic_api - operation_future = api.long_running_recognize( - audio=audio, - config=config, - ) - - return Operation.from_pb(operation_future.last_operation_data(), self) - - def streaming_recognize(self, sample, language_code, - max_alternatives=None, profanity_filter=None, - speech_contexts=(), single_utterance=False, - interim_results=False): - """Streaming speech recognition. - - .. note:: - - Streaming recognition requests are limited to 1 minute of audio. - See https://cloud.google.com/speech/limits#content - - Yields :class:`~streaming_response.StreamingSpeechResponse` containing - results and metadata from the streaming request. - - :type sample: :class:`~google.cloud.speech.sample.Sample` - :param sample: Instance of ``Sample`` containing audio information. - - :type language_code: str - :param language_code: The language of the supplied audio as - BCP-47 language tag. Example: ``'en-US'``. - - :type max_alternatives: int - :param max_alternatives: (Optional) Maximum number of recognition - hypotheses to be returned. The server may - return fewer than maxAlternatives. - Valid values are 0-30. A value of 0 or 1 - will return a maximum of 1. Defaults to 1 - - :type profanity_filter: bool - :param profanity_filter: If True, the server will attempt to filter - out profanities, replacing all but the - initial character in each filtered word with - asterisks, e.g. ``'f***'``. If False or - omitted, profanities won't be filtered out. - - :type speech_contexts: list - :param speech_contexts: A list of strings (max 50) containing words and - phrases "hints" so that the speech recognition - is more likely to recognize them. This can be - used to improve the accuracy for specific words - and phrases. This can also be used to add new - words to the vocabulary of the recognizer. - - :type single_utterance: bool - :param single_utterance: (Optional) If false or omitted, the recognizer - will perform continuous recognition - (continuing to process audio even if the user - pauses speaking) until the client closes the - output stream (gRPC API) or when the maximum - time limit has been reached. Multiple - SpeechRecognitionResults with the is_final - flag set to true may be returned. - If true, the recognizer will detect a single - spoken utterance. When it detects that the - user has paused or stopped speaking, it will - return an END_OF_UTTERANCE event and cease - recognition. It will return no more than one - SpeechRecognitionResult with the is_final flag - set to true. - - :type interim_results: bool - :param interim_results: (Optional) If true, interim results (tentative - hypotheses) may be returned as they become - available (these interim results are indicated - with the is_final=false flag). If false or - omitted, only is_final=true result(s) are - returned. - - :raises: :class:`ValueError` if sample.content is not a file-like - object. :class:`ValueError` if stream has closed. - - :rtype: :class:`~google.cloud.grpc.speech.v1\ - .cloud_speech_pb2.StreamingRecognizeResponse` - :returns: ``StreamingRecognizeResponse`` instances. - """ - if sample.stream.closed: - raise ValueError('Stream is closed.') - - requests = _stream_requests(sample, language_code=language_code, - max_alternatives=max_alternatives, - profanity_filter=profanity_filter, - speech_contexts=speech_contexts, - single_utterance=single_utterance, - interim_results=interim_results) - api = self._gapic_api - responses = api.streaming_recognize(requests) - return responses - - def recognize(self, sample, language_code, max_alternatives=None, - profanity_filter=None, speech_contexts=()): - """Synchronous Speech Recognition. - - .. _recognize: https://cloud.google.com/speech/reference/\ - rest/v1/speech/recognize - - See `recognize`_. - - :type sample: :class:`~google.cloud.speech.sample.Sample` - :param sample: Instance of ``Sample`` containing audio information. - - :type language_code: str - :param language_code: The language of the supplied audio as - BCP-47 language tag. Example: ``'en-US'``. - - :type max_alternatives: int - :param max_alternatives: (Optional) Maximum number of recognition - hypotheses to be returned. The server may - return fewer than maxAlternatives. - Valid values are 0-30. A value of 0 or 1 - will return a maximum of 1. Defaults to 1 - - :type profanity_filter: bool - :param profanity_filter: If True, the server will attempt to filter - out profanities, replacing all but the - initial character in each filtered word with - asterisks, e.g. ``'f***'``. If False or - omitted, profanities won't be filtered out. - - :type speech_contexts: list - :param speech_contexts: A list of strings (max 50) containing words and - phrases "hints" so that the speech recognition - is more likely to recognize them. This can be - used to improve the accuracy for specific words - and phrases. This can also be used to add new - words to the vocabulary of the recognizer. - - :rtype: list - :returns: List of :class:`google.cloud.speech.result.Result` objects. - - :raises: ValueError if there are no results. - """ - config = RecognitionConfig( - encoding=sample.encoding, - language_code=language_code, - max_alternatives=max_alternatives, - profanity_filter=profanity_filter, - sample_rate_hertz=sample.sample_rate_hertz, - speech_contexts=[SpeechContext(phrases=speech_contexts)], - ) - audio = RecognitionAudio(content=sample.content, - uri=sample.source_uri) - api = self._gapic_api - api_response = api.recognize(config=config, audio=audio) - - # Sanity check: If we got no results back, raise an error. - if len(api_response.results) == 0: - raise ValueError('No results returned from the Speech API.') - - # Iterate over any results that came back. - return [Result.from_pb(result) for result in api_response.results] - - -def _stream_requests(sample, language_code, max_alternatives=None, - profanity_filter=None, speech_contexts=(), - single_utterance=None, interim_results=None): - """Generate stream of requests from sample. - - :type sample: :class:`~google.cloud.speech.sample.Sample` - :param sample: Instance of ``Sample`` containing audio information. - - :type language_code: str - :param language_code: The language of the supplied audio as - BCP-47 language tag. Example: ``'en-US'``. - - :type max_alternatives: int - :param max_alternatives: (Optional) Maximum number of recognition - hypotheses to be returned. The server may - return fewer than maxAlternatives. - Valid values are 0-30. A value of 0 or 1 - will return a maximum of 1. Defaults to 1 - - :type profanity_filter: bool - :param profanity_filter: (Optional) If True, the server will attempt to - filter out profanities, replacing all but the - initial character in each filtered word with - asterisks, e.g. ``'f***'``. If False or - omitted, profanities won't be filtered out. - - :type speech_contexts: list - :param speech_contexts: (Optional) A list of strings (max 50) containing - words and phrases "hints" so that the speech - recognition is more likely to recognize them. - This can be used to improve the accuracy for - specific words and phrases. This can also be used - to add new words to the vocabulary of the - recognizer. - - :type single_utterance: bool - :param single_utterance: (Optional) If false or omitted, the recognizer - will perform continuous recognition - (continuing to process audio even if the user - pauses speaking) until the client closes the - output stream (gRPC API) or when the maximum - time limit has been reached. Multiple - SpeechRecognitionResults with the is_final - flag set to true may be returned. - - If true, the recognizer will detect a single - spoken utterance. When it detects that the - user has paused or stopped speaking, it will - return an END_OF_UTTERANCE event and cease - recognition. It will return no more than one - SpeechRecognitionResult with the is_final flag - set to true. - - :type interim_results: bool - :param interim_results: (Optional) If true, interim results (tentative - hypotheses) may be returned as they become - available (these interim results are indicated - with the is_final=false flag). If false or - omitted, only is_final=true result(s) are - returned. - """ - config_request = _make_streaming_request( - sample, language_code=language_code, max_alternatives=max_alternatives, - profanity_filter=profanity_filter, - speech_contexts=[SpeechContext(phrases=speech_contexts)], - single_utterance=single_utterance, interim_results=interim_results) - - # The config request MUST go first and not contain any audio data. - yield config_request - - while True: - data = sample.stream.read(sample.chunk_size) - if not data: - break - yield StreamingRecognizeRequest(audio_content=data) - - -def _make_streaming_request(sample, language_code, - max_alternatives, profanity_filter, - speech_contexts, single_utterance, - interim_results): - """Build streaming request. - - :type sample: :class:`~google.cloud.speech.sample.Sample` - :param sample: Instance of ``Sample`` containing audio information. - - :type language_code: str - :param language_code: The language of the supplied audio as - BCP-47 language tag. Example: ``'en-GB'``. - If omitted, defaults to ``'en-US'``. - - :type max_alternatives: int - :param max_alternatives: Maximum number of recognition - hypotheses to be returned. The server may - return fewer than maxAlternatives. - Valid values are 0-30. A value of 0 or 1 - will return a maximum of 1. Defaults to 1 - - :type profanity_filter: bool - :param profanity_filter: If True, the server will attempt to filter - out profanities, replacing all but the - initial character in each filtered word with - asterisks, e.g. ``'f***'``. If False or - omitted, profanities won't be filtered out. - - :type speech_contexts: list - :param speech_contexts: A list of strings (max 50) containing words and - phrases "hints" so that the speech recognition - is more likely to recognize them. This can be - used to improve the accuracy for specific words - and phrases. This can also be used to add new - words to the vocabulary of the recognizer. - - :type single_utterance: bool - :param single_utterance: If false or omitted, the recognizer - will perform continuous recognition - (continuing to process audio even if the user - pauses speaking) until the client closes the - output stream (gRPC API) or when the maximum - time limit has been reached. Multiple - SpeechRecognitionResults with the is_final - flag set to true may be returned. - - If true, the recognizer will detect a single - spoken utterance. When it detects that the - user has paused or stopped speaking, it will - return an END_OF_UTTERANCE event and cease - recognition. It will return no more than one - SpeechRecognitionResult with the is_final flag - set to true. - - :type interim_results: bool - :param interim_results: If true, interim results (tentative - hypotheses) may be returned as they become - available (these interim results are indicated - with the is_final=false flag). If false or - omitted, only is_final=true result(s) are - returned. - - :rtype: - :class:`~grpc.speech.v1.cloud_speech_pb2.StreamingRecognizeRequest` - :returns: Instance of ``StreamingRecognizeRequest``. - """ - config = RecognitionConfig( - encoding=sample.encoding, - language_code=language_code, - max_alternatives=max_alternatives, - profanity_filter=profanity_filter, - sample_rate_hertz=sample.sample_rate_hertz, - speech_contexts=speech_contexts, - ) - - streaming_config = StreamingRecognitionConfig( - config=config, single_utterance=single_utterance, - interim_results=interim_results) - - config_request = StreamingRecognizeRequest( - streaming_config=streaming_config) - - return config_request diff --git a/speech/google/cloud/speech/_http.py b/speech/google/cloud/speech/_http.py deleted file mode 100644 index 7ad4d34691a4..000000000000 --- a/speech/google/cloud/speech/_http.py +++ /dev/null @@ -1,234 +0,0 @@ -# Copyright 2017 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. - -"""HTTP module for managing Speech API requests.""" - -from base64 import b64encode - -from google.cloud._helpers import _bytes_to_unicode -from google.cloud._helpers import _to_bytes -from google.cloud import _http - -from google.cloud.speech import __version__ -from google.cloud.speech.result import Result -from google.cloud.speech.operation import Operation - - -_CLIENT_INFO = _http.CLIENT_INFO_TEMPLATE.format(__version__) - - -class Connection(_http.JSONConnection): - """A connection to Google Cloud Speech JSON REST API. - - :type client: :class:`~google.cloud.speech.client.Client` - :param client: The client that owns the current connection. - """ - - API_BASE_URL = 'https://speech.googleapis.com' - """The base of the API call URL.""" - - API_VERSION = 'v1' - """The version of the API, used in building the API call's URL.""" - - API_URL_TEMPLATE = '{api_base_url}/{api_version}/{path}' - """A template for the URL of a particular API call.""" - - _EXTRA_HEADERS = { - _http.CLIENT_INFO_HEADER: _CLIENT_INFO, - } - - -class HTTPSpeechAPI(object): - """Speech API for interacting with the HTTP version of the API. - - :type client: :class:`google.cloud.core.client.Client` - :param client: Instance of a ``Client`` object. - """ - def __init__(self, client): - self._client = client - self._connection = Connection(client) - - def long_running_recognize(self, sample, language_code, - max_alternatives=None, profanity_filter=None, - speech_contexts=()): - """Long-running Recognize request to Google Speech API. - - .. _long_running_recognize: https://cloud.google.com/speech/reference/\ - rest/v1/speech/longrunningrecognize - - See `long_running_recognize`_. - - :type sample: :class:`~google.cloud.speech.sample.Sample` - :param sample: Instance of ``Sample`` containing audio information. - - :type language_code: str - :param language_code: The language of the supplied audio as - BCP-47 language tag. Example: ``'en-US'``. - - :type max_alternatives: int - :param max_alternatives: (Optional) Maximum number of recognition - hypotheses to be returned. The server may - return fewer than maxAlternatives. - Valid values are 0-30. A value of 0 or 1 - will return a maximum of 1. Defaults to 1 - - :type profanity_filter: bool - :param profanity_filter: If True, the server will attempt to filter - out profanities, replacing all but the - initial character in each filtered word with - asterisks, e.g. ``'f***'``. If False or - omitted, profanities won't be filtered out. - - :type speech_contexts: list - :param speech_contexts: A list of strings (max 50) containing words and - phrases "hints" so that the speech recognition - is more likely to recognize them. This can be - used to improve the accuracy for specific words - and phrases. This can also be used to add new - words to the vocabulary of the recognizer. - - :rtype: :class:`~google.cloud.speech.operation.Operation` - :returns: Operation for asynchronous request to Google Speech API. - """ - data = _build_request_data(sample, language_code, max_alternatives, - profanity_filter, speech_contexts) - api_response = self._connection.api_request( - method='POST', path='speech:longrunningrecognize', data=data) - - operation = Operation.from_dict(api_response, self._client) - operation.caller_metadata['request_type'] = 'LongRunningRecognize' - return operation - - def recognize(self, sample, language_code, max_alternatives=None, - profanity_filter=None, speech_contexts=()): - """Synchronous Speech Recognition. - - .. _recognize: https://cloud.google.com/speech/reference/\ - rest/v1/speech/recognize - - See `recognize`_. - - :type sample: :class:`~google.cloud.speech.sample.Sample` - :param sample: Instance of ``Sample`` containing audio information. - - :type language_code: str - :param language_code: (Optional) The language of the supplied audio as - BCP-47 language tag. Example: ``'en-US'``. - - :type max_alternatives: int - :param max_alternatives: (Optional) Maximum number of recognition - hypotheses to be returned. The server may - return fewer than maxAlternatives. - Valid values are 0-30. A value of 0 or 1 - will return a maximum of 1. Defaults to 1 - - :type profanity_filter: bool - :param profanity_filter: If True, the server will attempt to filter - out profanities, replacing all but the - initial character in each filtered word with - asterisks, e.g. ``'f***'``. If False or - omitted, profanities won't be filtered out. - - :type speech_contexts: list - :param speech_contexts: A list of strings (max 50) containing words and - phrases "hints" so that the speech recognition - is more likely to recognize them. This can be - used to improve the accuracy for specific words - and phrases. This can also be used to add new - words to the vocabulary of the recognizer. - - :rtype: list - :returns: A list of dictionaries. One dict for each alternative. Each - dictionary typically contains two keys (though not - all will be present in all cases) - - * ``transcript``: The detected text from the audio recording. - * ``confidence``: The confidence in language detection, float - between 0 and 1. - - :raises: ValueError if more than one result is returned or no results. - """ - data = _build_request_data(sample, language_code, max_alternatives, - profanity_filter, speech_contexts) - api_response = self._connection.api_request( - method='POST', path='speech:recognize', data=data) - - if len(api_response['results']) > 0: - results = api_response['results'] - return [Result.from_api_repr(result) for result in results] - else: - raise ValueError('No results were returned from the API') - - -def _build_request_data(sample, language_code, max_alternatives=None, - profanity_filter=None, speech_contexts=()): - """Builds the request data before making API request. - - :type sample: :class:`~google.cloud.speech.sample.Sample` - :param sample: Instance of ``Sample`` containing audio information. - - :type language_code: str - :param language_code: The language of the supplied audio as - BCP-47 language tag. Example: ``'en-US'``. - - :type max_alternatives: int - :param max_alternatives: (Optional) Maximum number of recognition - hypotheses to be returned. The server may - return fewer than maxAlternatives. - Valid values are 0-30. A value of 0 or 1 - will return a maximum of 1. Defaults to 1 - - :type profanity_filter: bool - :param profanity_filter: If True, the server will attempt to filter - out profanities, replacing all but the - initial character in each filtered word with - asterisks, e.g. ``'f***'``. If False or - omitted, profanities won't be filtered out. - - :type speech_contexts: list - :param speech_contexts: A list of strings (max 50) containing words and - phrases "hints" so that the speech recognition - is more likely to recognize them. This can be - used to improve the accuracy for specific words - and phrases. This can also be used to add new - words to the vocabulary of the recognizer. - - :rtype: dict - :returns: Dictionary with required data for Google Speech API. - """ - if sample.content is not None: - audio = {'content': - _bytes_to_unicode(b64encode(_to_bytes(sample.content)))} - else: - audio = {'uri': sample.source_uri} - - config = { - 'encoding': sample.encoding, - 'languageCode': language_code, - 'sampleRateHertz': sample.sample_rate_hertz, - } - - if max_alternatives is not None: - config['maxAlternatives'] = max_alternatives - if profanity_filter is not None: - config['profanityFilter'] = profanity_filter - if speech_contexts: - config['speechContexts'] = {'phrases': speech_contexts} - - data = { - 'audio': audio, - 'config': config, - } - - return data diff --git a/speech/google/cloud/speech/alternative.py b/speech/google/cloud/speech/alternative.py deleted file mode 100644 index fe07b2ac019b..000000000000 --- a/speech/google/cloud/speech/alternative.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright 2016 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. - -"""Representation of Speech Alternative for the Google Speech API.""" - - -class Alternative(object): - """Representation of Speech Alternative. - - :type transcript: str - :param transcript: String of transcribed data. - - :type confidence: float - :param confidence: The confidence estimate between 0.0 and 1.0. - """ - def __init__(self, transcript, confidence): - self._transcript = transcript - self._confidence = confidence - - @classmethod - def from_api_repr(cls, alternative): - """Factory: construct ``Alternative`` from JSON response. - - :type alternative: dict - :param alternative: Dictionary response from the REST API. - - :rtype: :class:`Alternative` - :returns: Instance of ``Alternative``. - """ - return cls(alternative['transcript'], alternative.get('confidence')) - - @classmethod - def from_pb(cls, alternative): - """Factory: construct ``Alternative`` from protobuf response. - - :type alternative: - :class:`google.cloud.speech.v1.SpeechRecognitionAlternative` - :param alternative: Instance of ``SpeechRecognitionAlternative`` - from protobuf. - - :rtype: :class:`Alternative` - :returns: Instance of ``Alternative``. - """ - confidence = alternative.confidence - if confidence == 0.0: # In the protobof 0.0 means unset. - confidence = None - return cls(alternative.transcript, confidence) - - @property - def transcript(self): - """Transcript text from audio. - - :rtype: str - :returns: Text detected in audio. - """ - return self._transcript - - @property - def confidence(self): - """Confidence score for recognized speech. - - :rtype: float - :returns: Confidence score of recognized speech [0-1]. - """ - return self._confidence diff --git a/speech/google/cloud/speech/client.py b/speech/google/cloud/speech/client.py deleted file mode 100644 index 2749cc20af09..000000000000 --- a/speech/google/cloud/speech/client.py +++ /dev/null @@ -1,128 +0,0 @@ -# Copyright 2016 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. - -"""Basic client for Google Cloud Speech API.""" - -from __future__ import absolute_import - -import os -import warnings - -from google.cloud.client import Client as BaseClient -from google.cloud.environment_vars import DISABLE_GRPC - -from google.cloud.speech._gax import GAPICSpeechAPI -from google.cloud.speech._http import HTTPSpeechAPI -from google.cloud.speech.sample import Sample - - -_USE_GRPC = not os.getenv(DISABLE_GRPC, False) - - -class Client(BaseClient): - """Client to bundle configuration needed for API requests. - - :type credentials: :class:`~google.auth.credentials.Credentials` - :param credentials: (Optional) The OAuth2 Credentials to use for this - client. If not passed (and if no ``_http`` object is - passed), falls back to the default inferred from the - environment. - - :type _http: :class:`~requests.Session` - :param _http: (Optional) HTTP object to make requests. Can be any object - that defines ``request()`` with the same interface as - :meth:`requests.Session.request`. If not passed, an - ``_http`` object is created that is bound to the - ``credentials`` for the current object. - This parameter should be considered private, and could - change in the future. - - :type _use_grpc: bool - :param _use_grpc: (Optional) Explicitly specifies whether - to use the gRPC transport (via GAX) or HTTP. If unset, - falls back to the ``GOOGLE_CLOUD_DISABLE_GRPC`` - environment variable. - This parameter should be considered private, and could - change in the future. - """ - - SCOPE = ('https://www.googleapis.com/auth/cloud-platform',) - """The scopes required for authenticating as an API consumer.""" - - _speech_api = None - - def __init__(self, credentials=None, _http=None, _use_grpc=None): - warnings.warn( - 'This client class and objects that derive from it have been ' - 'deprecated. Use `google.cloud.speech.SpeechClient` ' - '(provided by this package) instead. This client will be removed ' - 'in a future release.', - DeprecationWarning, - ) - - super(Client, self).__init__(credentials=credentials, _http=_http) - # Save on the actual client class whether we use GAX or not. - if _use_grpc is None: - self._use_grpc = _USE_GRPC - else: - self._use_grpc = _use_grpc - - def sample(self, content=None, source_uri=None, stream=None, encoding=None, - sample_rate_hertz=None): - """Factory: construct Sample to use when making recognize requests. - - :type content: bytes - :param content: (Optional) Bytes containing audio data. - - :type source_uri: str - :param source_uri: (Optional) URI that points to a file that contains - audio data bytes as specified in RecognitionConfig. - Currently, only Google Cloud Storage URIs are - supported, which must be specified in the following - format: ``gs://bucket_name/object_name``. - - :type stream: file - :param stream: (Optional) File like object to stream. - - :type encoding: str - :param encoding: encoding of audio data sent in all RecognitionAudio - messages, can be one of: :attr:`~.Encoding.LINEAR16`, - :attr:`~.Encoding.FLAC`, :attr:`~.Encoding.MULAW`, - :attr:`~.Encoding.AMR`, :attr:`~.Encoding.AMR_WB` - - :type sample_rate_hertz: int - :param sample_rate_hertz: Sample rate in Hertz of the audio data sent - in all requests. Valid values are: - 8000-48000. For best results, set the - sampling rate of the audio source - to 16000 Hz. If that's not possible, use the - native sample rate of the audio source - (instead of re-sampling). - - :rtype: :class:`~google.cloud.speech.sample.Sample` - :returns: Instance of ``Sample``. - """ - return Sample(content=content, source_uri=source_uri, stream=stream, - encoding=encoding, sample_rate_hertz=sample_rate_hertz, - client=self) - - @property - def speech_api(self): - """Helper for speech-related API calls.""" - if self._speech_api is None: - if self._use_grpc: - self._speech_api = GAPICSpeechAPI(self) - else: - self._speech_api = HTTPSpeechAPI(self) - return self._speech_api diff --git a/speech/google/cloud/speech/encoding.py b/speech/google/cloud/speech/encoding.py deleted file mode 100644 index 25d8b5af9028..000000000000 --- a/speech/google/cloud/speech/encoding.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright 2016 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. - -"""Encodings used by the Google Cloud Speech API.""" - - -class Encoding(object): - """Audio encoding types. - - See - https://cloud.google.com/speech/reference/rest/v1/RecognitionConfig#AudioEncoding - """ - - LINEAR16 = 'LINEAR16' - """LINEAR16 encoding type.""" - - FLAC = 'FLAC' - """FLAC encoding type.""" - - MULAW = 'MULAW' - """MULAW encoding type.""" - - AMR = 'AMR' - """AMR encoding type.""" - - AMR_WB = 'AMR_WB' - """AMR_WB encoding type.""" - - OGG_OPUS = 'OGG_OPUS' - """OGG_OPUS encoding type.""" - - SPEEX_WITH_HEADER_BYTE = 'SPEEX_WITH_HEADER_BYTE' - """SPEEX_WITH_HEADER_BYTE encoding type.""" diff --git a/speech/google/cloud/speech/operation.py b/speech/google/cloud/speech/operation.py deleted file mode 100644 index 7ba7e897b240..000000000000 --- a/speech/google/cloud/speech/operation.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright 2016 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. - -"""Long running operation representation for Google Speech API""" - -from google.cloud.proto.speech.v1 import cloud_speech_pb2 - -from google.cloud import operation -from google.cloud.speech.result import Result - - -operation.register_type(cloud_speech_pb2.LongRunningRecognizeMetadata) -operation.register_type(cloud_speech_pb2.LongRunningRecognizeResponse) - - -class Operation(operation.Operation): - """Custom Long-Running Operation for Google Speech API. - - :type name: str - :param name: The fully-qualified path naming the operation. - - :type client: :class:`~google.cloud.speech.client.Client` - :param client: Client that created the current operation. - - :type caller_metadata: dict - :param caller_metadata: caller-assigned metadata about the operation - """ - - results = None - """List of transcriptions from the speech-to-text process.""" - - def _update_state(self, operation_pb): - """Update the state of the current object based on operation. - - This mostly does what the base class does, but all populates - results. - - :type operation_pb: - :class:`~google.longrunning.operations_pb2.Operation` - :param operation_pb: Protobuf to be parsed. - - :raises ValueError: If there are no ``results`` from the operation. - """ - super(Operation, self)._update_state(operation_pb) - - result_type = operation_pb.WhichOneof('result') - if result_type != 'response': - return - - # Retrieve the results. - # If there were no results at all, raise an exception. - pb_results = self.response.results - if len(pb_results) == 0: - raise ValueError('Speech API returned no results.') - - # Save the results to the Operation object. - self.results = [] - for pb_result in pb_results: - self.results.append(Result.from_pb(pb_result)) diff --git a/speech/google/cloud/speech/result.py b/speech/google/cloud/speech/result.py deleted file mode 100644 index 815ae3208dce..000000000000 --- a/speech/google/cloud/speech/result.py +++ /dev/null @@ -1,134 +0,0 @@ -# Copyright 2016 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. - -"""Speech result representations.""" - -from google.cloud.speech.alternative import Alternative - - -class Result(object): - """Speech recognition result representation. - - This is the object that comes back on sync or async requests - (but not streaming requests). - - :type alternatives: list - :param alternatives: List of - :class:`~google.cloud.speech.alternative.Alternative`. - """ - def __init__(self, alternatives): - self.alternatives = alternatives - - @classmethod - def from_pb(cls, result): - """Factory: construct instance of ``Result``. - - :type result: :class:`~google.cloud.proto.speech.v1\ - .cloud_speech_pb2.SpeechRecognitionResult` - :param result: Instance of ``SpeechRecognitionResult`` protobuf. - - :rtype: :class:`~google.cloud.speech.result.Result` - :returns: Instance of ``Result``. - """ - alternatives = [Alternative.from_pb(alternative) for alternative - in result.alternatives] - return cls(alternatives=alternatives) - - @classmethod - def from_api_repr(cls, result): - """Factory: construct instance of ``Result``. - - :type result: dict - :param result: Dictionary of a :class:`~google.cloud.proto.speech.\ - v1.cloud_speech_pb2.SpeechRecognitionResult` - - :rtype: :class:`~google.cloud.speech.result.Result` - :returns: Instance of ``Result``. - """ - alternatives = [Alternative.from_api_repr(alternative) for alternative - in result['alternatives']] - return cls(alternatives=alternatives) - - @property - def confidence(self): - """Return the confidence for the most probable alternative. - - :rtype: float - :returns: Confidence value, between 0 and 1. - """ - return self.alternatives[0].confidence - - @property - def transcript(self): - """Return the transcript for the most probable alternative. - - :rtype: str - :returns: Speech transcript. - """ - return self.alternatives[0].transcript - - -class StreamingSpeechResult(object): - """Streaming speech result representation. - - :type alternatives: list - :param alternatives: List of - :class:`~google.cloud.speech.alternative.Alternative`. - - :type is_final: bool - :param is_final: Boolean indicator of results finality. - - :type stability: float - :param stability: 0.0-1.0 stability score for the results returned. - """ - def __init__(self, alternatives, is_final=False, stability=0.0): - self.alternatives = alternatives - self.is_final = is_final - self.stability = stability - - @classmethod - def from_pb(cls, response): - """Factory: construct instance of ``StreamingSpeechResult``. - - :type response: :class:`~google.cloud.proto.speech.v1\ - .cloud_speech_pb2.StreamingRecognizeResult` - :param response: Instance of ``StreamingRecognizeResult`` protobuf. - - :rtype: :class:`~google.cloud.speech.result.StreamingSpeechResult` - :returns: Instance of ``StreamingSpeechResult``. - """ - alternatives = [Alternative.from_pb(result) for result - in response.alternatives] - is_final = response.is_final - stability = response.stability - return cls(alternatives=alternatives, is_final=is_final, - stability=stability) - - @property - def confidence(self): - """Return the confidence for the most probable alternative. - - :rtype: float - :returns: Confidence value, between 0 and 1. - """ - return self.alternatives[0].confidence - - @property - def transcript(self): - """Return the transcript for the most probable alternative. - - :rtype: str - :returns: Speech transcript. - """ - return self.alternatives[0].transcript diff --git a/speech/google/cloud/speech/sample.py b/speech/google/cloud/speech/sample.py deleted file mode 100644 index 2c75ef86a185..000000000000 --- a/speech/google/cloud/speech/sample.py +++ /dev/null @@ -1,300 +0,0 @@ -# Copyright 2016 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. - -"""Sample class to handle content for Google Cloud Speech API.""" - -from google.cloud.speech.encoding import Encoding -from google.cloud.speech.result import StreamingSpeechResult - - -class Sample(object): - """Representation of an audio sample to be used with Google Speech API. - - :type content: bytes - :param content: (Optional) Bytes containing audio data. - - :type source_uri: str - :param source_uri: (Optional) URI that points to a file that contains - audio data bytes as specified in RecognitionConfig. - Currently, only Google Cloud Storage URIs are - supported, which must be specified in the following - format: ``gs://bucket_name/object_name``. - - :type stream: file - :param stream: (Optional) File like object to stream. - - :type encoding: str - :param encoding: encoding of audio data sent in all RecognitionAudio - messages, can be one of: :attr:`~.Encoding.LINEAR16`, - :attr:`~.Encoding.FLAC`, :attr:`~.Encoding.MULAW`, - :attr:`~.Encoding.AMR`, :attr:`~.Encoding.AMR_WB` - - :type sample_rate_hertz: int - :param sample_rate_hertz: Sample rate in Hertz of the audio data sent in - all requests. Valid values are: 8000-48000. For - best results, set the sampling rate of the audio - source to 16000 Hz. If that's not possible, use - the native sample rate of the audio source - (instead of re-sampling). - - :type client: :class:`~google.cloud.speech.client.Client` - :param client: (Optional) The client that owns this instance of sample. - """ - default_encoding = Encoding.FLAC - - def __init__(self, content=None, source_uri=None, stream=None, - encoding=None, sample_rate_hertz=None, client=None): - self._client = client - - sources = [content is not None, source_uri is not None, - stream is not None] - if sources.count(True) != 1: - raise ValueError('Supply exactly one of ' - '\'content\', \'source_uri\', \'stream\'') - - self._content = content - self._source_uri = source_uri - self._stream = stream - self._sample_rate_hertz = sample_rate_hertz - - if encoding is not None and getattr(Encoding, encoding, False): - self._encoding = getattr(Encoding, encoding) - else: - raise ValueError('Invalid encoding: %s' % (encoding,)) - - @property - def chunk_size(self): - """Chunk size to send over gRPC. ~100ms - - :rtype: int - :returns: Optimized chunk size. - """ - return int(self.sample_rate_hertz / 10.0) - - @property - def source_uri(self): - """Google Cloud Storage URI of audio source. - - :rtype: str - :returns: Google Cloud Storage URI string. - """ - return self._source_uri - - @property - def content(self): - """Bytes of audio content. - - :rtype: bytes - :returns: Byte stream of audio content. - """ - return self._content - - @property - def sample_rate_hertz(self): - """Sample rate integer. - - :rtype: int - :returns: Integer between 8000 and 48,000. - """ - return self._sample_rate_hertz - - @property - def stream(self): - """Stream the content when it is a file-like object. - - :rtype: file - :returns: File like object to stream. - """ - return self._stream - - @property - def encoding(self): - """Audio encoding type - - :rtype: str - :returns: String value of Encoding type. - """ - return self._encoding - - def long_running_recognize(self, language_code, max_alternatives=None, - profanity_filter=None, speech_contexts=()): - """Asychronous Recognize request to Google Speech API. - - .. _long_running_recognize: https://cloud.google.com/speech/reference/\ - rest/v1/speech/longrunningrecognize - - See `long_running_recognize`_. - - :type language_code: str - :param language_code: (Optional) The language of the supplied audio as - BCP-47 language tag. Example: ``'en-US'``. - - :type max_alternatives: int - :param max_alternatives: (Optional) Maximum number of recognition - hypotheses to be returned. The server may - return fewer than maxAlternatives. - Valid values are 0-30. A value of 0 or 1 - will return a maximum of 1. Defaults to 1 - - :type profanity_filter: bool - :param profanity_filter: If True, the server will attempt to filter - out profanities, replacing all but the - initial character in each filtered word with - asterisks, e.g. ``'f***'``. If False or - omitted, profanities won't be filtered out. - - :type speech_contexts: list - :param speech_contexts: A list of strings (max 50) containing words and - phrases "hints" so that the speech recognition - is more likely to recognize them. This can be - used to improve the accuracy for specific words - and phrases. This can also be used to add new - words to the vocabulary of the recognizer. - - :rtype: :class:`~google.cloud.speech.operation.Operation` - :returns: Operation for asynchronous request to Google Speech API. - """ - api = self._client.speech_api - return api.long_running_recognize( - self, language_code, max_alternatives, profanity_filter, - speech_contexts) - - def streaming_recognize(self, language_code, - max_alternatives=None, profanity_filter=None, - speech_contexts=(), single_utterance=False, - interim_results=False): - """Streaming speech recognition. - - .. note:: - - Streaming recognition requests are limited to 1 minute of audio. - See https://cloud.google.com/speech/limits#content - - Yields: Instance of - :class:`~google.cloud.speech.result.StreamingSpeechResult` - containing results and metadata from the streaming request. - - :type language_code: str - :param language_code: The language of the supplied audio as - BCP-47 language tag. Example: ``'en-US'``. - - :type max_alternatives: int - :param max_alternatives: (Optional) Maximum number of recognition - hypotheses to be returned. The server may - return fewer than maxAlternatives. - Valid values are 0-30. A value of 0 or 1 - will return a maximum of 1. Defaults to 1 - - :type profanity_filter: bool - :param profanity_filter: If True, the server will attempt to filter - out profanities, replacing all but the - initial character in each filtered word with - asterisks, e.g. ``'f***'``. If False or - omitted, profanities won't be filtered out. - - :type speech_contexts: list - :param speech_contexts: A list of strings (max 50) containing words and - phrases "hints" so that the speech recognition - is more likely to recognize them. This can be - used to improve the accuracy for specific words - and phrases. This can also be used to add new - words to the vocabulary of the recognizer. - - :type single_utterance: bool - :param single_utterance: (Optional) If false or omitted, the recognizer - will perform continuous recognition - (continuing to process audio even if the user - pauses speaking) until the client closes the - output stream (gRPC API) or when the maximum - time limit has been reached. Multiple - SpeechRecognitionResults with the is_final - flag set to true may be returned. - If true, the recognizer will detect a single - spoken utterance. When it detects that the - user has paused or stopped speaking, it will - return an END_OF_UTTERANCE event and cease - recognition. It will return no more than one - SpeechRecognitionResult with the is_final flag - set to true. - - :type interim_results: bool - :param interim_results: (Optional) If true, interim results (tentative - hypotheses) may be returned as they become - available (these interim results are indicated - with the ``is_final=False`` flag). If false or - omitted, only is_final=true result(s) are - returned. - - :raises: EnvironmentError if gRPC is not available. - """ - if not self._client._use_grpc: - raise EnvironmentError('gRPC is required to use this API.') - - api = self._client.speech_api - responses = api.streaming_recognize(self, language_code, - max_alternatives, profanity_filter, - speech_contexts, single_utterance, - interim_results) - for response in responses: - for result in response.results: - if result.is_final or interim_results: - yield StreamingSpeechResult.from_pb(result) - - def recognize(self, language_code, max_alternatives=None, - profanity_filter=None, speech_contexts=()): - """Synchronous Speech Recognition. - - .. _recognize: https://cloud.google.com/speech/reference/\ - rest/v1/speech/recognize - - See `recognize`_. - - :type language_code: str - :param language_code: The language of the supplied audio as - BCP-47 language tag. Example: ``'en-US'``. - - :type max_alternatives: int - :param max_alternatives: (Optional) Maximum number of recognition - hypotheses to be returned. The server may - return fewer than maxAlternatives. - Valid values are 0-30. A value of 0 or 1 - will return a maximum of 1. Defaults to 1 - - :type profanity_filter: bool - :param profanity_filter: If True, the server will attempt to filter - out profanities, replacing all but the - initial character in each filtered word with - asterisks, e.g. ``'f***'``. If False or - omitted, profanities won't be filtered out. - - :type speech_contexts: list - :param speech_contexts: A list of strings (max 50) containing words and - phrases "hints" so that the speech recognition - is more likely to recognize them. This can be - used to improve the accuracy for specific words - and phrases. This can also be used to add new - words to the vocabulary of the recognizer. - - :rtype: list - :returns: A list of dictionaries. One dict for each alternative. Each - dictionary typically contains two keys (though not - all will be present in all cases) - - * ``transcript``: The detected text from the audio recording. - * ``confidence``: The confidence in language detection, float - between 0 and 1. - """ - api = self._client.speech_api - return api.recognize(self, language_code, max_alternatives, - profanity_filter, speech_contexts) diff --git a/speech/google/cloud/speech_v1/__init__.py b/speech/google/cloud/speech_v1/__init__.py index c4966ebd8af1..272b623c510d 100644 --- a/speech/google/cloud/speech_v1/__init__.py +++ b/speech/google/cloud/speech_v1/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2017, Google LLC All rights reserved. +# Copyright 2017 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,8 +14,8 @@ from __future__ import absolute_import -from google.cloud.gapic.speech.v1 import speech_client -from google.cloud.gapic.speech.v1 import enums +from google.cloud.speech_v1.gapic import speech_client +from google.cloud.speech_v1.gapic import enums from google.cloud.speech_v1.helpers import SpeechHelpers from google.cloud.speech_v1 import types diff --git a/speech/google/cloud/gapic/speech/v1/__init__.py b/speech/google/cloud/speech_v1/gapic/__init__.py similarity index 100% rename from speech/google/cloud/gapic/speech/v1/__init__.py rename to speech/google/cloud/speech_v1/gapic/__init__.py diff --git a/speech/google/cloud/gapic/speech/v1/enums.py b/speech/google/cloud/speech_v1/gapic/enums.py similarity index 57% rename from speech/google/cloud/gapic/speech/v1/enums.py rename to speech/google/cloud/speech_v1/gapic/enums.py index 70ad27d46c7b..ff9b829fac28 100644 --- a/speech/google/cloud/gapic/speech/v1/enums.py +++ b/speech/google/cloud/speech_v1/gapic/enums.py @@ -1,10 +1,10 @@ -# Copyright 2016 Google LLC All rights reserved. +# Copyright 2018 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 +# https://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, @@ -32,30 +32,30 @@ class AudioEncoding(object): ENCODING_UNSPECIFIED (int): Not specified. Will return result ``google.rpc.Code.INVALID_ARGUMENT``. LINEAR16 (int): Uncompressed 16-bit signed little-endian samples (Linear PCM). FLAC (int): ```FLAC`` `_ (Free Lossless Audio - Codec) is the recommended encoding because it is - lossless--therefore recognition is not compromised--and - requires only about half the bandwidth of ``LINEAR16``. ``FLAC`` stream - encoding supports 16-bit and 24-bit samples, however, not all fields in - ``STREAMINFO`` are supported. + Codec) is the recommended encoding because it is + lossless--therefore recognition is not compromised--and + requires only about half the bandwidth of ``LINEAR16``. ``FLAC`` stream + encoding supports 16-bit and 24-bit samples, however, not all fields in + ``STREAMINFO`` are supported. MULAW (int): 8-bit samples that compand 14-bit audio samples using G.711 PCMU/mu-law. AMR (int): Adaptive Multi-Rate Narrowband codec. ``sample_rate_hertz`` must be 8000. AMR_WB (int): Adaptive Multi-Rate Wideband codec. ``sample_rate_hertz`` must be 16000. OGG_OPUS (int): Opus encoded audio frames in Ogg container - (`OggOpus `_). - ``sample_rate_hertz`` must be 16000. + (`OggOpus `_). + ``sample_rate_hertz`` must be 16000. SPEEX_WITH_HEADER_BYTE (int): Although the use of lossy encodings is not recommended, if a very low - bitrate encoding is required, ``OGG_OPUS`` is highly preferred over - Speex encoding. The `Speex `_ encoding supported by - Cloud Speech API has a header byte in each block, as in MIME type - ``audio/x-speex-with-header-byte``. - It is a variant of the RTP Speex encoding defined in - `RFC 5574 `_. - The stream is a sequence of blocks, one block per RTP packet. Each block - starts with a byte containing the length of the block, in bytes, followed - by one or more frames of Speex data, padded to an integral number of - bytes (octets) as specified in RFC 5574. In other words, each RTP header - is replaced with a single byte containing the block length. Only Speex - wideband is supported. ``sample_rate_hertz`` must be 16000. + bitrate encoding is required, ``OGG_OPUS`` is highly preferred over + Speex encoding. The `Speex `_ encoding supported by + Cloud Speech API has a header byte in each block, as in MIME type + ``audio/x-speex-with-header-byte``. + It is a variant of the RTP Speex encoding defined in + `RFC 5574 `_. + The stream is a sequence of blocks, one block per RTP packet. Each block + starts with a byte containing the length of the block, in bytes, followed + by one or more frames of Speex data, padded to an integral number of + bytes (octets) as specified in RFC 5574. In other words, each RTP header + is replaced with a single byte containing the block length. Only Speex + wideband is supported. ``sample_rate_hertz`` must be 16000. """ ENCODING_UNSPECIFIED = 0 LINEAR16 = 1 @@ -75,12 +75,12 @@ class SpeechEventType(object): Attributes: SPEECH_EVENT_UNSPECIFIED (int): No speech event specified. END_OF_SINGLE_UTTERANCE (int): This event indicates that the server has detected the end of the user's - speech utterance and expects no additional speech. Therefore, the server - will not process additional audio (although it may subsequently return - additional results). The client should stop sending additional audio - data, half-close the gRPC connection, and wait for any additional results - until the server closes the gRPC connection. This event is only sent if - ``single_utterance`` was set to ``true``, and is not used otherwise. + speech utterance and expects no additional speech. Therefore, the server + will not process additional audio (although it may subsequently return + additional results). The client should stop sending additional audio + data, half-close the gRPC connection, and wait for any additional results + until the server closes the gRPC connection. This event is only sent if + ``single_utterance`` was set to ``true``, and is not used otherwise. """ SPEECH_EVENT_UNSPECIFIED = 0 END_OF_SINGLE_UTTERANCE = 1 diff --git a/speech/google/cloud/speech_v1/gapic/speech_client.py b/speech/google/cloud/speech_v1/gapic/speech_client.py new file mode 100644 index 000000000000..6640957b26e1 --- /dev/null +++ b/speech/google/cloud/speech_v1/gapic/speech_client.py @@ -0,0 +1,321 @@ +# Copyright 2018 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 +# +# https://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. +"""Accesses the google.cloud.speech.v1 Speech API.""" + +import pkg_resources + +import google.api_core.gapic_v1.client_info +import google.api_core.gapic_v1.config +import google.api_core.gapic_v1.method +import google.api_core.grpc_helpers +import google.api_core.operation +import google.api_core.operations_v1 +import google.api_core.protobuf_helpers + +from google.cloud.speech_v1.gapic import enums +from google.cloud.speech_v1.gapic import speech_client_config +from google.cloud.speech_v1.proto import cloud_speech_pb2 + +_GAPIC_LIBRARY_VERSION = pkg_resources.get_distribution( + 'google-cloud-speech', ).version + + +class SpeechClient(object): + """Service that implements Google Cloud Speech API.""" + + SERVICE_ADDRESS = 'speech.googleapis.com:443' + """The default address of the service.""" + + # The scopes needed to make gRPC calls to all of the methods defined in + # this service + _DEFAULT_SCOPES = ('https://www.googleapis.com/auth/cloud-platform', ) + + # The name of the interface for this client. This is the key used to find + # method configuration in the client_config dictionary. + _INTERFACE_NAME = 'google.cloud.speech.v1.Speech' + + def __init__(self, + channel=None, + credentials=None, + client_config=speech_client_config.config, + client_info=None): + """Constructor. + + Args: + channel (grpc.Channel): A ``Channel`` instance through + which to make calls. This argument is mutually exclusive + with ``credentials``; providing both will raise an exception. + credentials (google.auth.credentials.Credentials): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If none + are specified, the client will attempt to ascertain the + credentials from the environment. + client_config (dict): A dictionary of call options for each + method. If not specified, the default configuration is used. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + """ + # If both `channel` and `credentials` are specified, raise an + # exception (channels come with credentials baked in already). + if channel is not None and credentials is not None: + raise ValueError( + 'The `channel` and `credentials` arguments to {} are mutually ' + 'exclusive.'.format(self.__class__.__name__), ) + + # Create the channel. + if channel is None: + channel = google.api_core.grpc_helpers.create_channel( + self.SERVICE_ADDRESS, + credentials=credentials, + scopes=self._DEFAULT_SCOPES, + ) + + # Create the gRPC stubs. + self.speech_stub = (cloud_speech_pb2.SpeechStub(channel)) + + # Operations client for methods that return long-running operations + # futures. + self.operations_client = ( + google.api_core.operations_v1.OperationsClient(channel)) + + if client_info is None: + client_info = ( + google.api_core.gapic_v1.client_info.DEFAULT_CLIENT_INFO) + client_info.gapic_version = _GAPIC_LIBRARY_VERSION + + # Parse out the default settings for retry and timeout for each RPC + # from the client configuration. + # (Ordinarily, these are the defaults specified in the `*_config.py` + # file next to this one.) + method_configs = google.api_core.gapic_v1.config.parse_method_configs( + client_config['interfaces'][self._INTERFACE_NAME], ) + + # Write the "inner API call" methods to the class. + # These are wrapped versions of the gRPC stub methods, with retry and + # timeout configuration applied, called by the public methods on + # this class. + self._recognize = google.api_core.gapic_v1.method.wrap_method( + self.speech_stub.Recognize, + default_retry=method_configs['Recognize'].retry, + default_timeout=method_configs['Recognize'].timeout, + client_info=client_info, + ) + self._long_running_recognize = google.api_core.gapic_v1.method.wrap_method( + self.speech_stub.LongRunningRecognize, + default_retry=method_configs['LongRunningRecognize'].retry, + default_timeout=method_configs['LongRunningRecognize'].timeout, + client_info=client_info, + ) + self._streaming_recognize = google.api_core.gapic_v1.method.wrap_method( + self.speech_stub.StreamingRecognize, + default_retry=method_configs['StreamingRecognize'].retry, + default_timeout=method_configs['StreamingRecognize'].timeout, + client_info=client_info, + ) + + # Service calls + def recognize(self, + config, + audio, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): + """ + Performs synchronous speech recognition: receive results after all audio + has been sent and processed. + + Example: + >>> from google.cloud import speech_v1 + >>> from google.cloud.speech_v1 import enums + >>> + >>> client = speech_v1.SpeechClient() + >>> + >>> encoding = enums.RecognitionConfig.AudioEncoding.FLAC + >>> sample_rate_hertz = 44100 + >>> language_code = 'en-US' + >>> config = {'encoding': encoding, 'sample_rate_hertz': sample_rate_hertz, 'language_code': language_code} + >>> uri = 'gs://bucket_name/file_name.flac' + >>> audio = {'uri': uri} + >>> + >>> response = client.recognize(config, audio) + + Args: + config (Union[dict, ~google.cloud.speech_v1.types.RecognitionConfig]): *Required* Provides information to the recognizer that specifies how to + process the request. + If a dict is provided, it must be of the same form as the protobuf + message :class:`~google.cloud.speech_v1.types.RecognitionConfig` + audio (Union[dict, ~google.cloud.speech_v1.types.RecognitionAudio]): *Required* The audio data to be recognized. + If a dict is provided, it must be of the same form as the protobuf + message :class:`~google.cloud.speech_v1.types.RecognitionAudio` + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. + metadata (Optional[Sequence[Tuple[str, str]]]): Additional metadata + that is provided to the method. + + Returns: + A :class:`~google.cloud.speech_v1.types.RecognizeResponse` instance. + + Raises: + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. + """ + if metadata is None: + metadata = [] + metadata = list(metadata) + request = cloud_speech_pb2.RecognizeRequest( + config=config, + audio=audio, + ) + return self._recognize( + request, retry=retry, timeout=timeout, metadata=metadata) + + def long_running_recognize(self, + config, + audio, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): + """ + 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. + + Example: + >>> from google.cloud import speech_v1 + >>> from google.cloud.speech_v1 import enums + >>> + >>> client = speech_v1.SpeechClient() + >>> + >>> encoding = enums.RecognitionConfig.AudioEncoding.FLAC + >>> sample_rate_hertz = 44100 + >>> language_code = 'en-US' + >>> config = {'encoding': encoding, 'sample_rate_hertz': sample_rate_hertz, 'language_code': language_code} + >>> uri = 'gs://bucket_name/file_name.flac' + >>> audio = {'uri': uri} + >>> + >>> response = client.long_running_recognize(config, audio) + >>> + >>> def callback(operation_future): + ... # Handle result. + ... result = operation_future.result() + >>> + >>> response.add_done_callback(callback) + >>> + >>> # Handle metadata. + >>> metadata = response.metadata() + + Args: + config (Union[dict, ~google.cloud.speech_v1.types.RecognitionConfig]): *Required* Provides information to the recognizer that specifies how to + process the request. + If a dict is provided, it must be of the same form as the protobuf + message :class:`~google.cloud.speech_v1.types.RecognitionConfig` + audio (Union[dict, ~google.cloud.speech_v1.types.RecognitionAudio]): *Required* The audio data to be recognized. + If a dict is provided, it must be of the same form as the protobuf + message :class:`~google.cloud.speech_v1.types.RecognitionAudio` + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. + metadata (Optional[Sequence[Tuple[str, str]]]): Additional metadata + that is provided to the method. + + Returns: + A :class:`~google.cloud.speech_v1.types._OperationFuture` instance. + + Raises: + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. + """ + if metadata is None: + metadata = [] + metadata = list(metadata) + request = cloud_speech_pb2.LongRunningRecognizeRequest( + config=config, + audio=audio, + ) + operation = self._long_running_recognize( + request, retry=retry, timeout=timeout, metadata=metadata) + return google.api_core.operation.from_gapic( + operation, + self.operations_client, + cloud_speech_pb2.LongRunningRecognizeResponse, + metadata_type=cloud_speech_pb2.LongRunningRecognizeMetadata, + ) + + def streaming_recognize(self, + requests, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): + """ + Performs bidirectional streaming speech recognition: receive results while + sending audio. This method is only available via the gRPC API (not REST). + + EXPERIMENTAL: This method interface might change in the future. + + Example: + >>> from google.cloud import speech_v1 + >>> + >>> client = speech_v1.SpeechClient() + >>> + >>> request = {} + >>> + >>> requests = [request] + >>> for element in client.streaming_recognize(requests): + ... # process element + ... pass + + Args: + requests (iterator[dict|google.cloud.speech_v1.proto.cloud_speech_pb2.StreamingRecognizeRequest]): The input objects. If a dict is provided, it must be of the + same form as the protobuf message :class:`~google.cloud.speech_v1.types.StreamingRecognizeRequest` + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. + metadata (Optional[Sequence[Tuple[str, str]]]): Additional metadata + that is provided to the method. + + Returns: + Iterable[~google.cloud.speech_v1.types.StreamingRecognizeResponse]. + + Raises: + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. + """ + if metadata is None: + metadata = [] + metadata = list(metadata) + return self._streaming_recognize( + requests, retry=retry, timeout=timeout, metadata=metadata) diff --git a/speech/google/cloud/speech_v1/gapic/speech_client_config.py b/speech/google/cloud/speech_v1/gapic/speech_client_config.py new file mode 100644 index 000000000000..7d6138694011 --- /dev/null +++ b/speech/google/cloud/speech_v1/gapic/speech_client_config.py @@ -0,0 +1,38 @@ +config = { + "interfaces": { + "google.cloud.speech.v1.Speech": { + "retry_codes": { + "idempotent": ["DEADLINE_EXCEEDED", "UNAVAILABLE"], + "non_idempotent": [] + }, + "retry_params": { + "default": { + "initial_retry_delay_millis": 100, + "retry_delay_multiplier": 1.3, + "max_retry_delay_millis": 60000, + "initial_rpc_timeout_millis": 190000, + "rpc_timeout_multiplier": 1.0, + "max_rpc_timeout_millis": 190000, + "total_timeout_millis": 600000 + } + }, + "methods": { + "Recognize": { + "timeout_millis": 190000, + "retry_codes_name": "idempotent", + "retry_params_name": "default" + }, + "LongRunningRecognize": { + "timeout_millis": 60000, + "retry_codes_name": "non_idempotent", + "retry_params_name": "default" + }, + "StreamingRecognize": { + "timeout_millis": 190000, + "retry_codes_name": "idempotent", + "retry_params_name": "default" + } + } + } + } +} diff --git a/speech/tests/__init__.py b/speech/google/cloud/speech_v1/proto/__init__.py similarity index 100% rename from speech/tests/__init__.py rename to speech/google/cloud/speech_v1/proto/__init__.py diff --git a/speech/google/cloud/proto/speech/v1/cloud_speech_pb2.py b/speech/google/cloud/speech_v1/proto/cloud_speech_pb2.py similarity index 97% rename from speech/google/cloud/proto/speech/v1/cloud_speech_pb2.py rename to speech/google/cloud/speech_v1/proto/cloud_speech_pb2.py index 2f3aae756469..25aa3da7d15d 100644 --- a/speech/google/cloud/proto/speech/v1/cloud_speech_pb2.py +++ b/speech/google/cloud/speech_v1/proto/cloud_speech_pb2.py @@ -1,5 +1,5 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! -# source: google/cloud/proto/speech/v1/cloud_speech.proto +# source: google/cloud/speech_v1/proto/cloud_speech.proto import sys _b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) @@ -22,10 +22,10 @@ DESCRIPTOR = _descriptor.FileDescriptor( - name='google/cloud/proto/speech/v1/cloud_speech.proto', + name='google/cloud/speech_v1/proto/cloud_speech.proto', package='google.cloud.speech.v1', syntax='proto3', - serialized_pb=_b('\n/google/cloud/proto/speech/v1/cloud_speech.proto\x12\x16google.cloud.speech.v1\x1a\x1cgoogle/api/annotations.proto\x1a#google/longrunning/operations.proto\x1a\x19google/protobuf/any.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x1fgoogle/protobuf/timestamp.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\"\x91\x01\n\x1bLongRunningRecognizeRequest\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\"\xb4\x03\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\"\x8b\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\" \n\rSpeechContext\x12\x0f\n\x07phrases\x18\x01 \x03(\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\"`\n\x1cLongRunningRecognizeResponse\x12@\n\x07results\x18\x02 \x03(\x0b\x32/.google.cloud.speech.v1.SpeechRecognitionResult\"\x9e\x01\n\x1cLongRunningRecognizeMetadata\x12\x18\n\x10progress_percent\x18\x01 \x01(\x05\x12.\n\nstart_time\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x34\n\x10last_update_time\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\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\"\x8d\x01\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\"e\n\x17SpeechRecognitionResult\x12J\n\x0c\x61lternatives\x18\x01 \x03(\x0b\x32\x34.google.cloud.speech.v1.SpeechRecognitionAlternative\"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(\t2\xa6\x03\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\x96\x01\n\x14LongRunningRecognize\x12\x33.google.cloud.speech.v1.LongRunningRecognizeRequest\x1a\x1d.google.longrunning.Operation\"*\x82\xd3\xe4\x93\x02$\"\x1f/v1/speech:longrunningrecognize:\x01*\x12\x7f\n\x12StreamingRecognize\x12\x31.google.cloud.speech.v1.StreamingRecognizeRequest\x1a\x32.google.cloud.speech.v1.StreamingRecognizeResponse(\x01\x30\x01\x42l\n\x1a\x63om.google.cloud.speech.v1B\x0bSpeechProtoP\x01Z\n\x0fspeech_contexts\x18\x06 \x03(\x0b\x32%.google.cloud.speech.v1.SpeechContext\x12 \n\x18\x65nable_word_time_offsets\x18\x08 \x01(\x08\"\x8b\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\" \n\rSpeechContext\x12\x0f\n\x07phrases\x18\x01 \x03(\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\"`\n\x1cLongRunningRecognizeResponse\x12@\n\x07results\x18\x02 \x03(\x0b\x32/.google.cloud.speech.v1.SpeechRecognitionResult\"\x9e\x01\n\x1cLongRunningRecognizeMetadata\x12\x18\n\x10progress_percent\x18\x01 \x01(\x05\x12.\n\nstart_time\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x34\n\x10last_update_time\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\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\"\x8d\x01\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\"e\n\x17SpeechRecognitionResult\x12J\n\x0c\x61lternatives\x18\x01 \x03(\x0b\x32\x34.google.cloud.speech.v1.SpeechRecognitionAlternative\"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(\t2\xa6\x03\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\x96\x01\n\x14LongRunningRecognize\x12\x33.google.cloud.speech.v1.LongRunningRecognizeRequest\x1a\x1d.google.longrunning.Operation\"*\x82\xd3\xe4\x93\x02$\"\x1f/v1/speech:longrunningrecognize:\x01*\x12\x7f\n\x12StreamingRecognize\x12\x31.google.cloud.speech.v1.StreamingRecognizeRequest\x1a\x32.google.cloud.speech.v1.StreamingRecognizeResponse(\x01\x30\x01\x42l\n\x1a\x63om.google.cloud.speech.v1B\x0bSpeechProtoP\x01Z= 0.28.0, < 0.29dev', - 'google-api-core >= 0.1.1, < 0.2.0dev', - 'google-gax >= 0.15.14, < 0.16dev', + 'google-auth>=1.0.2, <2.0dev', + 'google-api-core >= 0.1.4, < 0.2.0dev', + 'googleapis-common-protos[grpc]>=1.5.2, <2.0dev', + 'requests>=2.18.4, <3.0dev', ] setup( name='google-cloud-speech', - version='0.30.1.dev1', + version='0.31.0', description='Python Client for Google Cloud Speech', long_description=README, namespace_packages=[ 'google', 'google.cloud', - 'google.cloud.gapic', - 'google.cloud.gapic.speech', - 'google.cloud.proto', - 'google.cloud.proto.speech', ], packages=find_packages(exclude=('tests*',)), install_requires=REQUIREMENTS, diff --git a/speech/tests/data/hello.wav b/speech/tests/data/hello.wav deleted file mode 100644 index 0378f790119f..000000000000 Binary files a/speech/tests/data/hello.wav and /dev/null differ diff --git a/speech/tests/gapic/test_speech_client_v1.py b/speech/tests/gapic/test_speech_client_v1.py deleted file mode 100644 index 2923f12b0fee..000000000000 --- a/speech/tests/gapic/test_speech_client_v1.py +++ /dev/null @@ -1,212 +0,0 @@ -# Copyright 2017, Google LLC All rights reserved. -# -# 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. -"""Unit tests.""" - -import mock -import unittest - -from google.gax import errors -from google.rpc import status_pb2 - -from google.cloud.gapic.speech.v1 import enums -from google.cloud.gapic.speech.v1 import speech_client -from google.cloud.proto.speech.v1 import cloud_speech_pb2 -from google.longrunning import operations_pb2 - - -class CustomException(Exception): - pass - - -class TestSpeechClient(unittest.TestCase): - @mock.patch('google.gax.config.create_stub', spec=True) - def test_recognize(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub - - client = speech_client.SpeechClient() - - # Mock request - encoding = enums.RecognitionConfig.AudioEncoding.FLAC - sample_rate_hertz = 44100 - language_code = 'en-US' - config = cloud_speech_pb2.RecognitionConfig( - encoding=encoding, - sample_rate_hertz=sample_rate_hertz, - language_code=language_code) - uri = 'gs://bucket_name/file_name.flac' - audio = cloud_speech_pb2.RecognitionAudio(uri=uri) - - # Mock response - expected_response = cloud_speech_pb2.RecognizeResponse() - grpc_stub.Recognize.return_value = expected_response - - response = client.recognize(config, audio) - self.assertEqual(expected_response, response) - - grpc_stub.Recognize.assert_called_once() - args, kwargs = grpc_stub.Recognize.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] - - expected_request = cloud_speech_pb2.RecognizeRequest( - config=config, audio=audio) - self.assertEqual(expected_request, actual_request) - - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_recognize_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub - - client = speech_client.SpeechClient() - - # Mock request - encoding = enums.RecognitionConfig.AudioEncoding.FLAC - sample_rate_hertz = 44100 - language_code = 'en-US' - config = cloud_speech_pb2.RecognitionConfig( - encoding=encoding, - sample_rate_hertz=sample_rate_hertz, - language_code=language_code) - uri = 'gs://bucket_name/file_name.flac' - audio = cloud_speech_pb2.RecognitionAudio(uri=uri) - - # Mock exception response - grpc_stub.Recognize.side_effect = CustomException() - - self.assertRaises(errors.GaxError, client.recognize, config, audio) - - @mock.patch('google.gax.config.create_stub', spec=True) - def test_long_running_recognize(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub - - client = speech_client.SpeechClient() - - # Mock request - encoding = enums.RecognitionConfig.AudioEncoding.FLAC - sample_rate_hertz = 44100 - language_code = 'en-US' - config = cloud_speech_pb2.RecognitionConfig( - encoding=encoding, - sample_rate_hertz=sample_rate_hertz, - language_code=language_code) - uri = 'gs://bucket_name/file_name.flac' - audio = cloud_speech_pb2.RecognitionAudio(uri=uri) - - # Mock response - expected_response = cloud_speech_pb2.LongRunningRecognizeResponse() - operation = operations_pb2.Operation( - name='operations/test_long_running_recognize', done=True) - operation.response.Pack(expected_response) - grpc_stub.LongRunningRecognize.return_value = operation - - response = client.long_running_recognize(config, audio) - self.assertEqual(expected_response, response.result()) - - grpc_stub.LongRunningRecognize.assert_called_once() - args, kwargs = grpc_stub.LongRunningRecognize.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] - - expected_request = cloud_speech_pb2.LongRunningRecognizeRequest( - config=config, audio=audio) - self.assertEqual(expected_request, actual_request) - - @mock.patch('google.gax.config.create_stub', spec=True) - def test_long_running_recognize_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub - - client = speech_client.SpeechClient() - - # Mock request - encoding = enums.RecognitionConfig.AudioEncoding.FLAC - sample_rate_hertz = 44100 - language_code = 'en-US' - config = cloud_speech_pb2.RecognitionConfig( - encoding=encoding, - sample_rate_hertz=sample_rate_hertz, - language_code=language_code) - uri = 'gs://bucket_name/file_name.flac' - audio = cloud_speech_pb2.RecognitionAudio(uri=uri) - - # Mock exception response - error = status_pb2.Status() - operation = operations_pb2.Operation( - name='operations/test_long_running_recognize_exception', done=True) - operation.error.CopyFrom(error) - grpc_stub.LongRunningRecognize.return_value = operation - - response = client.long_running_recognize(config, audio) - self.assertEqual(error, response.exception()) - - @mock.patch('google.gax.config.create_stub', spec=True) - def test_streaming_recognize(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub - - client = speech_client.SpeechClient() - - # Mock request - request = cloud_speech_pb2.StreamingRecognizeRequest() - requests = [request] - - # Mock response - expected_response = cloud_speech_pb2.StreamingRecognizeResponse() - grpc_stub.StreamingRecognize.return_value = iter([expected_response]) - - response = client.streaming_recognize(requests) - resources = list(response) - self.assertEqual(1, len(resources)) - self.assertEqual(expected_response, resources[0]) - - grpc_stub.StreamingRecognize.assert_called_once() - args, kwargs = grpc_stub.StreamingRecognize.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_requests = args[0] - self.assertEqual(1, len(actual_requests)) - actual_request = list(actual_requests)[0] - self.assertEqual(request, actual_request) - - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_streaming_recognize_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub - - client = speech_client.SpeechClient() - - # Mock request - request = cloud_speech_pb2.StreamingRecognizeRequest() - requests = [request] - - # Mock exception response - grpc_stub.StreamingRecognize.side_effect = CustomException() - - self.assertRaises(errors.GaxError, client.streaming_recognize, - requests) diff --git a/speech/tests/system.py b/speech/tests/system.py deleted file mode 100644 index 460712a7a519..000000000000 --- a/speech/tests/system.py +++ /dev/null @@ -1,283 +0,0 @@ -# Copyright 2016 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 io -import os -import time -import unittest -import wave - -import six - -from google.cloud import exceptions -from google.cloud import speech -from google.cloud import storage -from google.cloud.speech.alternative import Alternative - -from test_utils.retry import RetryErrors -from test_utils.retry import RetryResult -from test_utils.system import unique_resource_id - - -AUDIO_FILE = os.path.join(os.path.dirname(__file__), 'data', 'hello.wav') - - -def _operation_complete(result): - """Return operation result.""" - return result - - -def _wait_until_complete(operation, max_attempts=10): - """Wait until an operation has completed. - - :type operation: :class:`google.cloud.operation.Operation` - :param operation: Operation that has not completed. - - :type max_attempts: int - :param max_attempts: (Optional) The maximum number of times to check if - the operation has completed. Defaults to 5. - - :rtype: bool - :returns: Boolean indicating if the operation is complete. - """ - # This bizarre delay is necessary because the v1 API seems to return - # the v1beta1 type URL sometimes if you poll too soon. - time.sleep(3) - retry = RetryResult(_operation_complete, max_tries=max_attempts) - return retry(operation.poll)() - - -class Config(object): - """Run-time configuration to be modified at set-up. - - This is a mutable stand-in to allow test set-up to modify - global state. - """ - CLIENT = None - TEST_BUCKET = None - USE_GRPC = True - - -def setUpModule(): - Config.CLIENT = speech.Client() - Config.USE_GRPC = Config.CLIENT._use_grpc - # Now create a bucket for GCS stored content. - storage_client = storage.Client() - bucket_name = 'new' + unique_resource_id() - Config.TEST_BUCKET = storage_client.bucket(bucket_name) - # 429 Too Many Requests in case API requests rate-limited. - retry_429 = RetryErrors(exceptions.TooManyRequests) - retry_429(Config.TEST_BUCKET.create)() - - -def tearDownModule(): - # 409 Conflict if the bucket is full. - # 429 Too Many Requests in case API requests rate-limited. - bucket_retry = RetryErrors( - (exceptions.TooManyRequests, exceptions.Conflict)) - bucket_retry(Config.TEST_BUCKET.delete)(force=True) - - -class TestSpeechClient(unittest.TestCase): - ASSERT_TEXT = 'thank you for using Google Cloud platform' - - def setUp(self): - self.to_delete_by_case = [] - - def tearDown(self): - for value in self.to_delete_by_case: - value.delete() - - def _make_sync_request(self, content=None, source_uri=None, - max_alternatives=None): - client = Config.CLIENT - sample = client.sample( - content=content, - encoding=speech.Encoding.LINEAR16, - sample_rate_hertz=16000, - source_uri=source_uri, - ) - return sample.recognize( - language_code='en-US', - max_alternatives=max_alternatives, - profanity_filter=True, - speech_contexts=['Google', 'cloud'], - ) - - def _make_async_request(self, content=None, source_uri=None, - max_alternatives=None): - client = Config.CLIENT - sample = client.sample( - content=content, - encoding=speech.Encoding.LINEAR16, - sample_rate_hertz=16000, - source_uri=source_uri, - ) - return sample.long_running_recognize( - language_code='en-US', - max_alternatives=max_alternatives, - profanity_filter=True, - speech_contexts=['Google', 'cloud'], - ) - - def _make_streaming_request(self, file_obj, single_utterance=True, - interim_results=False): - client = Config.CLIENT - sample = client.sample(stream=file_obj, - encoding=speech.Encoding.LINEAR16, - sample_rate_hertz=16000) - return sample.streaming_recognize( - interim_results=interim_results, - language_code='en-US', - single_utterance=single_utterance, - speech_contexts=['hello', 'google'], - ) - - def _check_results(self, alternatives, num_results=1): - self.assertEqual(len(alternatives), num_results) - top_result = alternatives[0] - self.assertIsInstance(top_result, Alternative) - self.assertEqual(top_result.transcript, - 'hello ' + self.ASSERT_TEXT) - self.assertIsInstance(top_result.confidence, float) - if num_results == 2: - second_alternative = alternatives[1] - self.assertIsInstance(second_alternative, Alternative) - self.assertEqual(second_alternative.transcript, self.ASSERT_TEXT) - self.assertIsNone(second_alternative.confidence) - - def test_sync_recognize_local_file(self): - with open(AUDIO_FILE, 'rb') as file_obj: - content = file_obj.read() - - results = self._make_sync_request(content=content, - max_alternatives=1) - self.assertEqual(len(results), 1) - alternatives = results[0].alternatives - self.assertEqual(len(alternatives), 1) - self._check_results(alternatives, 1) - - def test_sync_recognize_gcs_file(self): - bucket_name = Config.TEST_BUCKET.name - blob_name = 'hello.wav' - blob = Config.TEST_BUCKET.blob(blob_name) - self.to_delete_by_case.append(blob) # Clean-up. - with open(AUDIO_FILE, 'rb') as file_obj: - blob.upload_from_file(file_obj) - - source_uri = 'gs://%s/%s' % (bucket_name, blob_name) - results = self._make_sync_request(source_uri=source_uri, - max_alternatives=1) - self.assertEqual(len(results), 1) - self._check_results(results[0].alternatives) - - def test_async_recognize_local_file(self): - with open(AUDIO_FILE, 'rb') as file_obj: - content = file_obj.read() - - operation = self._make_async_request(content=content, - max_alternatives=1) - _wait_until_complete(operation) - self.assertEqual(len(operation.results), 1) - alternatives = operation.results[0].alternatives - self.assertEqual(len(alternatives), 1) - self._check_results(alternatives, 1) - - def test_async_recognize_gcs_file(self): - bucket_name = Config.TEST_BUCKET.name - blob_name = 'hello.wav' - blob = Config.TEST_BUCKET.blob(blob_name) - self.to_delete_by_case.append(blob) # Clean-up. - with open(AUDIO_FILE, 'rb') as file_obj: - blob.upload_from_file(file_obj) - - source_uri = 'gs://%s/%s' % (bucket_name, blob_name) - operation = self._make_async_request(source_uri=source_uri, - max_alternatives=1) - - _wait_until_complete(operation) - self.assertEqual(len(operation.results), 1) - alternatives = operation.results[0].alternatives - self.assertEqual(len(alternatives), 1) - self._check_results(alternatives, 1) - - def test_stream_recognize(self): - if not Config.USE_GRPC: - self.skipTest('gRPC is required for Speech Streaming Recognize.') - - with open(AUDIO_FILE, 'rb') as file_obj: - for results in self._make_streaming_request(file_obj): - self._check_results(results.alternatives) - - def test_stream_recognize_interim_results(self): - if not Config.USE_GRPC: - self.skipTest('gRPC is required for Speech Streaming Recognize.') - - # Just test that the iterim results exist; the exact value can and - # does change, so writing a test for it is difficult. - with open(AUDIO_FILE, 'rb') as file_obj: - recognize = self._make_streaming_request(file_obj, - interim_results=True) - responses = list(recognize) - for response in responses: - self.assertIsInstance( - response.alternatives[0].transcript, - six.text_type, - ) - - self.assertGreater(len(responses), 5) - self._check_results(responses[-1].alternatives) - - def test_stream_recognize_single_utterance(self): - if not Config.USE_GRPC: - self.skipTest('gRPC is required for Speech Streaming Recognize.') - - with open(AUDIO_FILE, 'rb') as file_obj: - for results in self._make_streaming_request( - file_obj, single_utterance=False): - self._check_results(results.alternatives) - - def test_long_running_recognize(self): - content = None - repetitions = 5 - with open(AUDIO_FILE, 'rb') as in_stream: - in_wavfile = wave.open(in_stream) - params = in_wavfile.getparams() - frames = in_wavfile.readframes(in_wavfile.getnframes()) - - with io.BytesIO() as out_stream: - out_wavfile = wave.open(out_stream, 'w') - out_wavfile.setparams(params) - for _ in range(repetitions): - out_wavfile.writeframes(frames) - content = out_stream.getvalue() - - client = speech.SpeechClient() - - operation = client.long_running_recognize( - config=speech.types.RecognitionConfig( - encoding='LINEAR16', - language_code='en-US', - ), - audio=speech.types.RecognitionAudio(content=content) - ) - - op_result = operation.result() - wav_transcription = 'hello thank you for using google cloud platform' - expected = ' '.join([wav_transcription] * repetitions) - self.assertGreater(len(op_result.results), 0) - for result in op_result.results: - self.assertGreater(len(result.alternatives), 0) - for alternative in result.alternatives: - self.assertEqual(alternative.transcript.lower(), expected) diff --git a/speech/tests/system/gapic/v1/test_system_speech_v1.py b/speech/tests/system/gapic/v1/test_system_speech_v1.py new file mode 100644 index 000000000000..36728e6cb1ad --- /dev/null +++ b/speech/tests/system/gapic/v1/test_system_speech_v1.py @@ -0,0 +1,36 @@ +# Copyright 2018 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 +# +# https://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 time + +from google.cloud import speech_v1 +from google.cloud.speech_v1 import enums +from google.cloud.speech_v1.proto import cloud_speech_pb2 + + +class TestSystemSpeech(object): + def test_recognize(self): + + client = speech_v1.SpeechClient() + language_code = 'en-US' + sample_rate_hertz = 44100 + encoding = enums.RecognitionConfig.AudioEncoding.FLAC + config = { + 'language_code': language_code, + 'sample_rate_hertz': sample_rate_hertz, + 'encoding': encoding + } + uri = 'gs://gapic-toolkit/hello.flac' + audio = {'uri': uri} + response = client.recognize(config, audio) diff --git a/speech/tests/unit/_fixtures.py b/speech/tests/unit/_fixtures.py deleted file mode 100644 index aa3534c84d9c..000000000000 --- a/speech/tests/unit/_fixtures.py +++ /dev/null @@ -1,72 +0,0 @@ -# Copyright 2016 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. - -SYNC_RECOGNIZE_RESPONSE = { - 'results': [ - { - 'alternatives': [ - { - 'transcript': 'hello', - 'confidence': 0.784919, - }, - ], - }, - ], -} - -SYNC_RECOGNIZE_EMPTY_RESPONSE = { - 'results': [], -} - -ASYNC_RECOGNIZE_RESPONSE = { - 'name': '123456789', -} - -OPERATION_COMPLETE_RESPONSE = { - 'name': '123456789', - 'metadata': { - '@type': ('type.googleapis.com/' - 'google.cloud.speech.v1.LongRunningRecognizeMetadata'), - 'progressPercent': 100, - 'startTime': '2016-09-22T17:52:25.536964Z', - 'lastUpdateTime': '2016-09-22T17:52:27.802902Z', - }, - 'done': True, - 'response': { - '@type': ('type.googleapis.com/' - 'google.cloud.speech.v1.LongRunningRecognizeResponse'), - 'results': [ - { - 'alternatives': [ - { - 'transcript': 'how old is the Brooklyn Bridge', - 'confidence': 0.98267895, - }, - ], - }, - ], - }, -} - -OPERATION_INCOMPLETE_RESPONSE = { - 'name': '123456789', - 'metadata': { - '@type': ('type.googleapis.com/' - 'google.cloud.speech.v1.LongRunningRecognizeMetadata'), - 'progressPercent': 27, - 'startTime': '2016-09-22T17:52:25.536964Z', - 'lastUpdateTime': '2016-09-22T17:52:27.802902Z', - }, - 'done': False, -} diff --git a/speech/tests/unit/test_helpers.py b/speech/tests/unit/gapic/v1/test_helpers.py similarity index 93% rename from speech/tests/unit/test_helpers.py rename to speech/tests/unit/gapic/v1/test_helpers.py index 3e0487e94adc..a8f2061f2088 100644 --- a/speech/tests/unit/test_helpers.py +++ b/speech/tests/unit/gapic/v1/test_helpers.py @@ -40,10 +40,12 @@ def test_inherited_method(self): client.recognize(config, audio) # Assert that the underlying GAPIC method was called as expected. - recognize.assert_called_once_with(types.RecognizeRequest( + assert recognize.call_count == 1 + _, args, _ = recognize.mock_calls[0] + assert args[0] == types.RecognizeRequest( config=config, audio=audio, - ), None) + ) def test_streaming_recognize(self): from google.cloud.speech_v1 import types diff --git a/speech/tests/unit/gapic/v1/test_speech_client_v1.py b/speech/tests/unit/gapic/v1/test_speech_client_v1.py new file mode 100644 index 000000000000..332338f941d2 --- /dev/null +++ b/speech/tests/unit/gapic/v1/test_speech_client_v1.py @@ -0,0 +1,223 @@ +# Copyright 2018 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 +# +# https://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. +"""Unit tests.""" + +import pytest + +from google.rpc import status_pb2 + +from google.cloud import speech_v1 +from google.cloud.speech_v1 import enums +from google.cloud.speech_v1.proto import cloud_speech_pb2 +from google.longrunning import operations_pb2 + + +class MultiCallableStub(object): + """Stub for the grpc.UnaryUnaryMultiCallable interface.""" + + def __init__(self, method, channel_stub): + self.method = method + self.channel_stub = channel_stub + + def __call__(self, request, timeout=None, metadata=None, credentials=None): + self.channel_stub.requests.append((self.method, request)) + + response = None + if self.channel_stub.responses: + response = self.channel_stub.responses.pop() + + if isinstance(response, Exception): + raise response + + if response: + return response + + +class ChannelStub(object): + """Stub for the grpc.Channel interface.""" + + def __init__(self, responses=[]): + self.responses = responses + self.requests = [] + + def unary_unary(self, + method, + request_serializer=None, + response_deserializer=None): + return MultiCallableStub(method, self) + + def stream_stream(self, + method, + request_serializer=None, + response_deserializer=None): + return MultiCallableStub(method, self) + + +class CustomException(Exception): + pass + + +class TestSpeechClient(object): + def test_recognize(self): + # Setup Expected Response + expected_response = {} + expected_response = cloud_speech_pb2.RecognizeResponse( + **expected_response) + + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = speech_v1.SpeechClient(channel=channel) + + # Setup Request + encoding = enums.RecognitionConfig.AudioEncoding.FLAC + sample_rate_hertz = 44100 + language_code = 'en-US' + config = { + 'encoding': encoding, + 'sample_rate_hertz': sample_rate_hertz, + 'language_code': language_code + } + uri = 'gs://bucket_name/file_name.flac' + audio = {'uri': uri} + + response = client.recognize(config, audio) + assert expected_response == response + + assert len(channel.requests) == 1 + expected_request = cloud_speech_pb2.RecognizeRequest( + config=config, audio=audio) + actual_request = channel.requests[0][1] + assert expected_request == actual_request + + def test_recognize_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = speech_v1.SpeechClient(channel=channel) + + # Setup request + encoding = enums.RecognitionConfig.AudioEncoding.FLAC + sample_rate_hertz = 44100 + language_code = 'en-US' + config = { + 'encoding': encoding, + 'sample_rate_hertz': sample_rate_hertz, + 'language_code': language_code + } + uri = 'gs://bucket_name/file_name.flac' + audio = {'uri': uri} + + with pytest.raises(CustomException): + client.recognize(config, audio) + + def test_long_running_recognize(self): + # Setup Expected Response + expected_response = {} + expected_response = cloud_speech_pb2.LongRunningRecognizeResponse( + **expected_response) + operation = operations_pb2.Operation( + name='operations/test_long_running_recognize', done=True) + operation.response.Pack(expected_response) + + # Mock the API response + channel = ChannelStub(responses=[operation]) + client = speech_v1.SpeechClient(channel=channel) + + # Setup Request + encoding = enums.RecognitionConfig.AudioEncoding.FLAC + sample_rate_hertz = 44100 + language_code = 'en-US' + config = { + 'encoding': encoding, + 'sample_rate_hertz': sample_rate_hertz, + 'language_code': language_code + } + uri = 'gs://bucket_name/file_name.flac' + audio = {'uri': uri} + + response = client.long_running_recognize(config, audio) + result = response.result() + assert expected_response == result + + assert len(channel.requests) == 1 + expected_request = cloud_speech_pb2.LongRunningRecognizeRequest( + config=config, audio=audio) + actual_request = channel.requests[0][1] + assert expected_request == actual_request + + def test_long_running_recognize_exception(self): + # Setup Response + error = status_pb2.Status() + operation = operations_pb2.Operation( + name='operations/test_long_running_recognize_exception', done=True) + operation.error.CopyFrom(error) + + # Mock the API response + channel = ChannelStub(responses=[operation]) + client = speech_v1.SpeechClient(channel=channel) + + # Setup Request + encoding = enums.RecognitionConfig.AudioEncoding.FLAC + sample_rate_hertz = 44100 + language_code = 'en-US' + config = { + 'encoding': encoding, + 'sample_rate_hertz': sample_rate_hertz, + 'language_code': language_code + } + uri = 'gs://bucket_name/file_name.flac' + audio = {'uri': uri} + + response = client.long_running_recognize(config, audio) + exception = response.exception() + assert exception.errors[0] == error + + def test_streaming_recognize(self): + # Setup Expected Response + expected_response = {} + expected_response = cloud_speech_pb2.StreamingRecognizeResponse( + **expected_response) + + # Mock the API response + channel = ChannelStub(responses=[iter([expected_response])]) + client = speech_v1.SpeechClient(channel=channel) + + # Setup Request + request = {} + request = cloud_speech_pb2.StreamingRecognizeRequest(**request) + requests = [request] + + response = client._streaming_recognize(requests) + resources = list(response) + assert len(resources) == 1 + assert expected_response == resources[0] + + assert len(channel.requests) == 1 + actual_requests = channel.requests[0][1] + assert len(actual_requests) == 1 + actual_request = list(actual_requests)[0] + assert request == actual_request + + def test_streaming_recognize_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = speech_v1.SpeechClient(channel=channel) + + # Setup request + request = {} + + request = cloud_speech_pb2.StreamingRecognizeRequest(**request) + requests = [request] + + with pytest.raises(CustomException): + client._streaming_recognize(requests) diff --git a/speech/tests/unit/test__gax.py b/speech/tests/unit/test__gax.py deleted file mode 100644 index 1f4477fd1a73..000000000000 --- a/speech/tests/unit/test__gax.py +++ /dev/null @@ -1,180 +0,0 @@ -# Copyright 2016 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 unittest - -import mock - - -def _make_credentials(): - import google.auth.credentials - - return mock.Mock(spec=google.auth.credentials.Credentials) - - -class TestGAPICSpeechAPI(unittest.TestCase): - - @staticmethod - def _get_target_class(): - from google.cloud.speech._gax import GAPICSpeechAPI - - return GAPICSpeechAPI - - def _make_one(self, *args, **kw): - return self._get_target_class()(*args, **kw) - - @mock.patch('google.cloud._helpers.make_secure_channel', - return_value=mock.sentinel.channel) - @mock.patch( - 'google.cloud.gapic.speech.v1.speech_client.SpeechClient.__init__', - return_value=None) - @mock.patch('google.cloud._helpers.make_secure_stub', - return_value=mock.sentinel.stub) - def test_constructor(self, mocked_stub, mocked_init, mocked_channel): - from google.longrunning import operations_grpc - from google.cloud._http import DEFAULT_USER_AGENT - from google.cloud.gapic.speech.v1.speech_client import SpeechClient - from google.cloud.speech import __version__ - from google.cloud.speech._gax import OPERATIONS_API_HOST - - credentials = _make_credentials() - mock_cnxn = mock.Mock(credentials=credentials, spec=['credentials']) - mock_client = mock.Mock( - _connection=mock_cnxn, _credentials=credentials, - spec=['_connection', '_credentials']) - - speech_api = self._make_one(mock_client) - self.assertIs(speech_api._client, mock_client) - self.assertIsInstance(speech_api._gapic_api, SpeechClient) - - mocked_stub.assert_called_once_with( - mock_cnxn.credentials, DEFAULT_USER_AGENT, - operations_grpc.OperationsStub, OPERATIONS_API_HOST) - mocked_init.assert_called_once_with( - channel=mock.sentinel.channel, lib_name='gccl', - lib_version=__version__) - mocked_channel.assert_called_once_with( - mock_cnxn.credentials, DEFAULT_USER_AGENT, - 'speech.googleapis.com') - - -class TestSpeechGAXMakeRequests(unittest.TestCase): - SAMPLE_RATE = 16000 - HINTS = ['hi'] - AUDIO_CONTENT = b'/9j/4QNURXhpZgAASUkq' - - def _call_fut(self, sample, language_code, max_alternatives, - profanity_filter, speech_contexts, single_utterance, - interim_results): - from google.cloud.speech._gax import _make_streaming_request - - return _make_streaming_request( - sample=sample, language_code=language_code, - max_alternatives=max_alternatives, - profanity_filter=profanity_filter, speech_contexts=speech_contexts, - single_utterance=single_utterance, interim_results=interim_results) - - def test_ctor(self): - from google.cloud import speech - from google.cloud.speech.sample import Sample - from google.cloud.proto.speech.v1.cloud_speech_pb2 import ( - RecognitionConfig, SpeechContext, StreamingRecognitionConfig, - StreamingRecognizeRequest) - - sample = Sample( - content=self.AUDIO_CONTENT, encoding=speech.Encoding.FLAC, - sample_rate_hertz=self.SAMPLE_RATE) - language_code = 'US-en' - max_alternatives = 2 - profanity_filter = True - speech_contexts = [SpeechContext(phrases=self.HINTS)] - single_utterance = True - interim_results = False - - streaming_request = self._call_fut( - sample, language_code, max_alternatives, profanity_filter, - speech_contexts, single_utterance, interim_results) - self.assertIsInstance(streaming_request, StreamingRecognizeRequest) - - # This isn't set by _make_streaming_request(). - # The first request can only have `streaming_config` set. - # The following requests can only have `audio_content` set. - self.assertEqual(streaming_request.audio_content, b'') - - self.assertIsInstance( - streaming_request.streaming_config, StreamingRecognitionConfig) - streaming_config = streaming_request.streaming_config - self.assertTrue(streaming_config.single_utterance) - self.assertFalse(streaming_config.interim_results) - config = streaming_config.config - self.assertIsInstance(config, RecognitionConfig) - self.assertEqual(config.encoding, 2) # speech.Encoding.FLAC maps to 2. - self.assertEqual(config.sample_rate_hertz, self.SAMPLE_RATE) - self.assertEqual(config.language_code, language_code) - self.assertEqual(config.max_alternatives, max_alternatives) - self.assertTrue(config.profanity_filter) - self.assertEqual(config.speech_contexts[0].phrases, self.HINTS) - - -class TestSpeechGAXMakeRequestsStream(unittest.TestCase): - SAMPLE_RATE = 16000 - HINTS = ['hi'] - AUDIO_CONTENT = b'/9j/4QNURXhpZgAASUkq' - - def _call_fut(self, sample, language_code, max_alternatives, - profanity_filter, speech_contexts, single_utterance, - interim_results): - from google.cloud.speech._gax import _stream_requests - - return _stream_requests( - sample=sample, language_code=language_code, - max_alternatives=max_alternatives, - profanity_filter=profanity_filter, speech_contexts=speech_contexts, - single_utterance=single_utterance, interim_results=interim_results) - - def test_stream_requests(self): - from io import BytesIO - from google.cloud import speech - from google.cloud.speech.sample import Sample - from google.cloud.proto.speech.v1.cloud_speech_pb2 import ( - StreamingRecognitionConfig, StreamingRecognizeRequest) - - sample = Sample( - stream=BytesIO(self.AUDIO_CONTENT), encoding=speech.Encoding.FLAC, - sample_rate_hertz=self.SAMPLE_RATE) - language_code = 'US-en' - max_alternatives = 2 - profanity_filter = True - speech_contexts = self.HINTS - single_utterance = True - interim_results = False - streaming_requests = self._call_fut( - sample, language_code, max_alternatives, profanity_filter, - speech_contexts, single_utterance, interim_results) - all_requests = [] - for streaming_request in streaming_requests: - self.assertIsInstance(streaming_request, StreamingRecognizeRequest) - all_requests.append(streaming_request) - - self.assertEqual(len(all_requests), 2) - - config_request = all_requests[0] - streaming_request = all_requests[1] - # This isn't set by _make_streaming_request(). - # The first request can only have `streaming_config` set. - # The following requests can only have `audio_content` set. - self.assertEqual(config_request.audio_content, b'') - self.assertEqual(streaming_request.audio_content, self.AUDIO_CONTENT) - self.assertIsInstance( - config_request.streaming_config, StreamingRecognitionConfig) diff --git a/speech/tests/unit/test__http.py b/speech/tests/unit/test__http.py deleted file mode 100644 index ad7da038bf97..000000000000 --- a/speech/tests/unit/test__http.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2016 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 unittest - -import mock - - -class TestConnection(unittest.TestCase): - - @staticmethod - def _get_target_class(): - from google.cloud.speech._http import Connection - - return Connection - - def _make_one(self, *args, **kw): - return self._get_target_class()(*args, **kw) - - def test_build_api_url(self): - conn = self._make_one(object()) - method = 'speech:syncrecognize' - uri = '/'.join([ - conn.API_BASE_URL, - conn.API_VERSION, - method, - ]) - - self.assertEqual(conn.build_api_url(method), uri) - - def test_extra_headers(self): - import requests - - from google.cloud import _http as base_http - from google.cloud.speech import _http as MUT - - http = mock.create_autospec(requests.Session, instance=True) - response = requests.Response() - response.status_code = 200 - data = b'brent-spiner' - response._content = data - http.request.return_value = response - client = mock.Mock(_http=http, spec=['_http']) - - conn = self._make_one(client) - req_data = 'req-data-boring' - result = conn.api_request( - 'GET', '/rainbow', data=req_data, expect_json=False) - self.assertEqual(result, data) - - expected_headers = { - 'Accept-Encoding': 'gzip', - base_http.CLIENT_INFO_HEADER: MUT._CLIENT_INFO, - 'User-Agent': conn.USER_AGENT, - } - expected_uri = conn.build_api_url('/rainbow') - http.request.assert_called_once_with( - data=req_data, - headers=expected_headers, - method='GET', - url=expected_uri, - ) diff --git a/speech/tests/unit/test_alternative.py b/speech/tests/unit/test_alternative.py deleted file mode 100644 index df5081cc28f4..000000000000 --- a/speech/tests/unit/test_alternative.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright 2016 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 unittest - - -class TestAlternative(unittest.TestCase): - - @staticmethod - def _get_target_class(): - from google.cloud.speech.alternative import Alternative - - return Alternative - - def _make_one(self, *args, **kwargs): - return self._get_target_class()(*args, **kwargs) - - def test_constructor(self): - text = 'hello goodbye upstairs' - confidence = 0.5546875 - alternative = self._make_one(text, confidence) - self.assertEqual(alternative._transcript, text) - self.assertEqual(alternative._confidence, confidence) - - def test_transcript_property(self): - text = 'is this thing on?' - alternative = self._make_one(text, None) - self.assertEqual(alternative.transcript, text) - - def test_confidence_property(self): - confidence = 0.412109375 - alternative = self._make_one(None, confidence) - self.assertEqual(alternative.confidence, confidence) - - def test_from_api_repr_with_no_confidence(self): - data = { - 'transcript': 'testing 1 2 3', - } - - klass = self._get_target_class() - alternative = klass.from_api_repr(data) - self.assertEqual(alternative.transcript, data['transcript']) - self.assertIsNone(alternative.confidence) - - def test_from_pb_with_no_confidence(self): - from google.cloud.proto.speech.v1 import cloud_speech_pb2 - - text = 'the double trouble' - pb_value = cloud_speech_pb2.SpeechRecognitionAlternative( - transcript=text) - self.assertEqual(pb_value.confidence, 0.0) - - klass = self._get_target_class() - alternative = klass.from_pb(pb_value) - self.assertEqual(alternative.transcript, text) - self.assertIsNone(alternative.confidence) diff --git a/speech/tests/unit/test_client.py b/speech/tests/unit/test_client.py deleted file mode 100644 index 7467045194ec..000000000000 --- a/speech/tests/unit/test_client.py +++ /dev/null @@ -1,732 +0,0 @@ -# Copyright 2016 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 unittest - -import mock - - -def _make_credentials(): - import google.auth.credentials - - return mock.Mock(spec=google.auth.credentials.Credentials) - - -def _make_result(alternatives=()): - from google.cloud.proto.speech.v1 import cloud_speech_pb2 - - return cloud_speech_pb2.SpeechRecognitionResult( - alternatives=[ - cloud_speech_pb2.SpeechRecognitionAlternative( - transcript=alternative['transcript'], - confidence=alternative['confidence'], - ) for alternative in alternatives - ], - ) - - -def _make_streaming_result(alternatives=(), is_final=True, stability=1.0): - from google.cloud.proto.speech.v1 import cloud_speech_pb2 - - return cloud_speech_pb2.StreamingRecognitionResult( - alternatives=[ - cloud_speech_pb2.SpeechRecognitionAlternative( - transcript=alternative['transcript'], - confidence=alternative['confidence'], - ) for alternative in alternatives - ], - is_final=is_final, - stability=stability, - ) - - -def _make_streaming_response(*results): - from google.cloud.proto.speech.v1 import cloud_speech_pb2 - - response = cloud_speech_pb2.StreamingRecognizeResponse( - results=results, - ) - return response - - -def _make_sync_response(*results): - from google.cloud.proto.speech.v1 import cloud_speech_pb2 - - response = cloud_speech_pb2.RecognizeResponse( - results=results, - ) - return response - - -class TestClient(unittest.TestCase): - SAMPLE_RATE = 16000 - HINTS = ['hi'] - AUDIO_SOURCE_URI = 'gs://sample-bucket/sample-recording.flac' - AUDIO_CONTENT = b'testing 1 2 3' - - @staticmethod - def _get_target_class(): - from google.cloud.speech.client import Client - - return Client - - def _make_one(self, *args, **kw): - return self._get_target_class()(*args, **kw) - - def test_ctor(self): - creds = _make_credentials() - http = object() - client = self._make_one(credentials=creds, _http=http) - self.assertIs(client._credentials, creds) - self.assertIs(client._http, http) - - def test_ctor_use_grpc_preset(self): - creds = _make_credentials() - http = object() - client = self._make_one(credentials=creds, _http=http, _use_grpc=True) - self.assertTrue(client._use_grpc) - - def test_create_sample_from_client(self): - from google.cloud import speech - from google.cloud.speech.sample import Sample - - credentials = _make_credentials() - client = self._make_one(credentials=credentials) - - sample = client.sample( - source_uri=self.AUDIO_SOURCE_URI, encoding=speech.Encoding.FLAC, - sample_rate_hertz=self.SAMPLE_RATE) - self.assertIsInstance(sample, Sample) - self.assertEqual(sample.source_uri, self.AUDIO_SOURCE_URI) - self.assertEqual(sample.sample_rate_hertz, self.SAMPLE_RATE) - self.assertEqual(sample.encoding, speech.Encoding.FLAC) - - content_sample = client.sample( - content=self.AUDIO_CONTENT, encoding=speech.Encoding.FLAC, - sample_rate_hertz=self.SAMPLE_RATE) - self.assertEqual(content_sample.content, self.AUDIO_CONTENT) - self.assertEqual(content_sample.sample_rate_hertz, self.SAMPLE_RATE) - self.assertEqual(content_sample.encoding, speech.Encoding.FLAC) - - def test_sync_recognize_content_with_optional_params_no_gax(self): - from base64 import b64encode - - from google.cloud._helpers import _bytes_to_unicode - - from google.cloud import speech - from google.cloud.speech.alternative import Alternative - from google.cloud.speech.result import Result - from tests.unit._fixtures import SYNC_RECOGNIZE_RESPONSE - - _b64_audio_content = _bytes_to_unicode(b64encode(self.AUDIO_CONTENT)) - request = { - 'config': { - 'encoding': 'FLAC', - 'maxAlternatives': 2, - 'sampleRateHertz': 16000, - 'speechContexts': { - 'phrases': [ - 'hi', - ] - }, - 'languageCode': 'EN', - 'profanityFilter': True, - }, - 'audio': { - 'content': _b64_audio_content, - } - } - credentials = _make_credentials() - client = self._make_one(credentials=credentials, _use_grpc=False) - speech_api = client.speech_api - connection = _Connection(SYNC_RECOGNIZE_RESPONSE) - speech_api._connection = connection - - encoding = speech.Encoding.FLAC - - sample = client.sample( - content=self.AUDIO_CONTENT, encoding=encoding, - sample_rate_hertz=self.SAMPLE_RATE) - - response = sample.recognize( - language_code='EN', max_alternatives=2, profanity_filter=True, - speech_contexts=self.HINTS) - - self.assertEqual(len(connection._requested), 1) - req = connection._requested[0] - self.assertEqual(len(req), 3) - self.assertEqual(req['data'], request) - self.assertEqual(req['method'], 'POST') - self.assertEqual(req['path'], 'speech:recognize') - - alternative = SYNC_RECOGNIZE_RESPONSE['results'][0]['alternatives'][0] - expected = Alternative.from_api_repr(alternative) - self.assertEqual(len(response), 1) - result = response[0] - self.assertIsInstance(result, Result) - self.assertEqual(len(result.alternatives), 1) - alternative = result.alternatives[0] - self.assertEqual(alternative.transcript, expected.transcript) - self.assertEqual(alternative.confidence, expected.confidence) - - def test_sync_recognize_source_uri_without_optional_params_no_gax(self): - from google.cloud import speech - from google.cloud.speech.alternative import Alternative - from google.cloud.speech.result import Result - from tests.unit._fixtures import SYNC_RECOGNIZE_RESPONSE - - request = { - 'config': { - 'encoding': 'FLAC', - 'languageCode': 'en-US', - 'sampleRateHertz': 16000, - }, - 'audio': { - 'uri': self.AUDIO_SOURCE_URI, - }, - } - credentials = _make_credentials() - client = self._make_one(credentials=credentials, _use_grpc=False) - speech_api = client.speech_api - connection = _Connection(SYNC_RECOGNIZE_RESPONSE) - speech_api._connection = connection - - encoding = speech.Encoding.FLAC - - sample = client.sample( - source_uri=self.AUDIO_SOURCE_URI, encoding=encoding, - sample_rate_hertz=self.SAMPLE_RATE) - - response = [i for i in sample.recognize(language_code='en-US')] - - self.assertEqual(len(connection._requested), 1) - req = connection._requested[0] - self.assertEqual(len(req), 3) - self.assertEqual(req['data'], request) - self.assertEqual(req['method'], 'POST') - self.assertEqual(req['path'], 'speech:recognize') - - expected = Alternative.from_api_repr( - SYNC_RECOGNIZE_RESPONSE['results'][0]['alternatives'][0]) - self.assertEqual(len(response), 1) - - result = response[0] - self.assertIsInstance(result, Result) - self.assertEqual(len(result.alternatives), 1) - - alternative = result.alternatives[0] - self.assertEqual(alternative.transcript, expected.transcript) - self.assertEqual(alternative.confidence, expected.confidence) - - def test_sync_recognize_with_empty_results_no_gax(self): - from google.cloud import speech - from tests.unit._fixtures import SYNC_RECOGNIZE_EMPTY_RESPONSE - - credentials = _make_credentials() - client = self._make_one(credentials=credentials, _use_grpc=False) - speech_api = client.speech_api - speech_api._connection = _Connection(SYNC_RECOGNIZE_EMPTY_RESPONSE) - - sample = client.sample( - source_uri=self.AUDIO_SOURCE_URI, encoding=speech.Encoding.FLAC, - sample_rate_hertz=self.SAMPLE_RATE) - - with self.assertRaises(ValueError): - next(sample.recognize(language_code='en-US')) - - def test_sync_recognize_with_empty_results_gax(self): - from google.cloud import _helpers - from google.cloud._testing import _Monkey - - from google.cloud import speech - from google.cloud.speech import _gax - - credentials = _make_credentials() - client = self._make_one(credentials=credentials, _use_grpc=True) - client._credentials = credentials - - def speech_api(channel=None, **kwargs): - return _MockGAPICSpeechAPI( - response=_make_sync_response(), channel=channel, **kwargs) - - host = 'foo.apis.invalid' - speech_api.SERVICE_ADDRESS = host - - with _Monkey(_gax, SpeechClient=speech_api): - with mock.patch.object(_helpers, 'make_secure_channel') as msc: - client._speech_api = _gax.GAPICSpeechAPI(client) - - low_level = client.speech_api._gapic_api - self.assertIsInstance(low_level, _MockGAPICSpeechAPI) - self.assertIs(low_level._channel, msc.return_value) - - assert msc.mock_calls[0] == mock.call( - credentials, - _gax.DEFAULT_USER_AGENT, - host, - ) - - sample = client.sample( - source_uri=self.AUDIO_SOURCE_URI, encoding=speech.Encoding.FLAC, - sample_rate_hertz=self.SAMPLE_RATE) - - with self.assertRaises(ValueError): - next(sample.recognize(language_code='en-US')) - - def test_sync_recognize_with_gax(self): - from google.cloud import _helpers - from google.cloud._testing import _Monkey - - from google.cloud import speech - from google.cloud.speech import _gax - - creds = _make_credentials() - client = self._make_one(credentials=creds, _use_grpc=True) - client._credentials = creds - - alternatives = [{ - 'transcript': 'testing 1 2 3', - 'confidence': 0.740234375, - }, { - 'transcript': 'testing 4 5 6', - 'confidence': 0.6396484375, - }] - result = _make_result(alternatives) - - def speech_api(channel=None, **kwargs): - return _MockGAPICSpeechAPI( - response=_make_sync_response(result), channel=channel, - **kwargs) - - host = 'foo.apis.invalid' - speech_api.SERVICE_ADDRESS = host - - sample = client.sample( - source_uri=self.AUDIO_SOURCE_URI, encoding=speech.Encoding.FLAC, - sample_rate_hertz=self.SAMPLE_RATE) - - with _Monkey(_gax, SpeechClient=speech_api): - with mock.patch.object(_helpers, 'make_secure_channel') as msc: - client._speech_api = _gax.GAPICSpeechAPI(client) - - low_level = client.speech_api._gapic_api - self.assertIsInstance(low_level, _MockGAPICSpeechAPI) - self.assertIs(low_level._channel, msc.return_value) - - assert msc.mock_calls[0] == mock.call( - creds, - _gax.DEFAULT_USER_AGENT, - host, - ) - - results = [i for i in sample.recognize(language_code='en-US')] - - self.assertEqual(len(results), 1) - result = results[0] - self.assertEqual(len(results[0].alternatives), 2) - self.assertEqual( - result.transcript, result.alternatives[0].transcript, - alternatives[0]['transcript']) - self.assertEqual( - result.confidence, result.alternatives[0].confidence, - alternatives[0]['confidence']) - self.assertEqual( - result.alternatives[1].transcript, alternatives[1]['transcript']) - self.assertEqual( - result.alternatives[1].confidence, alternatives[1]['confidence']) - - def test_async_recognize_no_gax(self): - from google.cloud import speech - from google.cloud.speech.operation import Operation - from tests.unit._fixtures import ASYNC_RECOGNIZE_RESPONSE - - RETURNED = ASYNC_RECOGNIZE_RESPONSE - - credentials = _make_credentials() - client = self._make_one(credentials=credentials, _use_grpc=False) - speech_api = client.speech_api - speech_api._connection = _Connection(RETURNED) - - sample = client.sample( - encoding=speech.Encoding.LINEAR16, - sample_rate_hertz=self.SAMPLE_RATE, - source_uri=self.AUDIO_SOURCE_URI, - ) - operation = sample.long_running_recognize(language_code='en-US') - self.assertIsInstance(operation, Operation) - self.assertIs(operation.client, client) - self.assertEqual(operation.caller_metadata, { - 'request_type': 'LongRunningRecognize', - }) - self.assertFalse(operation.complete) - self.assertIsNone(operation.metadata) - - def test_async_recognize_with_gax(self): - from google.cloud._testing import _Monkey - - from google.cloud import _helpers - from google.cloud import speech - from google.cloud.speech import _gax - from google.cloud.speech.operation import Operation - - credentials = _make_credentials() - client = self._make_one(credentials=credentials, _use_grpc=True) - client._credentials = credentials - - sample = client.sample( - encoding=speech.Encoding.LINEAR16, - sample_rate_hertz=self.SAMPLE_RATE, - source_uri=self.AUDIO_SOURCE_URI, - ) - - def speech_api(channel=None, **kwargs): - return _MockGAPICSpeechAPI(channel=channel, **kwargs) - speech_api.SERVICE_ADDRESS = 'foo.api.invalid' - - with _Monkey(_gax, SpeechClient=speech_api): - with mock.patch.object(_helpers, 'make_secure_channel') as msc: - api = client.speech_api - - low_level = api._gapic_api - self.assertIsInstance(low_level, _MockGAPICSpeechAPI) - self.assertIs(low_level._channel, msc.return_value) - - assert msc.mock_calls[0] == mock.call( - credentials, - _gax.DEFAULT_USER_AGENT, - 'foo.api.invalid', - ) - - operation = sample.long_running_recognize(language_code='en-US') - self.assertIsInstance(operation, Operation) - self.assertFalse(operation.complete) - self.assertIsNone(operation.response) - - def test_streaming_depends_on_gax(self): - from google.cloud import speech - - credentials = _make_credentials() - client = self._make_one(credentials=credentials, _use_grpc=False) - sample = client.sample( - content=self.AUDIO_CONTENT, encoding=speech.Encoding.LINEAR16, - sample_rate_hertz=self.SAMPLE_RATE) - - with self.assertRaises(EnvironmentError): - list(sample.streaming_recognize(language_code='en-US')) - - def test_streaming_closed_stream(self): - from io import BytesIO - - from google.cloud import _helpers - from google.cloud._testing import _Monkey - - from google.cloud.speech import _gax - from google.cloud.speech.encoding import Encoding - - stream = BytesIO(b'Some audio data...') - credentials = _make_credentials() - client = self._make_one(credentials=credentials) - client._credentials = credentials - - def speech_api(channel=None, **kwargs): - return _MockGAPICSpeechAPI(channel=channel, **kwargs) - - host = 'foo.apis.invalid' - speech_api.SERVICE_ADDRESS = host - - stream.close() - self.assertTrue(stream.closed) - - sample = client.sample( - stream=stream, encoding=Encoding.LINEAR16, - sample_rate_hertz=self.SAMPLE_RATE) - - with _Monkey(_gax, SpeechClient=speech_api): - with mock.patch.object(_helpers, 'make_secure_channel') as msc: - client._speech_api = _gax.GAPICSpeechAPI(client) - - with self.assertRaises(ValueError): - list(sample.streaming_recognize(language_code='en-US')) - - def test_stream_recognize_interim_results(self): - from io import BytesIO - - from google.cloud import _helpers - from google.cloud._testing import _Monkey - - from google.cloud.speech import _gax - from google.cloud.speech.encoding import Encoding - from google.cloud.speech.result import StreamingSpeechResult - - stream = BytesIO(b'Some audio data...') - credentials = _make_credentials() - client = self._make_one(credentials=credentials) - client._credentials = credentials - - alternatives = [{ - 'transcript': 'testing streaming 1 2 3', - 'confidence': 0.5888671875, - }, { - 'transcript': 'testing streaming 4 5 6', - 'confidence': 0.28125, - }] - first_response = _make_streaming_response( - _make_streaming_result([], is_final=False, stability=0.314453125)) - second_response = _make_streaming_response( - _make_streaming_result( - alternatives, is_final=False, stability=0.28125)) - last_response = _make_streaming_response( - _make_streaming_result( - alternatives, is_final=True, stability=0.4375)) - responses = [first_response, second_response, last_response] - - def speech_api(channel=None, **kwargs): - return _MockGAPICSpeechAPI( - channel=channel, response=responses, **kwargs) - - host = 'foo.apis.invalid' - speech_api.SERVICE_ADDRESS = host - - with _Monkey(_gax, SpeechClient=speech_api): - with mock.patch.object(_helpers, 'make_secure_channel') as msc: - client._speech_api = _gax.GAPICSpeechAPI(client) - - sample = client.sample( - stream=stream, encoding=Encoding.LINEAR16, - sample_rate_hertz=self.SAMPLE_RATE) - - results = list(sample.streaming_recognize( - interim_results=True, - language_code='en-US', - )) - - self.assertEqual(len(results), 3) - for result in results: - self.assertIsInstance(result, StreamingSpeechResult) - - result = results[0] - self.assertEqual(result.alternatives, []) - self.assertFalse(result.is_final) - self.assertEqual(result.stability, 0.314453125) - - result_two = results[1] - self.assertEqual(result_two.stability, 0.28125) - self.assertFalse(result_two.is_final) - self.assertEqual( - result_two.transcript, result_two.alternatives[0].transcript, - alternatives[0]['transcript']) - self.assertEqual( - result_two.confidence, result_two.alternatives[0].confidence, - alternatives[0]['confidence']) - self.assertEqual( - result_two.alternatives[1].transcript, - alternatives[1]['transcript']) - self.assertEqual( - result_two.alternatives[1].confidence, - alternatives[1]['confidence']) - result_three = results[2] - self.assertTrue(result_three.is_final) - self.assertEqual(result_three.stability, 0.4375) - self.assertEqual( - result_three.transcript, result_three.alternatives[0].transcript, - alternatives[0]['transcript']) - self.assertEqual( - result_three.confidence, result_three.alternatives[0].confidence, - alternatives[0]['confidence']) - - def test_stream_recognize(self): - from io import BytesIO - - from google.cloud import _helpers - from google.cloud._testing import _Monkey - - from google.cloud.speech import _gax - from google.cloud.speech.encoding import Encoding - - stream = BytesIO(b'Some audio data...') - credentials = _make_credentials() - client = self._make_one(credentials=credentials) - client._credentials = credentials - - alternatives = [{ - 'transcript': 'testing streaming 1 2 3', - 'confidence': 0.4375, - }, { - 'transcript': 'testing streaming 4 5 6', - 'confidence': 0.84375, - }] - - first_response = _make_streaming_response( - _make_streaming_result(alternatives=alternatives, is_final=False)) - last_response = _make_streaming_response( - _make_streaming_result(alternatives=alternatives, is_final=True)) - responses = [first_response, last_response] - - channel_args = [] - channel_obj = object() - - def speech_api(channel=None, **kwargs): - return _MockGAPICSpeechAPI( - channel=channel, response=responses, **kwargs) - - host = 'foo.apis.invalid' - speech_api.SERVICE_ADDRESS = host - - with _Monkey(_gax, SpeechClient=speech_api): - with mock.patch.object(_helpers, 'make_secure_channel') as msc: - client._speech_api = _gax.GAPICSpeechAPI(client) - - sample = client.sample( - stream=stream, encoding=Encoding.LINEAR16, - sample_rate_hertz=self.SAMPLE_RATE) - - results = list(sample.streaming_recognize(language_code='en-US')) - self.assertEqual(len(results), 1) - result = results[0] - self.assertEqual( - result.alternatives[0].transcript, alternatives[0]['transcript']) - self.assertEqual( - result.alternatives[0].confidence, alternatives[0]['confidence']) - - def test_stream_recognize_no_results(self): - from io import BytesIO - - from google.cloud import _helpers - from google.cloud._testing import _Monkey - - from google.cloud.speech import _gax - from google.cloud.speech.encoding import Encoding - - stream = BytesIO(b'Some audio data...') - credentials = _make_credentials() - client = self._make_one(credentials=credentials) - client._credentials = credentials - - responses = [_make_streaming_response()] - - def speech_api(channel=None, **kwargs): - return _MockGAPICSpeechAPI( - channel=channel, response=responses, **kwargs) - - host = 'foo.apis.invalid' - speech_api.SERVICE_ADDRESS = host - - with _Monkey(_gax, SpeechClient=speech_api): - with mock.patch.object(_helpers, 'make_secure_channel') as msc: - client._speech_api = _gax.GAPICSpeechAPI(client) - - sample = client.sample( - stream=stream, encoding=Encoding.LINEAR16, - sample_rate_hertz=self.SAMPLE_RATE) - - results = list(sample.streaming_recognize(language_code='en-US')) - self.assertEqual(results, []) - - def test_speech_api_with_gax(self): - from google.cloud import _helpers - from google.cloud._testing import _Monkey - - from google.cloud.speech import _gax - - creds = _make_credentials() - client = self._make_one(credentials=creds, _use_grpc=True) - client._credentials = creds - - def speech_api(channel=None, **kwargs): - return _MockGAPICSpeechAPI(channel=channel, **kwargs) - - host = 'foo.apis.invalid' - speech_api.SERVICE_ADDRESS = host - - with _Monkey(_gax, SpeechClient=speech_api): - with mock.patch.object(_helpers, 'make_secure_channel') as msc: - client._speech_api = _gax.GAPICSpeechAPI(client) - - low_level = client.speech_api._gapic_api - self.assertIsInstance(low_level, _MockGAPICSpeechAPI) - self.assertIs(low_level._channel, msc.return_value) - - assert msc.mock_calls[0] == mock.call( - creds, - _gax.DEFAULT_USER_AGENT, - low_level.SERVICE_ADDRESS, - ) - - def test_speech_api_without_gax(self): - from google.cloud._http import Connection - from google.cloud.speech._http import HTTPSpeechAPI - - creds = _make_credentials() - client = self._make_one(credentials=creds, _use_grpc=False) - self.assertIsNone(client._speech_api) - self.assertIsInstance(client.speech_api, HTTPSpeechAPI) - self.assertIsInstance(client.speech_api._connection, Connection) - - def test_speech_api_preset(self): - creds = _make_credentials() - client = self._make_one(credentials=creds) - fake_api = object() - client._speech_api = fake_api - - self.assertIs(client.speech_api, fake_api) - - -class _MockGAPICSpeechAPI(object): - _requests = None - _response = None - _results = None - - SERVICE_ADDRESS = 'foo.apis.invalid' - - def __init__(self, response=None, channel=None, **kwargs): - self._response = response - self._channel = channel - self._kwargs = kwargs - - def long_running_recognize(self, config, audio): - from google.gapic.longrunning.operations_client import OperationsClient - from google.gax import _OperationFuture - from google.longrunning.operations_pb2 import Operation - from google.cloud.proto.speech.v1.cloud_speech_pb2 import ( - LongRunningRecognizeResponse) - - self.config = config - self.audio = audio - operations_client = mock.Mock(spec=OperationsClient) - operation_future = _OperationFuture( - Operation(), operations_client, LongRunningRecognizeResponse, {}) - return operation_future - - def recognize(self, config, audio): - self.config = config - self.audio = audio - - return self._response - - def streaming_recognize(self, requests): - self._requests = requests - for response in self._response: - yield response - - -class _Connection(object): - - def __init__(self, *responses): - self._responses = responses - self._requested = [] - - def api_request(self, **kw): - self._requested.append(kw) - response, self._responses = self._responses[0], self._responses[1:] - return response diff --git a/speech/tests/unit/test_operation.py b/speech/tests/unit/test_operation.py deleted file mode 100644 index 7c4071089b7e..000000000000 --- a/speech/tests/unit/test_operation.py +++ /dev/null @@ -1,132 +0,0 @@ -# Copyright 2016 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 unittest - - -class TestOperation(unittest.TestCase): - - OPERATION_NAME = '123456789' - - @staticmethod - def _get_target_class(): - from google.cloud.speech.operation import Operation - - return Operation - - def _make_one(self, *args, **kwargs): - return self._get_target_class()(*args, **kwargs) - - def test_constructor(self): - client = object() - operation = self._make_one( - self.OPERATION_NAME, client) - self.assertEqual(operation.name, self.OPERATION_NAME) - self.assertIs(operation.client, client) - self.assertIsNone(operation.target) - self.assertIsNone(operation.response) - self.assertIsNone(operation.results) - self.assertIsNone(operation.error) - self.assertIsNone(operation.metadata) - self.assertEqual(operation.caller_metadata, {}) - self.assertTrue(operation._from_grpc) - - @staticmethod - def _make_result(transcript, confidence): - from google.cloud.proto.speech.v1 import cloud_speech_pb2 - - return cloud_speech_pb2.SpeechRecognitionResult( - alternatives=[ - cloud_speech_pb2.SpeechRecognitionAlternative( - transcript=transcript, - confidence=confidence, - ), - ], - ) - - def _make_operation_pb(self, *results): - from google.cloud.proto.speech.v1 import cloud_speech_pb2 - from google.longrunning import operations_pb2 - from google.protobuf.any_pb2 import Any - - any_pb = None - if results: - result_pb = cloud_speech_pb2.LongRunningRecognizeResponse( - results=results, - ) - type_url = 'type.googleapis.com/%s' % ( - result_pb.DESCRIPTOR.full_name,) - any_pb = Any( - type_url=type_url, value=result_pb.SerializeToString()) - - return operations_pb2.Operation( - name=self.OPERATION_NAME, response=any_pb) - - def test__update_state_no_response(self): - client = object() - operation = self._make_one( - self.OPERATION_NAME, client) - - operation_pb = self._make_operation_pb() - operation._update_state(operation_pb) - self.assertIsNone(operation.response) - self.assertIsNone(operation.results) - - def test__update_state_with_response(self): - from google.cloud.speech.alternative import Alternative - from google.cloud.speech.result import Result - - client = object() - operation = self._make_one( - self.OPERATION_NAME, client) - - results = [ - self._make_result('hi mom', 0.75), - self._make_result('hi dad', 0.75), - ] - operation_pb = self._make_operation_pb(*results) - operation._update_state(operation_pb) - self.assertIsNotNone(operation.response) - - self.assertEqual(len(operation.results), 2) - for result, text in zip(operation.results, ['hi mom', 'hi dad']): - self.assertIsInstance(result, Result) - self.assertEqual(result.transcript, text) - self.assertEqual(result.confidence, 0.75) - self.assertIsInstance(result.alternatives, list) - self.assertIsInstance(result.alternatives[0], Alternative) - - def test__update_state_with_empty_response(self): - from google.cloud.proto.speech.v1 import cloud_speech_pb2 - from google.longrunning import operations_pb2 - from google.protobuf.any_pb2 import Any - - # Simulate an empty response (rather than no response yet, which - # is distinct). - response = cloud_speech_pb2.LongRunningRecognizeResponse(results=[]) - type_url = 'type.googleapis.com/%s' % response.DESCRIPTOR.full_name - any_pb = Any( - type_url=type_url, - value=response.SerializeToString(), - ) - operation_pb = operations_pb2.Operation( - name=self.OPERATION_NAME, - response=any_pb, - ) - - # Establish that we raise ValueError at state update time. - client = object() - operation = self._make_one(self.OPERATION_NAME, client) - with self.assertRaises(ValueError): - operation._update_state(operation_pb) diff --git a/speech/tests/unit/test_result.py b/speech/tests/unit/test_result.py deleted file mode 100644 index b3d38fe7f800..000000000000 --- a/speech/tests/unit/test_result.py +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2017 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 unittest - - -class TestResult(unittest.TestCase): - @staticmethod - def _get_target_class(): - from google.cloud.speech.result import Result - - return Result - - def _make_one(self, *args, **kw): - return self._get_target_class()(*args, **kw) - - def test_ctor(self): - result = self._make_one([]) - self.assertIsInstance(result, self._get_target_class()) - - def test_from_pb(self): - from google.cloud.proto.speech.v1 import cloud_speech_pb2 - - confidence = 0.625 - transcript = 'this is a test transcript' - alternative = cloud_speech_pb2.SpeechRecognitionAlternative( - transcript=transcript, confidence=confidence) - result_pb = cloud_speech_pb2.SpeechRecognitionResult( - alternatives=[alternative]) - - result = self._get_target_class().from_pb(result_pb) - self.assertEqual(result.confidence, confidence) - self.assertEqual(result.transcript, transcript) - - def test_from_api_repr(self): - confidence = 0.625 - transcript = 'this is a test' - response = { - 'alternatives': [ - { - 'confidence': confidence, - 'transcript': transcript, - }, - ], - } - - result = self._get_target_class().from_api_repr(response) - self.assertEqual(result.confidence, confidence) - self.assertEqual(result.transcript, transcript) diff --git a/speech/tests/unit/test_sample.py b/speech/tests/unit/test_sample.py deleted file mode 100644 index b7fbe36f7dcd..000000000000 --- a/speech/tests/unit/test_sample.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright 2016 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 unittest - - -class TestSample(unittest.TestCase): - SAMPLE_RATE = 16000 - AUDIO_SOURCE_URI = 'gs://sample-bucket/sample-recording.flac' - - @staticmethod - def _get_target_class(): - from google.cloud.speech.sample import Sample - - return Sample - - def _make_one(self, *args, **kw): - return self._get_target_class()(*args, **kw) - - def test_initialize_sample(self): - from google.cloud.speech.encoding import Encoding - - sample = self._make_one( - source_uri=self.AUDIO_SOURCE_URI, encoding=Encoding.FLAC, - sample_rate_hertz=self.SAMPLE_RATE) - self.assertEqual(sample.source_uri, self.AUDIO_SOURCE_URI) - self.assertEqual(sample.encoding, Encoding.FLAC) - self.assertEqual(sample.sample_rate_hertz, self.SAMPLE_RATE) - - def test_content_and_source_uri(self): - from io import BytesIO - - with self.assertRaises(ValueError): - self._make_one( - content='awefawagaeragere', source_uri=self.AUDIO_SOURCE_URI) - - with self.assertRaises(ValueError): - self._make_one( - stream=BytesIO(b'awefawagaeragere'), - source_uri=self.AUDIO_SOURCE_URI) - - with self.assertRaises(ValueError): - self._make_one( - content='awefawagaeragere', - stream=BytesIO(b'awefawagaeragere'), - source_uri=self.AUDIO_SOURCE_URI) - - def test_stream_property(self): - from io import BytesIO - from google.cloud.speech.encoding import Encoding - - data = b'abc 1 2 3 4' - stream = BytesIO(data) - sample = self._make_one( - stream=stream, encoding=Encoding.FLAC, - sample_rate_hertz=self.SAMPLE_RATE) - self.assertEqual(sample.stream, stream) - self.assertEqual(sample.stream.read(), data) - - def test_bytes_converts_to_file_like_object(self): - from google.cloud import speech - from google.cloud.speech.sample import Sample - - test_bytes = b'testing 1 2 3' - - sample = Sample( - content=test_bytes, encoding=speech.Encoding.FLAC, - sample_rate_hertz=self.SAMPLE_RATE) - self.assertEqual(sample.content, test_bytes) - self.assertEqual(sample.encoding, speech.Encoding.FLAC) - self.assertEqual(sample.sample_rate_hertz, self.SAMPLE_RATE) - - def test_sample_rates(self): - from google.cloud.speech.encoding import Encoding - - sample = self._make_one( - encoding=Encoding.FLAC, - sample_rate_hertz=self.SAMPLE_RATE, - source_uri=self.AUDIO_SOURCE_URI, - ) - self.assertEqual(sample.sample_rate_hertz, self.SAMPLE_RATE) - self.assertEqual(sample.encoding, Encoding.FLAC) - - def test_encoding(self): - from google.cloud.speech.encoding import Encoding - - with self.assertRaises(ValueError): - self._make_one( - encoding='OGG', - sample_rate_hertz=self.SAMPLE_RATE, - source_uri=self.AUDIO_SOURCE_URI, - ) - with self.assertRaises(ValueError): - self._make_one( - sample_rate_hertz=self.SAMPLE_RATE, - source_uri=self.AUDIO_SOURCE_URI, - ) - sample = self._make_one( - encoding=Encoding.FLAC, - sample_rate_hertz=self.SAMPLE_RATE, - source_uri=self.AUDIO_SOURCE_URI, - ) - self.assertEqual(sample.encoding, Encoding.FLAC)