1# -*- coding: utf-8 -*-
2# Copyright 2020 Google LLC
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#     http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16from collections import OrderedDict
17import functools
18import re
19from typing import (
20    Dict,
21    AsyncIterable,
22    Awaitable,
23    AsyncIterator,
24    Sequence,
25    Tuple,
26    Type,
27    Union,
28)
29import pkg_resources
30
31from google.api_core.client_options import ClientOptions  # type: ignore
32from google.api_core import exceptions as core_exceptions  # type: ignore
33from google.api_core import gapic_v1  # type: ignore
34from google.api_core import retry as retries  # type: ignore
35from google.auth import credentials as ga_credentials  # type: ignore
36from google.oauth2 import service_account  # type: ignore
37
38OptionalRetry = Union[retries.Retry, object]
39
40from google.api_core import operation  # type: ignore
41from google.api_core import operation_async  # type: ignore
42from google.cloud.speech_v1p1beta1.types import cloud_speech
43from google.protobuf import duration_pb2  # type: ignore
44from google.rpc import status_pb2  # type: ignore
45from .transports.base import SpeechTransport, DEFAULT_CLIENT_INFO
46from .transports.grpc_asyncio import SpeechGrpcAsyncIOTransport
47from .client import SpeechClient
48
49
50class SpeechAsyncClient:
51    """Service that implements Google Cloud Speech API."""
52
53    _client: SpeechClient
54
55    DEFAULT_ENDPOINT = SpeechClient.DEFAULT_ENDPOINT
56    DEFAULT_MTLS_ENDPOINT = SpeechClient.DEFAULT_MTLS_ENDPOINT
57
58    custom_class_path = staticmethod(SpeechClient.custom_class_path)
59    parse_custom_class_path = staticmethod(SpeechClient.parse_custom_class_path)
60    phrase_set_path = staticmethod(SpeechClient.phrase_set_path)
61    parse_phrase_set_path = staticmethod(SpeechClient.parse_phrase_set_path)
62    common_billing_account_path = staticmethod(SpeechClient.common_billing_account_path)
63    parse_common_billing_account_path = staticmethod(
64        SpeechClient.parse_common_billing_account_path
65    )
66    common_folder_path = staticmethod(SpeechClient.common_folder_path)
67    parse_common_folder_path = staticmethod(SpeechClient.parse_common_folder_path)
68    common_organization_path = staticmethod(SpeechClient.common_organization_path)
69    parse_common_organization_path = staticmethod(
70        SpeechClient.parse_common_organization_path
71    )
72    common_project_path = staticmethod(SpeechClient.common_project_path)
73    parse_common_project_path = staticmethod(SpeechClient.parse_common_project_path)
74    common_location_path = staticmethod(SpeechClient.common_location_path)
75    parse_common_location_path = staticmethod(SpeechClient.parse_common_location_path)
76
77    @classmethod
78    def from_service_account_info(cls, info: dict, *args, **kwargs):
79        """Creates an instance of this client using the provided credentials
80            info.
81
82        Args:
83            info (dict): The service account private key info.
84            args: Additional arguments to pass to the constructor.
85            kwargs: Additional arguments to pass to the constructor.
86
87        Returns:
88            SpeechAsyncClient: The constructed client.
89        """
90        return SpeechClient.from_service_account_info.__func__(SpeechAsyncClient, info, *args, **kwargs)  # type: ignore
91
92    @classmethod
93    def from_service_account_file(cls, filename: str, *args, **kwargs):
94        """Creates an instance of this client using the provided credentials
95            file.
96
97        Args:
98            filename (str): The path to the service account private key json
99                file.
100            args: Additional arguments to pass to the constructor.
101            kwargs: Additional arguments to pass to the constructor.
102
103        Returns:
104            SpeechAsyncClient: The constructed client.
105        """
106        return SpeechClient.from_service_account_file.__func__(SpeechAsyncClient, filename, *args, **kwargs)  # type: ignore
107
108    from_service_account_json = from_service_account_file
109
110    @property
111    def transport(self) -> SpeechTransport:
112        """Returns the transport used by the client instance.
113
114        Returns:
115            SpeechTransport: The transport used by the client instance.
116        """
117        return self._client.transport
118
119    get_transport_class = functools.partial(
120        type(SpeechClient).get_transport_class, type(SpeechClient)
121    )
122
123    def __init__(
124        self,
125        *,
126        credentials: ga_credentials.Credentials = None,
127        transport: Union[str, SpeechTransport] = "grpc_asyncio",
128        client_options: ClientOptions = None,
129        client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
130    ) -> None:
131        """Instantiates the speech client.
132
133        Args:
134            credentials (Optional[google.auth.credentials.Credentials]): The
135                authorization credentials to attach to requests. These
136                credentials identify the application to the service; if none
137                are specified, the client will attempt to ascertain the
138                credentials from the environment.
139            transport (Union[str, ~.SpeechTransport]): The
140                transport to use. If set to None, a transport is chosen
141                automatically.
142            client_options (ClientOptions): Custom options for the client. It
143                won't take effect if a ``transport`` instance is provided.
144                (1) The ``api_endpoint`` property can be used to override the
145                default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT
146                environment variable can also be used to override the endpoint:
147                "always" (always use the default mTLS endpoint), "never" (always
148                use the default regular endpoint) and "auto" (auto switch to the
149                default mTLS endpoint if client certificate is present, this is
150                the default value). However, the ``api_endpoint`` property takes
151                precedence if provided.
152                (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable
153                is "true", then the ``client_cert_source`` property can be used
154                to provide client certificate for mutual TLS transport. If
155                not provided, the default SSL client certificate will be used if
156                present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not
157                set, no client certificate will be used.
158
159        Raises:
160            google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport
161                creation failed for any reason.
162        """
163        self._client = SpeechClient(
164            credentials=credentials,
165            transport=transport,
166            client_options=client_options,
167            client_info=client_info,
168        )
169
170    async def recognize(
171        self,
172        request: Union[cloud_speech.RecognizeRequest, dict] = None,
173        *,
174        config: cloud_speech.RecognitionConfig = None,
175        audio: cloud_speech.RecognitionAudio = None,
176        retry: OptionalRetry = gapic_v1.method.DEFAULT,
177        timeout: float = None,
178        metadata: Sequence[Tuple[str, str]] = (),
179    ) -> cloud_speech.RecognizeResponse:
180        r"""Performs synchronous speech recognition: receive
181        results after all audio has been sent and processed.
182
183        Args:
184            request (Union[google.cloud.speech_v1p1beta1.types.RecognizeRequest, dict]):
185                The request object. The top-level message sent by the
186                client for the `Recognize` method.
187            config (:class:`google.cloud.speech_v1p1beta1.types.RecognitionConfig`):
188                Required. Provides information to the
189                recognizer that specifies how to process
190                the request.
191
192                This corresponds to the ``config`` field
193                on the ``request`` instance; if ``request`` is provided, this
194                should not be set.
195            audio (:class:`google.cloud.speech_v1p1beta1.types.RecognitionAudio`):
196                Required. The audio data to be
197                recognized.
198
199                This corresponds to the ``audio`` field
200                on the ``request`` instance; if ``request`` is provided, this
201                should not be set.
202            retry (google.api_core.retry.Retry): Designation of what errors, if any,
203                should be retried.
204            timeout (float): The timeout for this request.
205            metadata (Sequence[Tuple[str, str]]): Strings which should be
206                sent along with the request as metadata.
207
208        Returns:
209            google.cloud.speech_v1p1beta1.types.RecognizeResponse:
210                The only message returned to the client by the Recognize method. It
211                   contains the result as zero or more sequential
212                   SpeechRecognitionResult messages.
213
214        """
215        # Create or coerce a protobuf request object.
216        # Sanity check: If we got a request object, we should *not* have
217        # gotten any keyword arguments that map to the request.
218        has_flattened_params = any([config, audio])
219        if request is not None and has_flattened_params:
220            raise ValueError(
221                "If the `request` argument is set, then none of "
222                "the individual field arguments should be set."
223            )
224
225        request = cloud_speech.RecognizeRequest(request)
226
227        # If we have keyword arguments corresponding to fields on the
228        # request, apply these.
229        if config is not None:
230            request.config = config
231        if audio is not None:
232            request.audio = audio
233
234        # Wrap the RPC method; this adds retry and timeout information,
235        # and friendly error handling.
236        rpc = gapic_v1.method_async.wrap_method(
237            self._client._transport.recognize,
238            default_retry=retries.Retry(
239                initial=0.1,
240                maximum=60.0,
241                multiplier=1.3,
242                predicate=retries.if_exception_type(
243                    core_exceptions.DeadlineExceeded,
244                    core_exceptions.ServiceUnavailable,
245                ),
246                deadline=5000.0,
247            ),
248            default_timeout=5000.0,
249            client_info=DEFAULT_CLIENT_INFO,
250        )
251
252        # Send the request.
253        response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,)
254
255        # Done; return the response.
256        return response
257
258    async def long_running_recognize(
259        self,
260        request: Union[cloud_speech.LongRunningRecognizeRequest, dict] = None,
261        *,
262        config: cloud_speech.RecognitionConfig = None,
263        audio: cloud_speech.RecognitionAudio = None,
264        retry: OptionalRetry = gapic_v1.method.DEFAULT,
265        timeout: float = None,
266        metadata: Sequence[Tuple[str, str]] = (),
267    ) -> operation_async.AsyncOperation:
268        r"""Performs asynchronous speech recognition: receive results via
269        the google.longrunning.Operations interface. Returns either an
270        ``Operation.error`` or an ``Operation.response`` which contains
271        a ``LongRunningRecognizeResponse`` message. For more information
272        on asynchronous speech recognition, see the
273        `how-to <https://cloud.google.com/speech-to-text/docs/async-recognize>`__.
274
275        Args:
276            request (Union[google.cloud.speech_v1p1beta1.types.LongRunningRecognizeRequest, dict]):
277                The request object. The top-level message sent by the
278                client for the `LongRunningRecognize` method.
279            config (:class:`google.cloud.speech_v1p1beta1.types.RecognitionConfig`):
280                Required. Provides information to the
281                recognizer that specifies how to process
282                the request.
283
284                This corresponds to the ``config`` field
285                on the ``request`` instance; if ``request`` is provided, this
286                should not be set.
287            audio (:class:`google.cloud.speech_v1p1beta1.types.RecognitionAudio`):
288                Required. The audio data to be
289                recognized.
290
291                This corresponds to the ``audio`` field
292                on the ``request`` instance; if ``request`` is provided, this
293                should not be set.
294            retry (google.api_core.retry.Retry): Designation of what errors, if any,
295                should be retried.
296            timeout (float): The timeout for this request.
297            metadata (Sequence[Tuple[str, str]]): Strings which should be
298                sent along with the request as metadata.
299
300        Returns:
301            google.api_core.operation_async.AsyncOperation:
302                An object representing a long-running operation.
303
304                The result type for the operation will be :class:`google.cloud.speech_v1p1beta1.types.LongRunningRecognizeResponse` The only message returned to the client by the LongRunningRecognize method.
305                   It contains the result as zero or more sequential
306                   SpeechRecognitionResult messages. It is included in
307                   the result.response field of the Operation returned
308                   by the GetOperation call of the
309                   google::longrunning::Operations service.
310
311        """
312        # Create or coerce a protobuf request object.
313        # Sanity check: If we got a request object, we should *not* have
314        # gotten any keyword arguments that map to the request.
315        has_flattened_params = any([config, audio])
316        if request is not None and has_flattened_params:
317            raise ValueError(
318                "If the `request` argument is set, then none of "
319                "the individual field arguments should be set."
320            )
321
322        request = cloud_speech.LongRunningRecognizeRequest(request)
323
324        # If we have keyword arguments corresponding to fields on the
325        # request, apply these.
326        if config is not None:
327            request.config = config
328        if audio is not None:
329            request.audio = audio
330
331        # Wrap the RPC method; this adds retry and timeout information,
332        # and friendly error handling.
333        rpc = gapic_v1.method_async.wrap_method(
334            self._client._transport.long_running_recognize,
335            default_timeout=5000.0,
336            client_info=DEFAULT_CLIENT_INFO,
337        )
338
339        # Send the request.
340        response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,)
341
342        # Wrap the response in an operation future.
343        response = operation_async.from_gapic(
344            response,
345            self._client._transport.operations_client,
346            cloud_speech.LongRunningRecognizeResponse,
347            metadata_type=cloud_speech.LongRunningRecognizeMetadata,
348        )
349
350        # Done; return the response.
351        return response
352
353    def streaming_recognize(
354        self,
355        requests: AsyncIterator[cloud_speech.StreamingRecognizeRequest] = None,
356        *,
357        retry: OptionalRetry = gapic_v1.method.DEFAULT,
358        timeout: float = None,
359        metadata: Sequence[Tuple[str, str]] = (),
360    ) -> Awaitable[AsyncIterable[cloud_speech.StreamingRecognizeResponse]]:
361        r"""Performs bidirectional streaming speech recognition:
362        receive results while sending audio. This method is only
363        available via the gRPC API (not REST).
364
365        Args:
366            requests (AsyncIterator[`google.cloud.speech_v1p1beta1.types.StreamingRecognizeRequest`]):
367                The request object AsyncIterator. The top-level message sent by the
368                client for the `StreamingRecognize` method. Multiple
369                `StreamingRecognizeRequest` messages are sent. The first
370                message must contain a `streaming_config` message and
371                must not contain `audio_content`. All subsequent
372                messages must contain `audio_content` and must not
373                contain a `streaming_config` message.
374            retry (google.api_core.retry.Retry): Designation of what errors, if any,
375                should be retried.
376            timeout (float): The timeout for this request.
377            metadata (Sequence[Tuple[str, str]]): Strings which should be
378                sent along with the request as metadata.
379
380        Returns:
381            AsyncIterable[google.cloud.speech_v1p1beta1.types.StreamingRecognizeResponse]:
382                StreamingRecognizeResponse is the only message returned to the client by
383                   StreamingRecognize. A series of zero or more
384                   StreamingRecognizeResponse messages are streamed back
385                   to the client. If there is no recognizable audio, and
386                   single_utterance is set to false, then no messages
387                   are streamed back to the client.
388
389                   Here's an example of a series of
390                   StreamingRecognizeResponses that might be returned
391                   while processing audio:
392
393                   1. results { alternatives { transcript: "tube" }
394                      stability: 0.01 }
395                   2. results { alternatives { transcript: "to be a" }
396                      stability: 0.01 }
397                   3. results { alternatives { transcript: "to be" }
398                      stability: 0.9 } results { alternatives {
399                      transcript: " or not to be" } stability: 0.01 }
400                   4.
401
402                      results { alternatives { transcript: "to be or not to be"
403                         confidence: 0.92 }
404
405                      alternatives { transcript: "to bee or not to bee" }
406                         is_final: true }
407
408                   5. results { alternatives { transcript: " that's" }
409                      stability: 0.01 }
410                   6. results { alternatives { transcript: " that is" }
411                      stability: 0.9 } results { alternatives {
412                      transcript: " the question" } stability: 0.01 }
413                   7.
414
415                      results { alternatives { transcript: " that is the question"
416                         confidence: 0.98 }
417
418                      alternatives { transcript: " that was the question" }
419                         is_final: true }
420
421                   Notes:
422
423                   -  Only two of the above responses #4 and #7 contain
424                      final results; they are indicated by
425                      is_final: true. Concatenating these together
426                      generates the full transcript: "to be or not to be
427                      that is the question".
428                   -  The others contain interim results. #3 and #6
429                      contain two interim \`results`: the first portion
430                      has a high stability and is less likely to change;
431                      the second portion has a low stability and is very
432                      likely to change. A UI designer might choose to
433                      show only high stability results.
434                   -  The specific stability and confidence values shown
435                      above are only for illustrative purposes. Actual
436                      values may vary.
437                   -
438
439                      In each response, only one of these fields will be set:
440                         error, speech_event_type, or one or more
441                         (repeated) results.
442
443        """
444
445        # Wrap the RPC method; this adds retry and timeout information,
446        # and friendly error handling.
447        rpc = gapic_v1.method_async.wrap_method(
448            self._client._transport.streaming_recognize,
449            default_retry=retries.Retry(
450                initial=0.1,
451                maximum=60.0,
452                multiplier=1.3,
453                predicate=retries.if_exception_type(
454                    core_exceptions.DeadlineExceeded,
455                    core_exceptions.ServiceUnavailable,
456                ),
457                deadline=5000.0,
458            ),
459            default_timeout=5000.0,
460            client_info=DEFAULT_CLIENT_INFO,
461        )
462
463        # Send the request.
464        response = rpc(requests, retry=retry, timeout=timeout, metadata=metadata,)
465
466        # Done; return the response.
467        return response
468
469    async def __aenter__(self):
470        return self
471
472    async def __aexit__(self, exc_type, exc, tb):
473        await self.transport.close()
474
475
476try:
477    DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo(
478        gapic_version=pkg_resources.get_distribution("google-cloud-speech",).version,
479    )
480except pkg_resources.DistributionNotFound:
481    DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo()
482
483
484__all__ = ("SpeechAsyncClient",)
485