Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cloud Speech Veneer does not raise for > 1 result. #2962

Merged
merged 8 commits into from
Jan 25, 2017
Merged
28 changes: 14 additions & 14 deletions docs/speech-usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,14 @@ Great Britian.
>>> sample = client.sample(source_uri='gs://my-bucket/recording.flac',
... encoding=speech.Encoding.FLAC,
... sample_rate=44100)
>>> alternatives = sample.sync_recognize(
>>> results = sample.sync_recognize(
... speech.Encoding.FLAC, 16000,
... source_uri='gs://my-bucket/recording.flac', language_code='en-GB',
... max_alternatives=2)
>>> for alternative in alternatives:
>>> for result in results:
... print('=' * 20)
... print('transcript: ' + alternative.transcript)
... print('confidence: ' + alternative.confidence)
... print('transcript: ' + result.transcript)
... print('confidence: ' + result.confidence)
====================
transcript: Hello, this is a test
confidence: 0.81
Expand All @@ -112,12 +112,12 @@ Example of using the profanity filter.
>>> sample = client.sample(source_uri='gs://my-bucket/recording.flac',
... encoding=speech.Encoding.FLAC,
... sample_rate=44100)
>>> alternatives = sample.sync_recognize(max_alternatives=1,
... profanity_filter=True)
>>> for alternative in alternatives:
>>> results = sample.sync_recognize(max_alternatives=1,
... profanity_filter=True)
>>> for result in results:
... print('=' * 20)
... print('transcript: ' + alternative.transcript)
... print('confidence: ' + alternative.confidence)
... print('transcript: ' + result.transcript)
... print('confidence: ' + result.confidence)
====================
transcript: Hello, this is a f****** test
confidence: 0.81
Expand All @@ -134,12 +134,12 @@ words to the vocabulary of the recognizer.
... encoding=speech.Encoding.FLAC,
... sample_rate=44100)
>>> hints = ['hi', 'good afternoon']
>>> alternatives = sample.sync_recognize(max_alternatives=2,
... speech_context=hints)
>>> for alternative in alternatives:
>>> results = sample.sync_recognize(max_alternatives=2,
... speech_context=hints)
>>> for result in results:
... print('=' * 20)
... print('transcript: ' + alternative.transcript)
... print('confidence: ' + alternative.confidence)
... print('transcript: ' + result.transcript)
... print('confidence: ' + result.confidence)
====================
transcript: Hello, this is a test
confidence: 0.81
Expand Down
36 changes: 13 additions & 23 deletions speech/google/cloud/speech/_gax.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,17 @@


from google.cloud.gapic.speech.v1beta1.speech_client import SpeechClient
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import RecognitionAudio
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import RecognitionConfig
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import SpeechContext
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import (
StreamingRecognitionConfig)
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import (
StreamingRecognizeRequest)
from google.cloud.proto.speech.v1beta1.cloud_speech_pb2 import (
RecognitionAudio, RecognitionConfig, SpeechContext,
StreamingRecognitionConfig, StreamingRecognizeRequest)
from google.longrunning import operations_grpc

from google.cloud._helpers import make_secure_channel
from google.cloud._helpers import make_secure_stub
from google.cloud._http import DEFAULT_USER_AGENT

from google.cloud.speech.alternative import Alternative
from google.cloud.speech.operation import Operation
from google.cloud.speech.result import Result

OPERATIONS_API_HOST = 'speech.googleapis.com'

Expand Down Expand Up @@ -235,15 +231,9 @@ def sync_recognize(self, sample, language_code=None, max_alternatives=None,
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)
:returns: List of :class:`google.cloud.speech.result.Result` objects.

* ``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.
:raises: ValueError if there are no results.
"""
config = RecognitionConfig(
encoding=sample.encoding, sample_rate=sample.sample_rate,
Expand All @@ -254,13 +244,13 @@ def sync_recognize(self, sample, language_code=None, max_alternatives=None,
uri=sample.source_uri)
api = self._gapic_api
api_response = api.sync_recognize(config=config, audio=audio)
if len(api_response.results) == 1:
results = api_response.results.pop()
alternatives = results.alternatives
return [Alternative.from_pb(alternative)
for alternative in alternatives]
else:
raise ValueError('More than one result or none returned from API.')

# 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(i) for i in api_response.results]

This comment was marked as spam.



def _stream_requests(sample, language_code=None, max_alternatives=None,
Expand Down
6 changes: 5 additions & 1 deletion speech/google/cloud/speech/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@ class Client(BaseClient):
def __init__(self, credentials=None, http=None, use_gax=None):
super(Client, self).__init__(credentials=credentials, http=http)
self._connection = Connection(
credentials=self._credentials, http=self._http)
credentials=self._credentials,
http=self._http,
)

# Save on the actual client class whether we use GAX or not.
if use_gax is None:
self._use_gax = _USE_GAX
else:
Expand Down
18 changes: 10 additions & 8 deletions speech/google/cloud/speech/operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@

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

from google.cloud.grpc.speech.v1beta1 import cloud_speech_pb2
from google.cloud.proto.speech.v1beta1 import cloud_speech_pb2

from google.cloud import operation
from google.cloud.speech.alternative import Alternative
from google.cloud.speech.result import Result


operation.register_type(cloud_speech_pb2.AsyncRecognizeMetadata)
Expand Down Expand Up @@ -58,11 +58,13 @@ def _update_state(self, operation_pb):
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) != 1:
raise ValueError('Expected exactly one result, found:',
pb_results)
if len(pb_results) == 0:
raise ValueError('Speech API returned no results.')

result = pb_results[0]
self.results = [Alternative.from_pb(alternative)
for alternative in result.alternatives]
# Save the results to the Operation object.
self.results = []

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

for pb_result in pb_results:
self.results.append(Result.from_pb(pb_result))
67 changes: 65 additions & 2 deletions speech/google/cloud/speech/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,52 @@
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

This comment was marked as spam.

This comment was marked as spam.

(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 ``SpeechRecognitionResult``.

:type result: :class:`~google.cloud.grpc.speech.v1beta1\
.cloud_speech_pb2.StreamingRecognizeResult`
:param result: Instance of ``StreamingRecognizeResult`` protobuf.

:rtype: :class:`~google.cloud.speech.result.SpeechRecognitionResult`
:returns: Instance of ``SpeechRecognitionResult``.
"""
alternatives = [Alternative.from_pb(i) for i 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

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.


@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.

Expand Down Expand Up @@ -46,9 +92,26 @@ def from_pb(cls, response):
:rtype: :class:`~google.cloud.speech.result.StreamingSpeechResult`
:returns: Instance of ``StreamingSpeechResult``.
"""
alternatives = [Alternative.from_pb(alternative)
for alternative in response.alternatives]
alternatives = [Alternative.from_pb(i) for i 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
2 changes: 1 addition & 1 deletion speech/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
REQUIREMENTS = [
'google-cloud-core >= 0.22.1, < 0.23dev',
'grpcio >= 1.0.2, < 2.0dev',
'gapic-google-cloud-speech-v1beta1 >= 0.14.0, < 0.15dev',
'gapic-google-cloud-speech-v1beta1 >= 0.15.0, < 0.16dev',
]

setup(
Expand Down
15 changes: 4 additions & 11 deletions speech/unit_tests/test__gax.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,8 @@ def _call_fut(self, sample, language_code, max_alternatives,
def test_ctor(self):
from google.cloud import speech
from google.cloud.speech.sample import Sample
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import (
SpeechContext)
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import (
RecognitionConfig)
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import (
StreamingRecognitionConfig)
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import (
from google.cloud.proto.speech.v1beta1.cloud_speech_pb2 import (
RecognitionConfig, SpeechContext, StreamingRecognitionConfig,

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

StreamingRecognizeRequest)

sample = Sample(content=self.AUDIO_CONTENT,
Expand Down Expand Up @@ -103,10 +98,8 @@ def test_stream_requests(self):
from io import BytesIO
from google.cloud import speech
from google.cloud.speech.sample import Sample
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import (
StreamingRecognitionConfig)
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import (
StreamingRecognizeRequest)
from google.cloud.proto.speech.v1beta1.cloud_speech_pb2 import (
StreamingRecognitionConfig, StreamingRecognizeRequest)

sample = Sample(stream=BytesIO(self.AUDIO_CONTENT),
encoding=speech.Encoding.FLAC,
Expand Down
2 changes: 1 addition & 1 deletion speech/unit_tests/test_alternative.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def test_from_api_repr_with_no_confidence(self):
self.assertIsNone(alternative.confidence)

def test_from_pb_with_no_confidence(self):
from google.cloud.grpc.speech.v1beta1 import cloud_speech_pb2
from google.cloud.proto.speech.v1beta1 import cloud_speech_pb2

text = 'the double trouble'
pb_value = cloud_speech_pb2.SpeechRecognitionAlternative(
Expand Down