Skip to content

Commit 0ca8559

Browse files
committed
Add speech async GAPIC.
1 parent 6c59755 commit 0ca8559

File tree

6 files changed

+65
-26
lines changed

6 files changed

+65
-26
lines changed

docs/speech-usage.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,9 @@ See: `Speech Asynchronous Recognize`_
7070
>>> operation.complete
7171
True
7272
>>> for result in operation.results:
73-
... print('=' * 20)
74-
... print(result.transcript)
75-
... print(result.confidence)
73+
... print('=' * 20)
74+
... print(result.transcript)
75+
... print(result.confidence)
7676
====================
7777
'how old is the Brooklyn Bridge'
7878
0.98267895

speech/google/cloud/speech/_gax.py

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,13 @@
1414

1515
"""GAX/GAPIC module for managing Speech API requests."""
1616

17+
from google.longrunning import operations_grpc
18+
1719
from google.cloud.gapic.speech.v1beta1.speech_api import SpeechApi
20+
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import (
21+
AsyncRecognizeMetadata)
22+
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import (
23+
AsyncRecognizeResponse)
1824
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import SpeechContext
1925
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import RecognitionConfig
2026
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import RecognitionAudio
@@ -23,13 +29,23 @@
2329
from google.cloud.grpc.speech.v1beta1.cloud_speech_pb2 import (
2430
StreamingRecognizeRequest)
2531

26-
2732
from google.cloud.speech.alternative import Alternative
33+
from google.cloud._helpers import make_secure_stub
34+
from google.cloud.connection import DEFAULT_USER_AGENT
35+
from google.cloud.speech.operation import Operation
36+
from google.cloud.operation import register_type
37+
38+
39+
OPERATIONS_API_HOST = 'speech.googleapis.com'
40+
41+
register_type(AsyncRecognizeMetadata)
42+
register_type(AsyncRecognizeResponse)
2843

2944

3045
class GAPICSpeechAPI(object):
3146
"""Manage calls through GAPIC wrappers to the Speech API."""
32-
def __init__(self):
47+
def __init__(self, client=None):
48+
self._client = client
3349
self._gapic_api = SpeechApi()
3450

3551
def async_recognize(self, sample, language_code=None,
@@ -72,9 +88,26 @@ def async_recognize(self, sample, language_code=None,
7288
and phrases. This can also be used to add new
7389
words to the vocabulary of the recognizer.
7490
75-
:raises NotImplementedError: Always.
91+
:rtype: :class:`~google.cloud.operation.Opeartion`
92+
:returns: Instance of ``Operation`` to poll for results.
7693
"""
77-
raise NotImplementedError
94+
config = RecognitionConfig(
95+
encoding=sample.encoding, sample_rate=sample.sample_rate,
96+
language_code=language_code, max_alternatives=max_alternatives,
97+
profanity_filter=profanity_filter,
98+
speech_context=SpeechContext(phrases=speech_context))
99+
100+
audio = RecognitionAudio(content=sample.content,
101+
uri=sample.source_uri)
102+
api = self._gapic_api
103+
response = api.async_recognize(config=config, audio=audio)
104+
105+
self._client._operations_stub = make_secure_stub(
106+
self._client.connection.credentials,
107+
DEFAULT_USER_AGENT,
108+
operations_grpc.OperationsStub,
109+
OPERATIONS_API_HOST)
110+
return Operation.from_pb(response, self._client)
78111

79112
def sync_recognize(self, sample, language_code=None, max_alternatives=None,
80113
profanity_filter=None, speech_context=None):

speech/google/cloud/speech/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ def speech_api(self):
162162
"""Helper for speech-related API calls."""
163163
if self._speech_api is None:
164164
if self._use_gax:
165-
self._speech_api = GAPICSpeechAPI()
165+
self._speech_api = GAPICSpeechAPI(self)
166166
else:
167167
self._speech_api = _JSONSpeechAPI(self)
168168
return self._speech_api

speech/setup.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@
5252
REQUIREMENTS = [
5353
'google-cloud-core >= 0.20.0',
5454
'gapic-google-cloud-speech-v1beta1 >= 0.11.1, < 0.12.0',
55-
'grpc-google-cloud-speech-v1beta1 >= 0.11.1, < 0.12.0',
5655
]
5756

5857
setup(

speech/unit_tests/test_client.py

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -199,11 +199,10 @@ def test_sync_recognize_with_empty_results_gax(self):
199199
credentials = _Credentials()
200200
client = self._makeOne(credentials=credentials, use_gax=True)
201201
client.connection = _Connection()
202+
_MockGAPICSpeechAPI._results = []
202203

203204
with self.assertRaises(ValueError):
204-
mock_no_results = _MockGAPICSpeechAPI
205-
mock_no_results._results = []
206-
with _Monkey(MUT, SpeechApi=mock_no_results):
205+
with _Monkey(MUT, SpeechApi=_MockGAPICSpeechAPI):
207206
sample = Sample(source_uri=self.AUDIO_SOURCE_URI,
208207
encoding=speech.Encoding.FLAC,
209208
sample_rate=self.SAMPLE_RATE)
@@ -218,9 +217,7 @@ def test_sync_recognize_with_gax(self):
218217
client = self._makeOne(credentials=creds, use_gax=True)
219218
client.connection = _Connection()
220219
client._speech_api = None
221-
222-
mock_no_results = _MockGAPICSpeechAPI
223-
mock_no_results._results = [_MockGAPICSyncResult()]
220+
_MockGAPICSpeechAPI._results = [_MockGAPICSyncResult]
224221

225222
with _Monkey(MUT, SpeechApi=_MockGAPICSpeechAPI):
226223
sample = client.sample(source_uri=self.AUDIO_SOURCE_URI,
@@ -277,13 +274,16 @@ def test_async_recognize_with_gax(self):
277274
credentials = _Credentials()
278275
client = self._makeOne(credentials=credentials)
279276
client.connection = _Connection()
277+
client.connection.credentials = credentials
280278

281279
sample = client.sample(source_uri=self.AUDIO_SOURCE_URI,
282280
encoding=speech.Encoding.LINEAR16,
283281
sample_rate=self.SAMPLE_RATE)
284282
with _Monkey(MUT, SpeechApi=_MockGAPICSpeechAPI):
285-
with self.assertRaises(NotImplementedError):
286-
client.async_recognize(sample)
283+
operation = client.async_recognize(sample)
284+
285+
self.assertFalse(operation.complete)
286+
self.assertIsNone(operation.response)
287287

288288
def test_speech_api_with_gax(self):
289289
from google.cloud.speech import _gax as MUT
@@ -321,28 +321,40 @@ class _MockGAPICAlternative(object):
321321
confidence = 0.95234356
322322

323323

324+
class _MockGAPICMetadata(object):
325+
type_url = None
326+
327+
324328
class _MockGAPICSyncResult(object):
325329
alternatives = [_MockGAPICAlternative()]
326330

327331

328332
class _MockGAPICSpeechResponse(object):
329333
error = None
330334
endpointer_type = None
335+
name = None
336+
metadata = _MockGAPICMetadata()
331337
results = []
332338
result_index = 0
333339

334340

335341
class _MockGAPICSpeechAPI(object):
336342
_requests = None
337-
_response = _MockGAPICSpeechResponse()
343+
_response = _MockGAPICSpeechResponse
338344
_results = [_MockGAPICSyncResult()]
339345

346+
def async_recognize(self, config, audio):
347+
from google.longrunning.operations_pb2 import Operation
348+
self.config = config
349+
self.audio = audio
350+
operation = Operation()
351+
return operation
352+
340353
def sync_recognize(self, config, audio):
341354
self.config = config
342355
self.audio = audio
343-
mock_response = self._response
344-
mock_response.results = self._results
345-
return mock_response
356+
self._response.results = self._results
357+
return self._response
346358

347359

348360
class _Credentials(object):

system_tests/speech.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,6 @@ def _make_async_request(self, content=None, source_uri=None,
119119

120120
def _check_results(self, results, num_results=1):
121121
self.assertEqual(len(results), num_results)
122-
123122
top_result = results[0]
124123
self.assertIsInstance(top_result, Alternative)
125124
self.assertEqual(top_result.transcript,
@@ -153,8 +152,6 @@ def test_sync_recognize_gcs_file(self):
153152
self._check_results(result)
154153

155154
def test_async_recognize_local_file(self):
156-
if Config.USE_GAX:
157-
self.skipTest('async_recognize gRPC not yet implemented.')
158155
with open(AUDIO_FILE, 'rb') as file_obj:
159156
content = file_obj.read()
160157

@@ -165,8 +162,6 @@ def test_async_recognize_local_file(self):
165162
self._check_results(operation.results, 2)
166163

167164
def test_async_recognize_gcs_file(self):
168-
if Config.USE_GAX:
169-
self.skipTest('async_recognize gRPC not yet implemented.')
170165
bucket_name = Config.TEST_BUCKET.name
171166
blob_name = 'hello.wav'
172167
blob = Config.TEST_BUCKET.blob(blob_name)

0 commit comments

Comments
 (0)