Google's expected crashes are now a warning - code should be pollished
This commit is contained in:
parent
90e6fd1ed8
commit
be10bfe44c
1 changed files with 48 additions and 46 deletions
|
@ -33,7 +33,7 @@ class GoogleVoiceClient(object):
|
||||||
self.hugvey = hugvey
|
self.hugvey = hugvey
|
||||||
self.language_code = language_code
|
self.language_code = language_code
|
||||||
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = credential_file
|
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = credential_file
|
||||||
|
|
||||||
# Create a thread-safe buffer of audio data
|
# Create a thread-safe buffer of audio data
|
||||||
self.buffer = queue.Queue()
|
self.buffer = queue.Queue()
|
||||||
self.isRunning = threading.Event()
|
self.isRunning = threading.Event()
|
||||||
|
@ -41,53 +41,53 @@ class GoogleVoiceClient(object):
|
||||||
self.target_rate = 16000
|
self.target_rate = 16000
|
||||||
self.cv_laststate = None
|
self.cv_laststate = None
|
||||||
self.restart = False
|
self.restart = False
|
||||||
|
|
||||||
|
|
||||||
self.task = threading.Thread(target=self.run, name=f"hugvey#{self.hugvey.id}v")
|
self.task = threading.Thread(target=self.run, name=f"hugvey#{self.hugvey.id}v")
|
||||||
self.task.setDaemon(True)
|
self.task.setDaemon(True)
|
||||||
self.task.start()
|
self.task.start()
|
||||||
self.subsequentMutedFrames = 0
|
self.subsequentMutedFrames = 0
|
||||||
|
|
||||||
self.lastNonFinalTranscript = None
|
self.lastNonFinalTranscript = None
|
||||||
|
|
||||||
def pause(self):
|
def pause(self):
|
||||||
self.isRunning.clear()
|
self.isRunning.clear()
|
||||||
self.restart = True
|
self.restart = True
|
||||||
|
|
||||||
def resume(self):
|
def resume(self):
|
||||||
self.buffer = queue.Queue() # have a clear queue when resuming
|
self.buffer = queue.Queue() # have a clear queue when resuming
|
||||||
self.isRunning.set()
|
self.isRunning.set()
|
||||||
|
|
||||||
def generator(self):
|
def generator(self):
|
||||||
self.logger.debug('start generator')
|
self.logger.debug('start generator')
|
||||||
while not self.toBeShutdown and self.isRunning.is_set():
|
while not self.toBeShutdown and self.isRunning.is_set():
|
||||||
try:
|
try:
|
||||||
# set a timeout, as not to wait infinitely for the buffer when
|
# set a timeout, as not to wait infinitely for the buffer when
|
||||||
# we actually want to restart
|
# we actually want to restart
|
||||||
yield self.buffer.get(timeout=.3)
|
yield self.buffer.get(timeout=.3)
|
||||||
except queue.Empty as e:
|
except queue.Empty as e:
|
||||||
self.logger.debug('empty mic buffer - restart?')
|
self.logger.debug('empty mic buffer - restart?')
|
||||||
# print(self.isRunning.isSet())
|
# print(self.isRunning.isSet())
|
||||||
self.logger.info('stop generator')
|
self.logger.info('stop generator')
|
||||||
self.restart = False # don't trigger double restart
|
self.restart = False # don't trigger double restart
|
||||||
|
|
||||||
# raise RequireRestart("Restart required (generator)")
|
# raise RequireRestart("Restart required (generator)")
|
||||||
|
|
||||||
def setLanguage(self, language_code):
|
def setLanguage(self, language_code):
|
||||||
if self.language_code == language_code:
|
if self.language_code == language_code:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.logger.info("Change language from {} to {}".format(self.language_code, language_code))
|
self.logger.info("Change language from {} to {}".format(self.language_code, language_code))
|
||||||
self.language_code = language_code
|
self.language_code = language_code
|
||||||
self.isRunning.clear()
|
self.isRunning.clear()
|
||||||
self.restart = True
|
self.restart = True
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.isRunning.set()
|
self.isRunning.set()
|
||||||
|
|
||||||
# Leave this here to avoid "Too many files open" errors.
|
# Leave this here to avoid "Too many files open" errors.
|
||||||
self.speech_client = speech.SpeechClient()
|
self.speech_client = speech.SpeechClient()
|
||||||
|
|
||||||
while not self.toBeShutdown:
|
while not self.toBeShutdown:
|
||||||
config = types.RecognitionConfig(
|
config = types.RecognitionConfig(
|
||||||
encoding=enums.RecognitionConfig.AudioEncoding.LINEAR16,
|
encoding=enums.RecognitionConfig.AudioEncoding.LINEAR16,
|
||||||
|
@ -96,59 +96,59 @@ class GoogleVoiceClient(object):
|
||||||
self.streaming_config = types.StreamingRecognitionConfig(
|
self.streaming_config = types.StreamingRecognitionConfig(
|
||||||
config=config,
|
config=config,
|
||||||
interim_results=True)
|
interim_results=True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.logger.log(LOG_BS,"wait for Google Voice")
|
self.logger.log(LOG_BS,"wait for Google Voice")
|
||||||
if not self.isRunning.wait(timeout=1):
|
if not self.isRunning.wait(timeout=1):
|
||||||
continue # re-ceck toBeShutdown
|
continue # re-ceck toBeShutdown
|
||||||
self.logger.debug("Starting Google Voice")
|
self.logger.debug("Starting Google Voice")
|
||||||
|
|
||||||
|
|
||||||
audio_generator = self.generator()
|
audio_generator = self.generator()
|
||||||
requests = (types.StreamingRecognizeRequest(audio_content=content)
|
requests = (types.StreamingRecognizeRequest(audio_content=content)
|
||||||
for content in audio_generator)
|
for content in audio_generator)
|
||||||
responses = self.speech_client.streaming_recognize(
|
responses = self.speech_client.streaming_recognize(
|
||||||
self.streaming_config, requests)
|
self.streaming_config, requests)
|
||||||
|
|
||||||
self.logger.debug("Starting voice loop")
|
self.logger.debug("Starting voice loop")
|
||||||
for response in responses:
|
for response in responses:
|
||||||
if not response.results:
|
if not response.results:
|
||||||
self.logger.debug('...')
|
self.logger.debug('...')
|
||||||
continue
|
continue
|
||||||
"""Iterates through server responses and prints them.
|
"""Iterates through server responses and prints them.
|
||||||
|
|
||||||
The responses passed is a generator that will block until a response
|
The responses passed is a generator that will block until a response
|
||||||
is provided by the server.
|
is provided by the server.
|
||||||
|
|
||||||
Each response may contain multiple results, and each result may contain
|
Each response may contain multiple results, and each result may contain
|
||||||
multiple alternatives; for details, see https://goo.gl/tjCPAU. Here we
|
multiple alternatives; for details, see https://goo.gl/tjCPAU. Here we
|
||||||
print only the transcription for the top alternative of the top result.
|
print only the transcription for the top alternative of the top result.
|
||||||
|
|
||||||
In this case, responses are provided for interim results as well. If the
|
In this case, responses are provided for interim results as well. If the
|
||||||
response is an interim one, print a line feed at the end of it, to allow
|
response is an interim one, print a line feed at the end of it, to allow
|
||||||
the next result to overwrite it, until the response is a final one. For the
|
the next result to overwrite it, until the response is a final one. For the
|
||||||
final one, print a newline to preserve the finalized transcription.
|
final one, print a newline to preserve the finalized transcription.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# The `results` list is consecutive. For streaming, we only care about
|
# The `results` list is consecutive. For streaming, we only care about
|
||||||
# the first result being considered, since once it's `is_final`, it
|
# the first result being considered, since once it's `is_final`, it
|
||||||
# moves on to considering the next utterance.
|
# moves on to considering the next utterance.
|
||||||
result = response.results[0]
|
result = response.results[0]
|
||||||
if not result.alternatives:
|
if not result.alternatives:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Display the transcription of the top alternative.
|
# Display the transcription of the top alternative.
|
||||||
transcript = result.alternatives[0].transcript
|
transcript = result.alternatives[0].transcript
|
||||||
|
|
||||||
# self.logger.debug("Text: ".format(transcript))
|
# self.logger.debug("Text: ".format(transcript))
|
||||||
|
|
||||||
if not result.is_final:
|
if not result.is_final:
|
||||||
self.logger.debug(f"Text: {transcript}")
|
self.logger.debug(f"Text: {transcript}")
|
||||||
self.lastNonFinalTranscript = transcript
|
self.lastNonFinalTranscript = transcript
|
||||||
else:
|
else:
|
||||||
self.logger.info(f"Text: {transcript}")
|
self.logger.info(f"Text: {transcript}")
|
||||||
self.lastNonFinalTranscript = None
|
self.lastNonFinalTranscript = None
|
||||||
|
|
||||||
if result.is_final:
|
if result.is_final:
|
||||||
self.logger.info("native final")
|
self.logger.info("native final")
|
||||||
msg = {
|
msg = {
|
||||||
|
@ -156,13 +156,13 @@ class GoogleVoiceClient(object):
|
||||||
"is_final": result.is_final,
|
"is_final": result.is_final,
|
||||||
"transcript": transcript.strip(),
|
"transcript": transcript.strip(),
|
||||||
}
|
}
|
||||||
|
|
||||||
self.hugvey.queueEvent(msg)
|
self.hugvey.queueEvent(msg)
|
||||||
|
|
||||||
if self.restart:
|
if self.restart:
|
||||||
self.restart = False
|
self.restart = False
|
||||||
raise RequireRestart("Restart required")
|
raise RequireRestart("Restart required")
|
||||||
|
|
||||||
if self.toBeShutdown:
|
if self.toBeShutdown:
|
||||||
self.logger.warn("Stopping voice loop")
|
self.logger.warn("Stopping voice loop")
|
||||||
break
|
break
|
||||||
|
@ -170,30 +170,33 @@ class GoogleVoiceClient(object):
|
||||||
self.restart = False
|
self.restart = False
|
||||||
self.logger.warn("Restart Google Voice. Language: {}".format(self.language_code))
|
self.logger.warn("Restart Google Voice. Language: {}".format(self.language_code))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.critical(f"Crashed Google Voice: {e}")
|
if "305" in str(e):
|
||||||
|
self.logger.warning(f"Long Google Voice: {e}")
|
||||||
|
else:
|
||||||
|
self.logger.critical(f"Crashed Google Voice: {e}")
|
||||||
|
|
||||||
# sending an extra message is deprecated since we ignore finals anyway
|
# sending an extra message is deprecated since we ignore finals anyway
|
||||||
# make sure we always send a 'final' transcript.
|
# make sure we always send a 'final' transcript.
|
||||||
# if self.lastNonFinalTranscript is not None:
|
# if self.lastNonFinalTranscript is not None:
|
||||||
# msg = {
|
# msg = {
|
||||||
# "event": "speech",
|
# "event": "speech",
|
||||||
# "is_final": True,
|
# "is_final": True,
|
||||||
# "transcript": self.lastNonFinalTranscript.strip(),
|
# "transcript": self.lastNonFinalTranscript.strip(),
|
||||||
# }
|
# }
|
||||||
# self.hugvey.queueEvent(msg)
|
# self.hugvey.queueEvent(msg)
|
||||||
|
|
||||||
self.logger.warn("Stop google run()") # finish means wrapping of hugvey#3v thread
|
self.logger.warn("Stop google run()") # finish means wrapping of hugvey#3v thread
|
||||||
|
|
||||||
# time.sleep(1)
|
# time.sleep(1)
|
||||||
# for i in gc.get_referrers(self):
|
# for i in gc.get_referrers(self):
|
||||||
# print(i)
|
# print(i)
|
||||||
|
|
||||||
|
|
||||||
def receive(self, chunk):
|
def receive(self, chunk):
|
||||||
if not self.task.isAlive():
|
if not self.task.isAlive():
|
||||||
raise Exception("Voice thread died")
|
raise Exception("Voice thread died")
|
||||||
|
|
||||||
|
|
||||||
if audioop.max(chunk, 2) == 0:
|
if audioop.max(chunk, 2) == 0:
|
||||||
# mic is muted on client side.
|
# mic is muted on client side.
|
||||||
self.subsequentMutedFrames += 1
|
self.subsequentMutedFrames += 1
|
||||||
|
@ -202,31 +205,30 @@ class GoogleVoiceClient(object):
|
||||||
self.logger.info("Pause muted stream!")
|
self.logger.info("Pause muted stream!")
|
||||||
self.pause()
|
self.pause()
|
||||||
return
|
return
|
||||||
|
|
||||||
self.subsequentMutedFrames = 0
|
self.subsequentMutedFrames = 0
|
||||||
# self.logger.debug("We have mic!")
|
# self.logger.debug("We have mic!")
|
||||||
if not self.isRunning.is_set():
|
if not self.isRunning.is_set():
|
||||||
self.logger.info("Resume voice")
|
self.logger.info("Resume voice")
|
||||||
self.resume()
|
self.resume()
|
||||||
|
|
||||||
|
|
||||||
if not self.isRunning.is_set():
|
if not self.isRunning.is_set():
|
||||||
# logger.log(LOG_BS, "Don't put to queue if google is paused")
|
# logger.log(LOG_BS, "Don't put to queue if google is paused")
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.src_rate == self.target_rate:
|
if self.src_rate == self.target_rate:
|
||||||
data = chunk
|
data = chunk
|
||||||
else:
|
else:
|
||||||
data, self.cv_laststate = audioop.ratecv(chunk, 2, 1, self.src_rate, self.target_rate, self.cv_laststate)
|
data, self.cv_laststate = audioop.ratecv(chunk, 2, 1, self.src_rate, self.target_rate, self.cv_laststate)
|
||||||
self.buffer.put_nowait(data)
|
self.buffer.put_nowait(data)
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
self.toBeShutdown = True
|
self.toBeShutdown = True
|
||||||
self.hugvey = None
|
self.hugvey = None
|
||||||
|
|
||||||
def triggerStart(self):
|
def triggerStart(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
self.logger.warn("Destroyed google object")
|
self.logger.warn("Destroyed google object")
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue