Skip to content

Commit a70815d

Browse files
lukesneeringerdaspecster
authored andcommitted
Cloud Speech Veneer does not raise for > 1 result. (#2962)
* Cloud Speech Veneer does not raise for > 1 result. This commit also: - adds `transcript` and `confidence` convenience methods on result objects - updates unit tests appropriately - moves from google.cloud.grpc.* to google.cloud.proto.* - updates dependencies accordingly * Fix linting error, and make imports follow PEP8. * Fix two more linting issues. * Address @daspecster suggestions. Also finally fix all linting issues. * Update speech usage RST file. * Swap back to a list return, fixes coverage. * Final lint change for @daspecster. * Move imports to one per two lines.
1 parent 6b7b9ac commit a70815d

File tree

10 files changed

+176
-92
lines changed

10 files changed

+176
-92
lines changed

docs/speech-usage.rst

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,14 @@ Great Britian.
8888
>>> sample = client.sample(source_uri='gs://my-bucket/recording.flac',
8989
... encoding=speech.Encoding.FLAC,
9090
... sample_rate=44100)
91-
>>> alternatives = sample.sync_recognize(
91+
>>> results = sample.sync_recognize(
9292
... speech.Encoding.FLAC, 16000,
9393
... source_uri='gs://my-bucket/recording.flac', language_code='en-GB',
9494
... max_alternatives=2)
95-
>>> for alternative in alternatives:
95+
>>> for result in results:
9696
... print('=' * 20)
97-
... print('transcript: ' + alternative.transcript)
98-
... print('confidence: ' + alternative.confidence)
97+
... print('transcript: ' + result.transcript)
98+
... print('confidence: ' + result.confidence)
9999
====================
100100
transcript: Hello, this is a test
101101
confidence: 0.81
@@ -112,12 +112,12 @@ Example of using the profanity filter.
112112
>>> sample = client.sample(source_uri='gs://my-bucket/recording.flac',
113113
... encoding=speech.Encoding.FLAC,
114114
... sample_rate=44100)
115-
>>> alternatives = sample.sync_recognize(max_alternatives=1,
116-
... profanity_filter=True)
117-
>>> for alternative in alternatives:
115+
>>> results = sample.sync_recognize(max_alternatives=1,
116+
... profanity_filter=True)
117+
>>> for result in results:
118118
... print('=' * 20)
119-
... print('transcript: ' + alternative.transcript)
120-
... print('confidence: ' + alternative.confidence)
119+
... print('transcript: ' + result.transcript)
120+
... print('confidence: ' + result.confidence)
121121
====================
122122
transcript: Hello, this is a f****** test
123123
confidence: 0.81
@@ -134,12 +134,12 @@ words to the vocabulary of the recognizer.
134134
... encoding=speech.Encoding.FLAC,
135135
... sample_rate=44100)
136136
>>> hints = ['hi', 'good afternoon']
137-
>>> alternatives = sample.sync_recognize(max_alternatives=2,
138-
... speech_context=hints)
139-
>>> for alternative in alternatives:
137+
>>> results = sample.sync_recognize(max_alternatives=2,
138+
... speech_context=hints)
139+
>>> for result in results:
140140
... print('=' * 20)
141-
... print('transcript: ' + alternative.transcript)
142-
... print('confidence: ' + alternative.confidence)
141+
... print('transcript: ' + result.transcript)
142+
... print('confidence: ' + result.confidence)
143143
====================
144144
transcript: Hello, this is a test
145145
confidence: 0.81

speech/google/cloud/speech/_gax.py

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,23 @@
1616

1717

1818
from google.cloud.gapic.speech.v1beta1.speech_client import SpeechClient
19-
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import RecognitionAudio
20-
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import RecognitionConfig
21-
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import SpeechContext
22-
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import (
19+
from google.cloud.proto.speech.v1beta1.cloud_speech_pb2 import RecognitionAudio
20+
from google.cloud.proto.speech.v1beta1.cloud_speech_pb2 import (
21+
RecognitionConfig)
22+
from google.cloud.proto.speech.v1beta1.cloud_speech_pb2 import (
23+
SpeechContext)
24+
from google.cloud.proto.speech.v1beta1.cloud_speech_pb2 import (
2325
StreamingRecognitionConfig)
24-
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import (
26+
from google.cloud.proto.speech.v1beta1.cloud_speech_pb2 import (
2527
StreamingRecognizeRequest)
2628
from google.longrunning import operations_grpc
2729

2830
from google.cloud._helpers import make_secure_channel
2931
from google.cloud._helpers import make_secure_stub
3032
from google.cloud._http import DEFAULT_USER_AGENT
3133

32-
from google.cloud.speech.alternative import Alternative
3334
from google.cloud.speech.operation import Operation
35+
from google.cloud.speech.result import Result
3436

3537
OPERATIONS_API_HOST = 'speech.googleapis.com'
3638

@@ -235,15 +237,9 @@ def sync_recognize(self, sample, language_code=None, max_alternatives=None,
235237
words to the vocabulary of the recognizer.
236238
237239
:rtype: list
238-
:returns: A list of dictionaries. One dict for each alternative. Each
239-
dictionary typically contains two keys (though not
240-
all will be present in all cases)
240+
:returns: List of :class:`google.cloud.speech.result.Result` objects.
241241
242-
* ``transcript``: The detected text from the audio recording.
243-
* ``confidence``: The confidence in language detection, float
244-
between 0 and 1.
245-
246-
:raises: ValueError if more than one result is returned or no results.
242+
:raises: ValueError if there are no results.
247243
"""
248244
config = RecognitionConfig(
249245
encoding=sample.encoding, sample_rate=sample.sample_rate,
@@ -254,13 +250,13 @@ def sync_recognize(self, sample, language_code=None, max_alternatives=None,
254250
uri=sample.source_uri)
255251
api = self._gapic_api
256252
api_response = api.sync_recognize(config=config, audio=audio)
257-
if len(api_response.results) == 1:
258-
results = api_response.results.pop()
259-
alternatives = results.alternatives
260-
return [Alternative.from_pb(alternative)
261-
for alternative in alternatives]
262-
else:
263-
raise ValueError('More than one result or none returned from API.')
253+
254+
# Sanity check: If we got no results back, raise an error.
255+
if len(api_response.results) == 0:
256+
raise ValueError('No results returned from the Speech API.')
257+
258+
# Iterate over any results that came back.
259+
return [Result.from_pb(result) for result in api_response.results]
264260

265261

266262
def _stream_requests(sample, language_code=None, max_alternatives=None,

speech/google/cloud/speech/client.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,11 @@ class Client(BaseClient):
6060
def __init__(self, credentials=None, http=None, use_gax=None):
6161
super(Client, self).__init__(credentials=credentials, http=http)
6262
self._connection = Connection(
63-
credentials=self._credentials, http=self._http)
63+
credentials=self._credentials,
64+
http=self._http,
65+
)
66+
67+
# Save on the actual client class whether we use GAX or not.
6468
if use_gax is None:
6569
self._use_gax = _USE_GAX
6670
else:

speech/google/cloud/speech/operation.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@
1414

1515
"""Long running operation representation for Google Speech API"""
1616

17-
from google.cloud.grpc.speech.v1beta1 import cloud_speech_pb2
17+
from google.cloud.proto.speech.v1beta1 import cloud_speech_pb2
1818

1919
from google.cloud import operation
20-
from google.cloud.speech.alternative import Alternative
20+
from google.cloud.speech.result import Result
2121

2222

2323
operation.register_type(cloud_speech_pb2.AsyncRecognizeMetadata)
@@ -58,11 +58,13 @@ def _update_state(self, operation_pb):
5858
if result_type != 'response':
5959
return
6060

61+
# Retrieve the results.
62+
# If there were no results at all, raise an exception.
6163
pb_results = self.response.results
62-
if len(pb_results) != 1:
63-
raise ValueError('Expected exactly one result, found:',
64-
pb_results)
64+
if len(pb_results) == 0:
65+
raise ValueError('Speech API returned no results.')
6566

66-
result = pb_results[0]
67-
self.results = [Alternative.from_pb(alternative)
68-
for alternative in result.alternatives]
67+
# Save the results to the Operation object.
68+
self.results = []
69+
for pb_result in pb_results:
70+
self.results.append(Result.from_pb(pb_result))

speech/google/cloud/speech/result.py

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,53 @@
1717
from google.cloud.speech.alternative import Alternative
1818

1919

20+
class Result(object):
21+
"""Speech recognition result representation.
22+
23+
This is the object that comes back on sync or async requests
24+
(but not streaming requests).
25+
26+
:type alternatives: list
27+
:param alternatives: List of
28+
:class:`~google.cloud.speech.alternative.Alternative`.
29+
"""
30+
def __init__(self, alternatives):
31+
self.alternatives = alternatives
32+
33+
@classmethod
34+
def from_pb(cls, result):
35+
"""Factory: construct instance of ``SpeechRecognitionResult``.
36+
37+
:type result: :class:`~google.cloud.grpc.speech.v1beta1\
38+
.cloud_speech_pb2.StreamingRecognizeResult`
39+
:param result: Instance of ``StreamingRecognizeResult`` protobuf.
40+
41+
:rtype: :class:`~google.cloud.speech.result.SpeechRecognitionResult`
42+
:returns: Instance of ``SpeechRecognitionResult``.
43+
"""
44+
alternatives = [Alternative.from_pb(result) for result
45+
in result.alternatives]
46+
return cls(alternatives=alternatives)
47+
48+
@property
49+
def confidence(self):
50+
"""Return the confidence for the most probable alternative.
51+
52+
:rtype: float
53+
:returns: Confidence value, between 0 and 1.
54+
"""
55+
return self.alternatives[0].confidence
56+
57+
@property
58+
def transcript(self):
59+
"""Return the transcript for the most probable alternative.
60+
61+
:rtype: str
62+
:returns: Speech transcript.
63+
"""
64+
return self.alternatives[0].transcript
65+
66+
2067
class StreamingSpeechResult(object):
2168
"""Streaming speech result representation.
2269
@@ -46,9 +93,27 @@ def from_pb(cls, response):
4693
:rtype: :class:`~google.cloud.speech.result.StreamingSpeechResult`
4794
:returns: Instance of ``StreamingSpeechResult``.
4895
"""
49-
alternatives = [Alternative.from_pb(alternative)
50-
for alternative in response.alternatives]
96+
alternatives = [Alternative.from_pb(result) for result
97+
in response.alternatives]
5198
is_final = response.is_final
5299
stability = response.stability
53100
return cls(alternatives=alternatives, is_final=is_final,
54101
stability=stability)
102+
103+
@property
104+
def confidence(self):
105+
"""Return the confidence for the most probable alternative.
106+
107+
:rtype: float
108+
:returns: Confidence value, between 0 and 1.
109+
"""
110+
return self.alternatives[0].confidence
111+
112+
@property
113+
def transcript(self):
114+
"""Return the transcript for the most probable alternative.
115+
116+
:rtype: str
117+
:returns: Speech transcript.
118+
"""
119+
return self.alternatives[0].transcript

speech/setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
REQUIREMENTS = [
5252
'google-cloud-core >= 0.22.1, < 0.23dev',
5353
'grpcio >= 1.0.2, < 2.0dev',
54-
'gapic-google-cloud-speech-v1beta1 >= 0.14.0, < 0.15dev',
54+
'gapic-google-cloud-speech-v1beta1 >= 0.15.0, < 0.16dev',
5555
]
5656

5757
setup(

speech/unit_tests/test__gax.py

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,8 @@ def _call_fut(self, sample, language_code, max_alternatives,
3636
def test_ctor(self):
3737
from google.cloud import speech
3838
from google.cloud.speech.sample import Sample
39-
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import (
40-
SpeechContext)
41-
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import (
42-
RecognitionConfig)
43-
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import (
44-
StreamingRecognitionConfig)
45-
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import (
39+
from google.cloud.proto.speech.v1beta1.cloud_speech_pb2 import (
40+
RecognitionConfig, SpeechContext, StreamingRecognitionConfig,
4641
StreamingRecognizeRequest)
4742

4843
sample = Sample(content=self.AUDIO_CONTENT,
@@ -103,10 +98,8 @@ def test_stream_requests(self):
10398
from io import BytesIO
10499
from google.cloud import speech
105100
from google.cloud.speech.sample import Sample
106-
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import (
107-
StreamingRecognitionConfig)
108-
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import (
109-
StreamingRecognizeRequest)
101+
from google.cloud.proto.speech.v1beta1.cloud_speech_pb2 import (
102+
StreamingRecognitionConfig, StreamingRecognizeRequest)
110103

111104
sample = Sample(stream=BytesIO(self.AUDIO_CONTENT),
112105
encoding=speech.Encoding.FLAC,

speech/unit_tests/test_alternative.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def test_from_api_repr_with_no_confidence(self):
5454
self.assertIsNone(alternative.confidence)
5555

5656
def test_from_pb_with_no_confidence(self):
57-
from google.cloud.grpc.speech.v1beta1 import cloud_speech_pb2
57+
from google.cloud.proto.speech.v1beta1 import cloud_speech_pb2
5858

5959
text = 'the double trouble'
6060
pb_value = cloud_speech_pb2.SpeechRecognitionAlternative(

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy