From 59745644b08328c883e71d53f3fcc5537644e3c7 Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Fri, 19 Mar 2021 08:37:31 -0700 Subject: [PATCH] feat: Support output transcript to Google Cloud Storage for LongRunningRecognize (#128) * chore: upgrade gapic-generator-python to 0.42.2 PiperOrigin-RevId: 361662015 Source-Author: Google APIs Source-Date: Mon Mar 8 14:47:18 2021 -0800 Source-Repo: googleapis/googleapis Source-Sha: 28a591963253d52ce3a25a918cafbdd9928de8cf Source-Link: https://github.com/googleapis/googleapis/commit/28a591963253d52ce3a25a918cafbdd9928de8cf * feat: Support output transcript to GCS for LongRunningRecognize. PiperOrigin-RevId: 362294447 Source-Author: Google APIs Source-Date: Thu Mar 11 08:07:37 2021 -0800 Source-Repo: googleapis/googleapis Source-Sha: b6ebac16c3aecb798d4f25443d96df2f42a965ca Source-Link: https://github.com/googleapis/googleapis/commit/b6ebac16c3aecb798d4f25443d96df2f42a965ca * feat: Support output transcript to GCS for LongRunningRecognize. PiperOrigin-RevId: 362934100 Source-Author: Google APIs Source-Date: Mon Mar 15 07:18:03 2021 -0700 Source-Repo: googleapis/googleapis Source-Sha: 72326861be446be27d53af95c87e6e313367c371 Source-Link: https://github.com/googleapis/googleapis/commit/72326861be446be27d53af95c87e6e313367c371 --- google/cloud/speech_v1/types/__init__.py | 44 ++--- google/cloud/speech_v1p1beta1/__init__.py | 6 +- .../speech_v1p1beta1/proto/cloud_speech.proto | 75 +++++--- .../proto/cloud_speech_adaptation.proto | 2 + .../services/adaptation/async_client.py | 67 +++++++ .../services/adaptation/client.py | 67 +++++++ .../cloud/speech_v1p1beta1/types/__init__.py | 90 +++++----- .../speech_v1p1beta1/types/cloud_speech.py | 45 ++++- scripts/fixup_speech_v1p1beta1_keywords.py | 2 +- synth.metadata | 4 +- .../gapic/speech_v1p1beta1/test_adaptation.py | 168 ++++++++++++++++++ 11 files changed, 469 insertions(+), 101 deletions(-) diff --git a/google/cloud/speech_v1/types/__init__.py b/google/cloud/speech_v1/types/__init__.py index 44034960..a08e2564 100644 --- a/google/cloud/speech_v1/types/__init__.py +++ b/google/cloud/speech_v1/types/__init__.py @@ -16,41 +16,41 @@ # from .cloud_speech import ( - RecognizeRequest, + LongRunningRecognizeMetadata, LongRunningRecognizeRequest, - StreamingRecognizeRequest, - StreamingRecognitionConfig, + LongRunningRecognizeResponse, + RecognitionAudio, RecognitionConfig, - SpeakerDiarizationConfig, RecognitionMetadata, - SpeechContext, - RecognitionAudio, + RecognizeRequest, RecognizeResponse, - LongRunningRecognizeResponse, - LongRunningRecognizeMetadata, - StreamingRecognizeResponse, - StreamingRecognitionResult, - SpeechRecognitionResult, + SpeakerDiarizationConfig, + SpeechContext, SpeechRecognitionAlternative, + SpeechRecognitionResult, + StreamingRecognitionConfig, + StreamingRecognitionResult, + StreamingRecognizeRequest, + StreamingRecognizeResponse, WordInfo, ) __all__ = ( - "RecognizeRequest", + "LongRunningRecognizeMetadata", "LongRunningRecognizeRequest", - "StreamingRecognizeRequest", - "StreamingRecognitionConfig", + "LongRunningRecognizeResponse", + "RecognitionAudio", "RecognitionConfig", - "SpeakerDiarizationConfig", "RecognitionMetadata", - "SpeechContext", - "RecognitionAudio", + "RecognizeRequest", "RecognizeResponse", - "LongRunningRecognizeResponse", - "LongRunningRecognizeMetadata", - "StreamingRecognizeResponse", - "StreamingRecognitionResult", - "SpeechRecognitionResult", + "SpeakerDiarizationConfig", + "SpeechContext", "SpeechRecognitionAlternative", + "SpeechRecognitionResult", + "StreamingRecognitionConfig", + "StreamingRecognitionResult", + "StreamingRecognizeRequest", + "StreamingRecognizeResponse", "WordInfo", ) diff --git a/google/cloud/speech_v1p1beta1/__init__.py b/google/cloud/speech_v1p1beta1/__init__.py index 129b8b78..a45dedd4 100644 --- a/google/cloud/speech_v1p1beta1/__init__.py +++ b/google/cloud/speech_v1p1beta1/__init__.py @@ -33,6 +33,7 @@ from .types.cloud_speech import StreamingRecognitionResult from .types.cloud_speech import StreamingRecognizeRequest from .types.cloud_speech import StreamingRecognizeResponse +from .types.cloud_speech import TranscriptOutputConfig from .types.cloud_speech import WordInfo from .types.cloud_speech_adaptation import CreateCustomClassRequest from .types.cloud_speech_adaptation import CreatePhraseSetRequest @@ -59,7 +60,6 @@ class SpeechClient(SpeechHelpers, SpeechClient): __all__ = ( - "AdaptationClient", "CreateCustomClassRequest", "CreatePhraseSetRequest", "CustomClass", @@ -82,6 +82,7 @@ class SpeechClient(SpeechHelpers, SpeechClient): "RecognizeResponse", "SpeakerDiarizationConfig", "SpeechAdaptation", + "SpeechClient", "SpeechContext", "SpeechRecognitionAlternative", "SpeechRecognitionResult", @@ -89,8 +90,9 @@ class SpeechClient(SpeechHelpers, SpeechClient): "StreamingRecognitionResult", "StreamingRecognizeRequest", "StreamingRecognizeResponse", + "TranscriptOutputConfig", "UpdateCustomClassRequest", "UpdatePhraseSetRequest", "WordInfo", - "SpeechClient", + "AdaptationClient", ) diff --git a/google/cloud/speech_v1p1beta1/proto/cloud_speech.proto b/google/cloud/speech_v1p1beta1/proto/cloud_speech.proto index 3eccfb66..9a8e256f 100644 --- a/google/cloud/speech_v1p1beta1/proto/cloud_speech.proto +++ b/google/cloud/speech_v1p1beta1/proto/cloud_speech.proto @@ -19,7 +19,6 @@ package google.cloud.speech.v1p1beta1; import "google/api/annotations.proto"; import "google/api/client.proto"; import "google/api/field_behavior.proto"; -import "google/api/resource.proto"; import "google/cloud/speech/v1p1beta1/resource.proto"; import "google/longrunning/operations.proto"; import "google/protobuf/any.proto"; @@ -37,8 +36,7 @@ option objc_class_prefix = "GCS"; // Service that implements Google Cloud Speech API. service Speech { option (google.api.default_host) = "speech.googleapis.com"; - option (google.api.oauth_scopes) = - "https://www.googleapis.com/auth/cloud-platform"; + option (google.api.oauth_scopes) = "https://www.googleapis.com/auth/cloud-platform"; // Performs synchronous speech recognition: receive results after all audio // has been sent and processed. @@ -56,8 +54,7 @@ service Speech { // a `LongRunningRecognizeResponse` message. // For more information on asynchronous speech recognition, see the // [how-to](https://cloud.google.com/speech-to-text/docs/async-recognize). - rpc LongRunningRecognize(LongRunningRecognizeRequest) - returns (google.longrunning.Operation) { + rpc LongRunningRecognize(LongRunningRecognizeRequest) returns (google.longrunning.Operation) { option (google.api.http) = { post: "/v1p1beta1/speech:longrunningrecognize" body: "*" @@ -71,8 +68,8 @@ service Speech { // Performs bidirectional streaming speech recognition: receive results while // sending audio. This method is only available via the gRPC API (not REST). - rpc StreamingRecognize(stream StreamingRecognizeRequest) - returns (stream StreamingRecognizeResponse) {} + rpc StreamingRecognize(stream StreamingRecognizeRequest) returns (stream StreamingRecognizeResponse) { + } } // The top-level message sent by the client for the `Recognize` method. @@ -94,6 +91,19 @@ message LongRunningRecognizeRequest { // Required. The audio data to be recognized. RecognitionAudio audio = 2 [(google.api.field_behavior) = REQUIRED]; + + // Optional. Specifies an optional destination for the recognition results. + TranscriptOutputConfig output_config = 4 [(google.api.field_behavior) = OPTIONAL]; +} + +// Specifies an optional destination for the recognition results. +message TranscriptOutputConfig { + oneof output_type { + // Specifies a Cloud Storage URI for the recognition results. Must be + // specified in the format: `gs://bucket_name/object_name`, and the bucket + // must already exist. + string gcs_uri = 1; + } } // The top-level message sent by the client for the `StreamingRecognize` method. @@ -171,7 +181,7 @@ message RecognitionConfig { // a lossless encoding (`FLAC` or `LINEAR16`). The accuracy of the speech // recognition can be reduced if lossy codecs are used to capture or transmit // audio, particularly if background noise is present. Lossy codecs include - // `MULAW`, `AMR`, `AMR_WB`, `OGG_OPUS`, `SPEEX_WITH_HEADER_BYTE`, and `MP3`. + // `MULAW`, `AMR`, `AMR_WB`, `OGG_OPUS`, `SPEEX_WITH_HEADER_BYTE`, `MP3`. // // The `FLAC` and `WAV` audio file formats include a header that describes the // included audio content. You can request recognition for `WAV` files that @@ -182,8 +192,7 @@ message RecognitionConfig { // an `AudioEncoding` when you send send `FLAC` or `WAV` audio, the // encoding configuration must match the encoding described in the audio // header; otherwise the request returns an - // [google.rpc.Code.INVALID_ARGUMENT][google.rpc.Code.INVALID_ARGUMENT] error - // code. + // [google.rpc.Code.INVALID_ARGUMENT][google.rpc.Code.INVALID_ARGUMENT] error code. enum AudioEncoding { // Not specified. ENCODING_UNSPECIFIED = 0; @@ -237,8 +246,7 @@ message RecognitionConfig { // Encoding of audio data sent in all `RecognitionAudio` messages. // This field is optional for `FLAC` and `WAV` audio files and required - // for all other audio formats. For details, see - // [AudioEncoding][google.cloud.speech.v1p1beta1.RecognitionConfig.AudioEncoding]. + // for all other audio formats. For details, see [AudioEncoding][google.cloud.speech.v1p1beta1.RecognitionConfig.AudioEncoding]. AudioEncoding encoding = 1; // Sample rate in Hertz of the audio data sent in all @@ -247,8 +255,7 @@ message RecognitionConfig { // source to 16000 Hz. If that's not possible, use the native sample rate of // the audio source (instead of re-sampling). // This field is optional for FLAC and WAV audio files, but is - // required for all other audio formats. For details, see - // [AudioEncoding][google.cloud.speech.v1p1beta1.RecognitionConfig.AudioEncoding]. + // required for all other audio formats. For details, see [AudioEncoding][google.cloud.speech.v1p1beta1.RecognitionConfig.AudioEncoding]. int32 sample_rate_hertz = 2; // The number of channels in the input audio data. @@ -424,8 +431,10 @@ message SpeakerDiarizationConfig { int32 max_speaker_count = 3; // Output only. Unused. - int32 speaker_tag = 5 - [deprecated = true, (google.api.field_behavior) = OUTPUT_ONLY]; + int32 speaker_tag = 5 [ + deprecated = true, + (google.api.field_behavior) = OUTPUT_ONLY + ]; } // Description of audio data to be recognized. @@ -589,8 +598,8 @@ message SpeechContext { // Contains audio data in the encoding specified in the `RecognitionConfig`. // Either `content` or `uri` must be supplied. Supplying both or neither -// returns [google.rpc.Code.INVALID_ARGUMENT][google.rpc.Code.INVALID_ARGUMENT]. -// See [content limits](https://cloud.google.com/speech-to-text/quotas#content). +// returns [google.rpc.Code.INVALID_ARGUMENT][google.rpc.Code.INVALID_ARGUMENT]. See +// [content limits](https://cloud.google.com/speech-to-text/quotas#content). message RecognitionAudio { // The audio source, which is either inline content or a Google Cloud // Storage uri. @@ -605,9 +614,8 @@ message RecognitionAudio { // Currently, only Google Cloud Storage URIs are // supported, which must be specified in the following format: // `gs://bucket_name/object_name` (other URI formats return - // [google.rpc.Code.INVALID_ARGUMENT][google.rpc.Code.INVALID_ARGUMENT]). - // For more information, see [Request - // URIs](https://cloud.google.com/storage/docs/reference-uris). + // [google.rpc.Code.INVALID_ARGUMENT][google.rpc.Code.INVALID_ARGUMENT]). For more information, see + // [Request URIs](https://cloud.google.com/storage/docs/reference-uris). string uri = 2; } } @@ -630,6 +638,12 @@ message LongRunningRecognizeResponse { // Sequential list of transcription results corresponding to // sequential portions of audio. repeated SpeechRecognitionResult results = 2; + + // Original output config if present in the request. + TranscriptOutputConfig output_config = 6; + + // If the transcript output fails this field contains the relevant error. + google.rpc.Status output_error = 7; } // Describes the progress of a long-running `LongRunningRecognize` call. It is @@ -646,9 +660,12 @@ message LongRunningRecognizeMetadata { // Time of the most recent processing update. google.protobuf.Timestamp last_update_time = 3; - // Output only. The URI of the audio file being transcribed. Empty if the - // audio was sent as byte content. + // Output only. The URI of the audio file being transcribed. Empty if the audio was sent + // as byte content. string uri = 4 [(google.api.field_behavior) = OUTPUT_ONLY]; + + // Output only. A copy of the TranscriptOutputConfig if it was set in the request. + TranscriptOutputConfig output_config = 5 [(google.api.field_behavior) = OUTPUT_ONLY]; } // `StreamingRecognizeResponse` is the only message returned to the client by @@ -762,9 +779,9 @@ message StreamingRecognitionResult { // For audio_channel_count = N, its output values can range from '1' to 'N'. int32 channel_tag = 5; - // Output only. The [BCP-47](https://www.rfc-editor.org/rfc/bcp/bcp47.txt) - // language tag of the language in this result. This language code was - // detected to have the most likelihood of being spoken in the audio. + // Output only. The [BCP-47](https://www.rfc-editor.org/rfc/bcp/bcp47.txt) language tag + // of the language in this result. This language code was detected to have + // the most likelihood of being spoken in the audio. string language_code = 6 [(google.api.field_behavior) = OUTPUT_ONLY]; } @@ -781,9 +798,9 @@ message SpeechRecognitionResult { // For audio_channel_count = N, its output values can range from '1' to 'N'. int32 channel_tag = 2; - // Output only. The [BCP-47](https://www.rfc-editor.org/rfc/bcp/bcp47.txt) - // language tag of the language in this result. This language code was - // detected to have the most likelihood of being spoken in the audio. + // Output only. The [BCP-47](https://www.rfc-editor.org/rfc/bcp/bcp47.txt) language tag + // of the language in this result. This language code was detected to have + // the most likelihood of being spoken in the audio. string language_code = 5 [(google.api.field_behavior) = OUTPUT_ONLY]; } diff --git a/google/cloud/speech_v1p1beta1/proto/cloud_speech_adaptation.proto b/google/cloud/speech_v1p1beta1/proto/cloud_speech_adaptation.proto index 4e4377c9..16789739 100644 --- a/google/cloud/speech_v1p1beta1/proto/cloud_speech_adaptation.proto +++ b/google/cloud/speech_v1p1beta1/proto/cloud_speech_adaptation.proto @@ -69,6 +69,7 @@ service Adaptation { patch: "/v1p1beta1/{phrase_set.name=projects/*/locations/*/phraseSets/*}" body: "phrase_set" }; + option (google.api.method_signature) = "phrase_set,update_mask"; } // Delete a phrase set. @@ -110,6 +111,7 @@ service Adaptation { patch: "/v1p1beta1/{custom_class.name=projects/*/locations/*/customClasses/*}" body: "custom_class" }; + option (google.api.method_signature) = "custom_class,update_mask"; } // Delete a custom class. diff --git a/google/cloud/speech_v1p1beta1/services/adaptation/async_client.py b/google/cloud/speech_v1p1beta1/services/adaptation/async_client.py index 96827966..42ff88d1 100644 --- a/google/cloud/speech_v1p1beta1/services/adaptation/async_client.py +++ b/google/cloud/speech_v1p1beta1/services/adaptation/async_client.py @@ -31,6 +31,7 @@ from google.cloud.speech_v1p1beta1.services.adaptation import pagers from google.cloud.speech_v1p1beta1.types import cloud_speech_adaptation from google.cloud.speech_v1p1beta1.types import resource +from google.protobuf import field_mask_pb2 as field_mask # type: ignore from .transports.base import AdaptationTransport, DEFAULT_CLIENT_INFO from .transports.grpc_asyncio import AdaptationGrpcAsyncIOTransport @@ -427,6 +428,8 @@ async def update_phrase_set( self, request: cloud_speech_adaptation.UpdatePhraseSetRequest = None, *, + phrase_set: resource.PhraseSet = None, + update_mask: field_mask.FieldMask = None, retry: retries.Retry = gapic_v1.method.DEFAULT, timeout: float = None, metadata: Sequence[Tuple[str, str]] = (), @@ -437,6 +440,21 @@ async def update_phrase_set( request (:class:`google.cloud.speech_v1p1beta1.types.UpdatePhraseSetRequest`): The request object. Message sent by the client for the `UpdatePhraseSet` method. + phrase_set (:class:`google.cloud.speech_v1p1beta1.types.PhraseSet`): + Required. The phrase set to update. + + The phrase set's ``name`` field is used to identify the + set to be updated. Format: + {api_version}/projects/{project}/locations/{location}/phraseSets/{phrase_set} + + This corresponds to the ``phrase_set`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + update_mask (:class:`google.protobuf.field_mask_pb2.FieldMask`): + The list of fields to be updated. + This corresponds to the ``update_mask`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. @@ -452,9 +470,25 @@ async def update_phrase_set( """ # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([phrase_set, update_mask]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) request = cloud_speech_adaptation.UpdatePhraseSetRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if phrase_set is not None: + request.phrase_set = phrase_set + if update_mask is not None: + request.update_mask = update_mask + # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. rpc = gapic_v1.method_async.wrap_method( @@ -809,6 +843,8 @@ async def update_custom_class( self, request: cloud_speech_adaptation.UpdateCustomClassRequest = None, *, + custom_class: resource.CustomClass = None, + update_mask: field_mask.FieldMask = None, retry: retries.Retry = gapic_v1.method.DEFAULT, timeout: float = None, metadata: Sequence[Tuple[str, str]] = (), @@ -819,6 +855,21 @@ async def update_custom_class( request (:class:`google.cloud.speech_v1p1beta1.types.UpdateCustomClassRequest`): The request object. Message sent by the client for the `UpdateCustomClass` method. + custom_class (:class:`google.cloud.speech_v1p1beta1.types.CustomClass`): + Required. The custom class to update. + + The custom class's ``name`` field is used to identify + the custom class to be updated. Format: + {api_version}/projects/{project}/locations/{location}/customClasses/{custom_class} + + This corresponds to the ``custom_class`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + update_mask (:class:`google.protobuf.field_mask_pb2.FieldMask`): + The list of fields to be updated. + This corresponds to the ``update_mask`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. @@ -838,9 +889,25 @@ async def update_custom_class( """ # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([custom_class, update_mask]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) request = cloud_speech_adaptation.UpdateCustomClassRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if custom_class is not None: + request.custom_class = custom_class + if update_mask is not None: + request.update_mask = update_mask + # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. rpc = gapic_v1.method_async.wrap_method( diff --git a/google/cloud/speech_v1p1beta1/services/adaptation/client.py b/google/cloud/speech_v1p1beta1/services/adaptation/client.py index 36f9a04c..07ef9aa5 100644 --- a/google/cloud/speech_v1p1beta1/services/adaptation/client.py +++ b/google/cloud/speech_v1p1beta1/services/adaptation/client.py @@ -35,6 +35,7 @@ from google.cloud.speech_v1p1beta1.services.adaptation import pagers from google.cloud.speech_v1p1beta1.types import cloud_speech_adaptation from google.cloud.speech_v1p1beta1.types import resource +from google.protobuf import field_mask_pb2 as field_mask # type: ignore from .transports.base import AdaptationTransport, DEFAULT_CLIENT_INFO from .transports.grpc import AdaptationGrpcTransport @@ -622,6 +623,8 @@ def update_phrase_set( self, request: cloud_speech_adaptation.UpdatePhraseSetRequest = None, *, + phrase_set: resource.PhraseSet = None, + update_mask: field_mask.FieldMask = None, retry: retries.Retry = gapic_v1.method.DEFAULT, timeout: float = None, metadata: Sequence[Tuple[str, str]] = (), @@ -632,6 +635,21 @@ def update_phrase_set( request (google.cloud.speech_v1p1beta1.types.UpdatePhraseSetRequest): The request object. Message sent by the client for the `UpdatePhraseSet` method. + phrase_set (google.cloud.speech_v1p1beta1.types.PhraseSet): + Required. The phrase set to update. + + The phrase set's ``name`` field is used to identify the + set to be updated. Format: + {api_version}/projects/{project}/locations/{location}/phraseSets/{phrase_set} + + This corresponds to the ``phrase_set`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + update_mask (google.protobuf.field_mask_pb2.FieldMask): + The list of fields to be updated. + This corresponds to the ``update_mask`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. @@ -647,6 +665,14 @@ def update_phrase_set( """ # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([phrase_set, update_mask]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) # Minor optimization to avoid making a copy if the user passes # in a cloud_speech_adaptation.UpdatePhraseSetRequest. @@ -655,6 +681,14 @@ def update_phrase_set( if not isinstance(request, cloud_speech_adaptation.UpdatePhraseSetRequest): request = cloud_speech_adaptation.UpdatePhraseSetRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if phrase_set is not None: + request.phrase_set = phrase_set + if update_mask is not None: + request.update_mask = update_mask + # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. rpc = self._transport._wrapped_methods[self._transport.update_phrase_set] @@ -1009,6 +1043,8 @@ def update_custom_class( self, request: cloud_speech_adaptation.UpdateCustomClassRequest = None, *, + custom_class: resource.CustomClass = None, + update_mask: field_mask.FieldMask = None, retry: retries.Retry = gapic_v1.method.DEFAULT, timeout: float = None, metadata: Sequence[Tuple[str, str]] = (), @@ -1019,6 +1055,21 @@ def update_custom_class( request (google.cloud.speech_v1p1beta1.types.UpdateCustomClassRequest): The request object. Message sent by the client for the `UpdateCustomClass` method. + custom_class (google.cloud.speech_v1p1beta1.types.CustomClass): + Required. The custom class to update. + + The custom class's ``name`` field is used to identify + the custom class to be updated. Format: + {api_version}/projects/{project}/locations/{location}/customClasses/{custom_class} + + This corresponds to the ``custom_class`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + update_mask (google.protobuf.field_mask_pb2.FieldMask): + The list of fields to be updated. + This corresponds to the ``update_mask`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. @@ -1038,6 +1089,14 @@ def update_custom_class( """ # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([custom_class, update_mask]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) # Minor optimization to avoid making a copy if the user passes # in a cloud_speech_adaptation.UpdateCustomClassRequest. @@ -1046,6 +1105,14 @@ def update_custom_class( if not isinstance(request, cloud_speech_adaptation.UpdateCustomClassRequest): request = cloud_speech_adaptation.UpdateCustomClassRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if custom_class is not None: + request.custom_class = custom_class + if update_mask is not None: + request.update_mask = update_mask + # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. rpc = self._transport._wrapped_methods[self._transport.update_custom_class] diff --git a/google/cloud/speech_v1p1beta1/types/__init__.py b/google/cloud/speech_v1p1beta1/types/__init__.py index 11617052..06d92d08 100644 --- a/google/cloud/speech_v1p1beta1/types/__init__.py +++ b/google/cloud/speech_v1p1beta1/types/__init__.py @@ -15,76 +15,78 @@ # limitations under the License. # -from .resource import ( - CustomClass, - PhraseSet, - SpeechAdaptation, -) from .cloud_speech import ( - RecognizeRequest, + LongRunningRecognizeMetadata, LongRunningRecognizeRequest, - StreamingRecognizeRequest, - StreamingRecognitionConfig, + LongRunningRecognizeResponse, + RecognitionAudio, RecognitionConfig, - SpeakerDiarizationConfig, RecognitionMetadata, - SpeechContext, - RecognitionAudio, + RecognizeRequest, RecognizeResponse, - LongRunningRecognizeResponse, - LongRunningRecognizeMetadata, - StreamingRecognizeResponse, - StreamingRecognitionResult, - SpeechRecognitionResult, + SpeakerDiarizationConfig, + SpeechContext, SpeechRecognitionAlternative, + SpeechRecognitionResult, + StreamingRecognitionConfig, + StreamingRecognitionResult, + StreamingRecognizeRequest, + StreamingRecognizeResponse, + TranscriptOutputConfig, WordInfo, ) from .cloud_speech_adaptation import ( + CreateCustomClassRequest, CreatePhraseSetRequest, - UpdatePhraseSetRequest, - GetPhraseSetRequest, - ListPhraseSetRequest, - ListPhraseSetResponse, + DeleteCustomClassRequest, DeletePhraseSetRequest, - CreateCustomClassRequest, - UpdateCustomClassRequest, GetCustomClassRequest, + GetPhraseSetRequest, ListCustomClassesRequest, ListCustomClassesResponse, - DeleteCustomClassRequest, + ListPhraseSetRequest, + ListPhraseSetResponse, + UpdateCustomClassRequest, + UpdatePhraseSetRequest, +) +from .resource import ( + CustomClass, + PhraseSet, + SpeechAdaptation, ) __all__ = ( - "CustomClass", - "PhraseSet", - "SpeechAdaptation", - "RecognizeRequest", + "LongRunningRecognizeMetadata", "LongRunningRecognizeRequest", - "StreamingRecognizeRequest", - "StreamingRecognitionConfig", + "LongRunningRecognizeResponse", + "RecognitionAudio", "RecognitionConfig", - "SpeakerDiarizationConfig", "RecognitionMetadata", - "SpeechContext", - "RecognitionAudio", + "RecognizeRequest", "RecognizeResponse", - "LongRunningRecognizeResponse", - "LongRunningRecognizeMetadata", - "StreamingRecognizeResponse", - "StreamingRecognitionResult", - "SpeechRecognitionResult", + "SpeakerDiarizationConfig", + "SpeechContext", "SpeechRecognitionAlternative", + "SpeechRecognitionResult", + "StreamingRecognitionConfig", + "StreamingRecognitionResult", + "StreamingRecognizeRequest", + "StreamingRecognizeResponse", + "TranscriptOutputConfig", "WordInfo", + "CreateCustomClassRequest", "CreatePhraseSetRequest", - "UpdatePhraseSetRequest", - "GetPhraseSetRequest", - "ListPhraseSetRequest", - "ListPhraseSetResponse", + "DeleteCustomClassRequest", "DeletePhraseSetRequest", - "CreateCustomClassRequest", - "UpdateCustomClassRequest", "GetCustomClassRequest", + "GetPhraseSetRequest", "ListCustomClassesRequest", "ListCustomClassesResponse", - "DeleteCustomClassRequest", + "ListPhraseSetRequest", + "ListPhraseSetResponse", + "UpdateCustomClassRequest", + "UpdatePhraseSetRequest", + "CustomClass", + "PhraseSet", + "SpeechAdaptation", ) diff --git a/google/cloud/speech_v1p1beta1/types/cloud_speech.py b/google/cloud/speech_v1p1beta1/types/cloud_speech.py index 59d5d718..3af3ae02 100644 --- a/google/cloud/speech_v1p1beta1/types/cloud_speech.py +++ b/google/cloud/speech_v1p1beta1/types/cloud_speech.py @@ -29,6 +29,7 @@ manifest={ "RecognizeRequest", "LongRunningRecognizeRequest", + "TranscriptOutputConfig", "StreamingRecognizeRequest", "StreamingRecognitionConfig", "RecognitionConfig", @@ -77,12 +78,34 @@ class LongRunningRecognizeRequest(proto.Message): request. audio (google.cloud.speech_v1p1beta1.types.RecognitionAudio): Required. The audio data to be recognized. + output_config (google.cloud.speech_v1p1beta1.types.TranscriptOutputConfig): + Optional. Specifies an optional destination + for the recognition results. """ config = proto.Field(proto.MESSAGE, number=1, message="RecognitionConfig",) audio = proto.Field(proto.MESSAGE, number=2, message="RecognitionAudio",) + output_config = proto.Field( + proto.MESSAGE, number=4, message="TranscriptOutputConfig", + ) + + +class TranscriptOutputConfig(proto.Message): + r"""Specifies an optional destination for the recognition + results. + + Attributes: + gcs_uri (str): + Specifies a Cloud Storage URI for the recognition results. + Must be specified in the format: + ``gs://bucket_name/object_name``, and the bucket must + already exist. + """ + + gcs_uri = proto.Field(proto.STRING, number=1, oneof="output_type") + class StreamingRecognizeRequest(proto.Message): r"""The top-level message sent by the client for the @@ -358,7 +381,7 @@ class AudioEncoding(proto.Enum): The accuracy of the speech recognition can be reduced if lossy codecs are used to capture or transmit audio, particularly if background noise is present. Lossy codecs include ``MULAW``, - ``AMR``, ``AMR_WB``, ``OGG_OPUS``, ``SPEEX_WITH_HEADER_BYTE``, and + ``AMR``, ``AMR_WB``, ``OGG_OPUS``, ``SPEEX_WITH_HEADER_BYTE``, ``MP3``. The ``FLAC`` and ``WAV`` audio file formats include a header that @@ -660,12 +683,24 @@ class LongRunningRecognizeResponse(proto.Message): results (Sequence[google.cloud.speech_v1p1beta1.types.SpeechRecognitionResult]): Sequential list of transcription results corresponding to sequential portions of audio. + output_config (google.cloud.speech_v1p1beta1.types.TranscriptOutputConfig): + Original output config if present in the + request. + output_error (google.rpc.status_pb2.Status): + If the transcript output fails this field + contains the relevant error. """ results = proto.RepeatedField( proto.MESSAGE, number=2, message="SpeechRecognitionResult", ) + output_config = proto.Field( + proto.MESSAGE, number=6, message="TranscriptOutputConfig", + ) + + output_error = proto.Field(proto.MESSAGE, number=7, message=status.Status,) + class LongRunningRecognizeMetadata(proto.Message): r"""Describes the progress of a long-running ``LongRunningRecognize`` @@ -686,6 +721,10 @@ class LongRunningRecognizeMetadata(proto.Message): Output only. The URI of the audio file being transcribed. Empty if the audio was sent as byte content. + output_config (google.cloud.speech_v1p1beta1.types.TranscriptOutputConfig): + Output only. A copy of the + TranscriptOutputConfig if it was set in the + request. """ progress_percent = proto.Field(proto.INT32, number=1) @@ -698,6 +737,10 @@ class LongRunningRecognizeMetadata(proto.Message): uri = proto.Field(proto.STRING, number=4) + output_config = proto.Field( + proto.MESSAGE, number=5, message="TranscriptOutputConfig", + ) + class StreamingRecognizeResponse(proto.Message): r"""``StreamingRecognizeResponse`` is the only message returned to the diff --git a/scripts/fixup_speech_v1p1beta1_keywords.py b/scripts/fixup_speech_v1p1beta1_keywords.py index 58c63d01..8c79edec 100644 --- a/scripts/fixup_speech_v1p1beta1_keywords.py +++ b/scripts/fixup_speech_v1p1beta1_keywords.py @@ -49,7 +49,7 @@ class speechCallTransformer(cst.CSTTransformer): 'get_phrase_set': ('name', ), 'list_custom_classes': ('parent', 'page_size', 'page_token', ), 'list_phrase_set': ('parent', 'page_size', 'page_token', ), - 'long_running_recognize': ('config', 'audio', ), + 'long_running_recognize': ('config', 'audio', 'output_config', ), 'recognize': ('config', 'audio', ), 'streaming_recognize': ('streaming_config', 'audio_content', ), 'update_custom_class': ('custom_class', 'update_mask', ), diff --git a/synth.metadata b/synth.metadata index f16a41af..600704bd 100644 --- a/synth.metadata +++ b/synth.metadata @@ -11,8 +11,8 @@ "git": { "name": "googleapis", "remote": "https://github.com/googleapis/googleapis.git", - "sha": "9adc11e84218d5e234392e7fe81676e778895525", - "internalRef": "359844338" + "sha": "72326861be446be27d53af95c87e6e313367c371", + "internalRef": "362934100" } }, { diff --git a/tests/unit/gapic/speech_v1p1beta1/test_adaptation.py b/tests/unit/gapic/speech_v1p1beta1/test_adaptation.py index f47c5d84..75f5f723 100644 --- a/tests/unit/gapic/speech_v1p1beta1/test_adaptation.py +++ b/tests/unit/gapic/speech_v1p1beta1/test_adaptation.py @@ -1398,6 +1398,89 @@ async def test_update_phrase_set_field_headers_async(): ] +def test_update_phrase_set_flattened(): + client = AdaptationClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_phrase_set), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = resource.PhraseSet() + + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.update_phrase_set( + phrase_set=resource.PhraseSet(name="name_value"), + update_mask=field_mask.FieldMask(paths=["paths_value"]), + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0].phrase_set == resource.PhraseSet(name="name_value") + + assert args[0].update_mask == field_mask.FieldMask(paths=["paths_value"]) + + +def test_update_phrase_set_flattened_error(): + client = AdaptationClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_phrase_set( + cloud_speech_adaptation.UpdatePhraseSetRequest(), + phrase_set=resource.PhraseSet(name="name_value"), + update_mask=field_mask.FieldMask(paths=["paths_value"]), + ) + + +@pytest.mark.asyncio +async def test_update_phrase_set_flattened_async(): + client = AdaptationAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_phrase_set), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = resource.PhraseSet() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(resource.PhraseSet()) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.update_phrase_set( + phrase_set=resource.PhraseSet(name="name_value"), + update_mask=field_mask.FieldMask(paths=["paths_value"]), + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0].phrase_set == resource.PhraseSet(name="name_value") + + assert args[0].update_mask == field_mask.FieldMask(paths=["paths_value"]) + + +@pytest.mark.asyncio +async def test_update_phrase_set_flattened_error_async(): + client = AdaptationAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.update_phrase_set( + cloud_speech_adaptation.UpdatePhraseSetRequest(), + phrase_set=resource.PhraseSet(name="name_value"), + update_mask=field_mask.FieldMask(paths=["paths_value"]), + ) + + def test_delete_phrase_set( transport: str = "grpc", request_type=cloud_speech_adaptation.DeletePhraseSetRequest ): @@ -2625,6 +2708,91 @@ async def test_update_custom_class_field_headers_async(): ) in kw["metadata"] +def test_update_custom_class_flattened(): + client = AdaptationClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_custom_class), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = resource.CustomClass() + + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.update_custom_class( + custom_class=resource.CustomClass(name="name_value"), + update_mask=field_mask.FieldMask(paths=["paths_value"]), + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0].custom_class == resource.CustomClass(name="name_value") + + assert args[0].update_mask == field_mask.FieldMask(paths=["paths_value"]) + + +def test_update_custom_class_flattened_error(): + client = AdaptationClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_custom_class( + cloud_speech_adaptation.UpdateCustomClassRequest(), + custom_class=resource.CustomClass(name="name_value"), + update_mask=field_mask.FieldMask(paths=["paths_value"]), + ) + + +@pytest.mark.asyncio +async def test_update_custom_class_flattened_async(): + client = AdaptationAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_custom_class), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = resource.CustomClass() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + resource.CustomClass() + ) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.update_custom_class( + custom_class=resource.CustomClass(name="name_value"), + update_mask=field_mask.FieldMask(paths=["paths_value"]), + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0].custom_class == resource.CustomClass(name="name_value") + + assert args[0].update_mask == field_mask.FieldMask(paths=["paths_value"]) + + +@pytest.mark.asyncio +async def test_update_custom_class_flattened_error_async(): + client = AdaptationAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.update_custom_class( + cloud_speech_adaptation.UpdateCustomClassRequest(), + custom_class=resource.CustomClass(name="name_value"), + update_mask=field_mask.FieldMask(paths=["paths_value"]), + ) + + def test_delete_custom_class( transport: str = "grpc", request_type=cloud_speech_adaptation.DeleteCustomClassRequest,