Logging made fit for cutelog / client audio stream now on port = port_nr + hugvey_id'
This commit is contained in:
parent
3eb4c78ae4
commit
d95709b9a1
10 changed files with 102 additions and 85 deletions
|
@ -22,8 +22,8 @@ import queue
|
||||||
import threading
|
import threading
|
||||||
from hugvey.voice import VoiceStorage
|
from hugvey.voice import VoiceStorage
|
||||||
|
|
||||||
|
mainLogger = logging.getLogger("hugvey")
|
||||||
logger = logging.getLogger("command")
|
logger = mainLogger.getChild("command")
|
||||||
|
|
||||||
# def exceptionEmitter(a):
|
# def exceptionEmitter(a):
|
||||||
# print(a)
|
# print(a)
|
||||||
|
@ -159,7 +159,7 @@ class CentralCommand(object):
|
||||||
|
|
||||||
while self.isRunning.is_set():
|
while self.isRunning.is_set():
|
||||||
hv_id, cmd = await self.commandQueue.get()
|
hv_id, cmd = await self.commandQueue.get()
|
||||||
logger.info('Got command to send: {} {}'.format(hv_id, cmd))
|
logger.debug('Got command to send: {} {}'.format(hv_id, cmd))
|
||||||
zmqSend(s, hv_id, cmd)
|
zmqSend(s, hv_id, cmd)
|
||||||
|
|
||||||
logger.warn('Stopping command sender')
|
logger.warn('Stopping command sender')
|
||||||
|
@ -191,7 +191,7 @@ class CentralCommand(object):
|
||||||
async def eventListener(self):
|
async def eventListener(self):
|
||||||
s = self.ctx.socket(zmq.SUB)
|
s = self.ctx.socket(zmq.SUB)
|
||||||
s.bind(self.config['events']['listen_address'])
|
s.bind(self.config['events']['listen_address'])
|
||||||
logger.info("Listen for events on: {}".format(
|
logger.debug("Listen for events on: {}".format(
|
||||||
self.config['events']['listen_address']))
|
self.config['events']['listen_address']))
|
||||||
|
|
||||||
for id in self.hugvey_ids:
|
for id in self.hugvey_ids:
|
||||||
|
@ -262,10 +262,9 @@ class HugveyState(object):
|
||||||
STATE_RUNNING = "running"
|
STATE_RUNNING = "running"
|
||||||
|
|
||||||
def __init__(self, id: int, command: CentralCommand):
|
def __init__(self, id: int, command: CentralCommand):
|
||||||
|
|
||||||
self.id = id
|
self.id = id
|
||||||
self.command = command
|
self.command = command
|
||||||
self.logger = logging.getLogger(f"hugvey{self.id}")
|
self.logger = mainLogger.getChild(f"{self.id}").getChild("command")
|
||||||
self.loop = asyncio.new_event_loop()
|
self.loop = asyncio.new_event_loop()
|
||||||
self.isConfigured = False
|
self.isConfigured = False
|
||||||
self.isRunning = asyncio.Event(loop=self.loop)
|
self.isRunning = asyncio.Event(loop=self.loop)
|
||||||
|
@ -323,8 +322,8 @@ class HugveyState(object):
|
||||||
print(awaitable)
|
print(awaitable)
|
||||||
await awaitable
|
await awaitable
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception(e)
|
self.logger.exception(e)
|
||||||
logger.critical(f"Hugvey restart required but not implemented yet")
|
self.logger.critical(f"Hugvey restart required but not implemented yet")
|
||||||
|
|
||||||
# TODO: restart
|
# TODO: restart
|
||||||
|
|
||||||
|
@ -348,7 +347,7 @@ class HugveyState(object):
|
||||||
self.eventQueue = asyncio.Queue() # start event queue here, to avoid loop issues
|
self.eventQueue = asyncio.Queue() # start event queue here, to avoid loop issues
|
||||||
while self.command.isRunning.is_set():
|
while self.command.isRunning.is_set():
|
||||||
event = await self.eventQueue.get()
|
event = await self.eventQueue.get()
|
||||||
self.logger.info("Received: {}".format(event))
|
self.logger.debug("Received: {}".format(event))
|
||||||
|
|
||||||
if event['event'] == 'connection' and not self.isRunning.is_set():
|
if event['event'] == 'connection' and not self.isRunning.is_set():
|
||||||
self.restart()
|
self.restart()
|
||||||
|
@ -462,7 +461,7 @@ class HugveyState(object):
|
||||||
self.streamer = AudioStreamer(
|
self.streamer = AudioStreamer(
|
||||||
self.command.config['voice']['chunk'],
|
self.command.config['voice']['chunk'],
|
||||||
self.ip,
|
self.ip,
|
||||||
int(self.command.config['voice']['port']))
|
int(self.command.config['voice']['port']) + self.id)
|
||||||
|
|
||||||
if self.command.config['voyeur']:
|
if self.command.config['voyeur']:
|
||||||
self.logger.warn("Debug on: Connecting Audio player")
|
self.logger.warn("Debug on: Connecting Audio player")
|
||||||
|
@ -470,7 +469,7 @@ class HugveyState(object):
|
||||||
self.command.config['voice']['src_rate'], self.command.config['voice']['out_rate'])
|
self.command.config['voice']['src_rate'], self.command.config['voice']['out_rate'])
|
||||||
self.streamer.addConsumer(self.player)
|
self.streamer.addConsumer(self.player)
|
||||||
|
|
||||||
self.logger.info("Start Speech")
|
self.logger.debug("Start Speech")
|
||||||
self.google = GoogleVoiceClient(
|
self.google = GoogleVoiceClient(
|
||||||
hugvey=self,
|
hugvey=self,
|
||||||
src_rate=self.command.config['voice']['src_rate'],
|
src_rate=self.command.config['voice']['src_rate'],
|
||||||
|
@ -485,13 +484,13 @@ class HugveyState(object):
|
||||||
Start the audio streamer service
|
Start the audio streamer service
|
||||||
'''
|
'''
|
||||||
|
|
||||||
self.logger.info("Start audio stream")
|
self.logger.debug("Start audio stream")
|
||||||
|
|
||||||
while self.notShuttingDown:
|
while self.notShuttingDown:
|
||||||
await self.isRunning.wait()
|
await self.isRunning.wait()
|
||||||
|
|
||||||
self.logger.info("Start audio stream")
|
self.logger.debug("Start audio stream")
|
||||||
await self.getStreamer().run()
|
await self.getStreamer().run()
|
||||||
self.logger.warn(f"stream has left the building from {self.ip}")
|
self.logger.critical(f"stream has left the building from {self.ip}")
|
||||||
# if we end up here, the streamer finished, probably meaning hte hugvey shutdown
|
# if we end up here, the streamer finished, probably meaning hte hugvey shutdown
|
||||||
self.gone()
|
self.gone()
|
||||||
|
|
|
@ -98,7 +98,7 @@ class VoiceServer(object):
|
||||||
|
|
||||||
while not self.stopped:
|
while not self.stopped:
|
||||||
try:
|
try:
|
||||||
address = "tcp://*:{}".format(self.voice_port)
|
address = "tcp://*:{}".format(self.voice_port + self.hugvey.id)
|
||||||
self.voice_socket = self.ctx.socket(zmq.PUB)
|
self.voice_socket = self.ctx.socket(zmq.PUB)
|
||||||
self.voice_socket.bind(address)
|
self.voice_socket.bind(address)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
logger = logging.getLogger("communication")
|
|
||||||
|
mainLogger = logging.getLogger("hugvey")
|
||||||
|
|
||||||
# hyper verbose log level. Have it here, becase it needs to be _somewhere_
|
# hyper verbose log level. Have it here, becase it needs to be _somewhere_
|
||||||
LOG_BS = 5
|
LOG_BS = 5
|
||||||
|
@ -11,14 +12,17 @@ def getTopic(hugvey_id):
|
||||||
|
|
||||||
|
|
||||||
def zmqSend(socket, hugvey_id, msg):
|
def zmqSend(socket, hugvey_id, msg):
|
||||||
logger.info("SEND: {}".format(msg))
|
log = mainLogger.getChild(f"{hugvey_id}").getChild("communication")
|
||||||
|
log.debug("SEND: {}".format(msg))
|
||||||
msgData = json.dumps(msg)
|
msgData = json.dumps(msg)
|
||||||
topic = getTopic(hugvey_id)
|
topic = getTopic(hugvey_id)
|
||||||
logger.info("Send 0mq to {} containing {}".format(topic, msg))
|
log.debug("Send 0mq to {} containing {}".format(topic, msg))
|
||||||
socket.send_multipart([topic.encode(), msgData.encode()])
|
socket.send_multipart([topic.encode(), msgData.encode()])
|
||||||
|
|
||||||
async def zmqReceive(socket):
|
async def zmqReceive(socket):
|
||||||
topic, msg = await socket.recv_multipart()
|
topic, msg = await socket.recv_multipart()
|
||||||
hugvey_id = topic.decode()[2:]
|
hugvey_id = topic.decode()[2:]
|
||||||
logger.info("Received 0mq messages for Hugvey #{} containing {}".format(hugvey_id, msg.decode()))
|
mainLogger.getChild(f"{hugvey_id}").getChild("communication").debug(
|
||||||
|
"Received 0mq messages for Hugvey #{} containing {}".format(hugvey_id, msg.decode())
|
||||||
|
)
|
||||||
return int(hugvey_id), json.loads(msg.decode())
|
return int(hugvey_id), json.loads(msg.decode())
|
||||||
|
|
|
@ -18,7 +18,8 @@ from urllib.parse import urlparse
|
||||||
from hugvey import central_command
|
from hugvey import central_command
|
||||||
from hugvey.voice import VoiceStorage
|
from hugvey.voice import VoiceStorage
|
||||||
|
|
||||||
logger = logging.getLogger("panopticon")
|
mainLogger = logging.getLogger("hugvey")
|
||||||
|
logger = mainLogger.getChild("panopticon")
|
||||||
|
|
||||||
web_dir = os.path.join(os.path.split(__file__)[0], '..', 'www')
|
web_dir = os.path.join(os.path.split(__file__)[0], '..', 'www')
|
||||||
|
|
||||||
|
|
|
@ -18,14 +18,15 @@ import queue
|
||||||
import uuid
|
import uuid
|
||||||
from hugvey.communication import LOG_BS
|
from hugvey.communication import LOG_BS
|
||||||
|
|
||||||
|
mainLogger = logging.getLogger("hugvey")
|
||||||
logger = logging.getLogger("speech")
|
logger = mainLogger.getChild("speech")
|
||||||
|
|
||||||
class RequireRestart(Exception):
|
class RequireRestart(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class GoogleVoiceClient(object):
|
class GoogleVoiceClient(object):
|
||||||
def __init__(self, hugvey, src_rate, credential_file, language_code = "en_GB"):
|
def __init__(self, hugvey, src_rate, credential_file, language_code = "en_GB"):
|
||||||
|
self.logger = mainLogger.getChild(f"{hugvey.id}").getChild('speech')
|
||||||
self.src_rate = src_rate
|
self.src_rate = src_rate
|
||||||
self.hugvey = hugvey
|
self.hugvey = hugvey
|
||||||
self.language_code = language_code
|
self.language_code = language_code
|
||||||
|
@ -60,7 +61,7 @@ class GoogleVoiceClient(object):
|
||||||
if self.language_code == language_code:
|
if self.language_code == language_code:
|
||||||
return
|
return
|
||||||
|
|
||||||
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.restart = True
|
self.restart = True
|
||||||
|
|
||||||
|
@ -71,7 +72,7 @@ class GoogleVoiceClient(object):
|
||||||
while not self.toBeShutdown:
|
while not self.toBeShutdown:
|
||||||
try:
|
try:
|
||||||
self.isRunning.wait()
|
self.isRunning.wait()
|
||||||
logger.info("Starting Google Voice")
|
self.logger.info("Starting Google Voice")
|
||||||
|
|
||||||
self.speech_client = speech.SpeechClient()
|
self.speech_client = speech.SpeechClient()
|
||||||
config = types.RecognitionConfig(
|
config = types.RecognitionConfig(
|
||||||
|
@ -88,7 +89,7 @@ class GoogleVoiceClient(object):
|
||||||
responses = self.speech_client.streaming_recognize(
|
responses = self.speech_client.streaming_recognize(
|
||||||
self.streaming_config, requests)
|
self.streaming_config, requests)
|
||||||
|
|
||||||
logger.info("Starting voice loop")
|
self.logger.info("Starting voice loop")
|
||||||
for response in responses:
|
for response in responses:
|
||||||
if not response.results:
|
if not response.results:
|
||||||
continue
|
continue
|
||||||
|
@ -117,12 +118,12 @@ class GoogleVoiceClient(object):
|
||||||
# Display the transcription of the top alternative.
|
# Display the transcription of the top alternative.
|
||||||
transcript = result.alternatives[0].transcript
|
transcript = result.alternatives[0].transcript
|
||||||
|
|
||||||
# logger.debug("Text: ".format(transcript))
|
# self.logger.debug("Text: ".format(transcript))
|
||||||
|
|
||||||
if not result.is_final:
|
if not result.is_final:
|
||||||
logger.debug(f"Text: {transcript}")
|
self.logger.debug(f"Text: {transcript}")
|
||||||
else:
|
else:
|
||||||
logger.info(f"Text: {transcript}")
|
self.logger.info(f"Text: {transcript}")
|
||||||
|
|
||||||
msg = {
|
msg = {
|
||||||
"event": "speech",
|
"event": "speech",
|
||||||
|
@ -137,12 +138,12 @@ class GoogleVoiceClient(object):
|
||||||
raise RequireRestart("Restart required")
|
raise RequireRestart("Restart required")
|
||||||
|
|
||||||
if self.toBeShutdown:
|
if self.toBeShutdown:
|
||||||
logger.warn("Stopping voice loop")
|
self.logger.warn("Stopping voice loop")
|
||||||
break
|
break
|
||||||
except RequireRestart as e:
|
except RequireRestart as e:
|
||||||
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:
|
||||||
logger.critical(f"Crashed Google Voice: {e}")
|
self.logger.critical(f"Crashed Google Voice: {e}")
|
||||||
|
|
||||||
|
|
||||||
def receive(self, chunk):
|
def receive(self, chunk):
|
||||||
|
|
|
@ -2,8 +2,8 @@ import pyaudio
|
||||||
import logging
|
import logging
|
||||||
import audioop
|
import audioop
|
||||||
|
|
||||||
|
mainLogger = logging.getLogger("hugvey")
|
||||||
logger = logging.getLogger("player")
|
logger = mainLogger.getChild("player")
|
||||||
|
|
||||||
class Player:
|
class Player:
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -6,7 +6,8 @@ import logging
|
||||||
from zmq.asyncio import Context
|
from zmq.asyncio import Context
|
||||||
import zmq
|
import zmq
|
||||||
|
|
||||||
logger = logging.getLogger("streamer")
|
mainLogger = logging.getLogger("hugvey")
|
||||||
|
logger = mainLogger.getChild("streamer")
|
||||||
|
|
||||||
class AudioStreamer(object):
|
class AudioStreamer(object):
|
||||||
def __init__(self, chunk, address: str, port: int):
|
def __init__(self, chunk, address: str, port: int):
|
||||||
|
|
100
hugvey/story.py
100
hugvey/story.py
|
@ -7,7 +7,8 @@ import urllib.parse
|
||||||
from .communication import LOG_BS
|
from .communication import LOG_BS
|
||||||
from tornado.httpclient import AsyncHTTPClient, HTTPRequest
|
from tornado.httpclient import AsyncHTTPClient, HTTPRequest
|
||||||
|
|
||||||
logger = logging.getLogger("narrative")
|
mainLogger = logging.getLogger("hugvey")
|
||||||
|
logger = mainLogger.getChild("narrative")
|
||||||
|
|
||||||
class Utterance(object):
|
class Utterance(object):
|
||||||
"""Part of a reply"""
|
"""Part of a reply"""
|
||||||
|
@ -44,6 +45,7 @@ class Message(object):
|
||||||
|
|
||||||
def setStory(self, story):
|
def setStory(self, story):
|
||||||
self.story = story
|
self.story = story
|
||||||
|
self.logger = story.logger.getChild("message")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def initFromJson(message, data, story):
|
def initFromJson(message, data, story):
|
||||||
|
@ -70,7 +72,7 @@ class Message(object):
|
||||||
|
|
||||||
def setVariable(self, name, value):
|
def setVariable(self, name, value):
|
||||||
if name not in self.variables:
|
if name not in self.variables:
|
||||||
logger.critical("Set nonexisting variable")
|
self.logger.critical("Set nonexisting variable")
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.variableValues[name] == value:
|
if self.variableValues[name] == value:
|
||||||
|
@ -78,21 +80,21 @@ class Message(object):
|
||||||
|
|
||||||
self.variableValues[name] = value
|
self.variableValues[name] = value
|
||||||
|
|
||||||
logger.warn(f"Set variable, now fetch {name}")
|
self.story.warn(f"Set variable, now fetch {name}")
|
||||||
if not None in self.variableValues.values():
|
if not None in self.variableValues.values():
|
||||||
logger.warn(f"now fetch indeed {name}")
|
self.story.warn(f"now fetch indeed {name}")
|
||||||
asyncio.get_event_loop().create_task(self.getAudioFilePath())
|
asyncio.get_event_loop().create_task(self.getAudioFilePath())
|
||||||
# asyncio.get_event_loop().call_soon_threadsafe(self.getAudioFilePath)
|
# asyncio.get_event_loop().call_soon_threadsafe(self.getAudioFilePath)
|
||||||
logger.warn(f"started {name}")
|
self.story.warn(f"started {name}")
|
||||||
|
|
||||||
def getText(self):
|
def getText(self):
|
||||||
# sort reverse to avoid replacing the wrong variable
|
# sort reverse to avoid replacing the wrong variable
|
||||||
self.variables.sort(key=len, reverse=True)
|
self.variables.sort(key=len, reverse=True)
|
||||||
text = self.text
|
text = self.text
|
||||||
logger.info(f"Getting text for {self.id}")
|
self.logger.debug(f"Getting text for {self.id}")
|
||||||
logger.debug(self.variables)
|
self.logger.debug(self.variables)
|
||||||
for var in self.variables:
|
for var in self.variables:
|
||||||
logger.debug(f"try replacing ${var} with {self.variableValues[var]} in {text}")
|
self.logger.debug(f"try replacing ${var} with {self.variableValues[var]} in {text}")
|
||||||
replacement = self.variableValues[var] if (self.variableValues[var] is not None) else "nothing" #TODO: translate nothing to each language
|
replacement = self.variableValues[var] if (self.variableValues[var] is not None) else "nothing" #TODO: translate nothing to each language
|
||||||
text = text.replace('$'+var, replacement)
|
text = text.replace('$'+var, replacement)
|
||||||
return text
|
return text
|
||||||
|
@ -134,7 +136,7 @@ class Message(object):
|
||||||
if self.audioFile is not None:
|
if self.audioFile is not None:
|
||||||
return self.audioFile
|
return self.audioFile
|
||||||
|
|
||||||
logger.warn(f"Fetching audio for {self.getText()}")
|
self.logger.debug(f"Fetching audio for {self.getText()}")
|
||||||
async with self.filenameFetchLock:
|
async with self.filenameFetchLock:
|
||||||
client = AsyncHTTPClient()
|
client = AsyncHTTPClient()
|
||||||
queryString = urllib.parse.urlencode({
|
queryString = urllib.parse.urlencode({
|
||||||
|
@ -146,14 +148,14 @@ class Message(object):
|
||||||
url = f"http://localhost:{self.story.panopticon_port}/voice?{queryString}",
|
url = f"http://localhost:{self.story.panopticon_port}/voice?{queryString}",
|
||||||
method="GET"
|
method="GET"
|
||||||
)
|
)
|
||||||
logger.log(LOG_BS, request.url)
|
self.logger.log(LOG_BS, request.url)
|
||||||
response = await client.fetch(request)
|
response = await client.fetch(request)
|
||||||
|
|
||||||
if response.code != 200:
|
if response.code != 200:
|
||||||
logger.critical(f"Error when fetching filename: {response.code} for {queryString}")
|
self.logger.critical(f"Error when fetching filename: {response.code} for {queryString}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
logger.warn(f"Fetched audio for {self.getText()}")
|
self.logger.debug(f"Fetched audio for {self.getText()}")
|
||||||
return response.body.decode().strip()
|
return response.body.decode().strip()
|
||||||
|
|
||||||
|
|
||||||
|
@ -242,11 +244,11 @@ class Condition(object):
|
||||||
|
|
||||||
if 'onlyIfNoReply' in self.vars and self.vars['onlyIfNoReply']:
|
if 'onlyIfNoReply' in self.vars and self.vars['onlyIfNoReply']:
|
||||||
if story.currentReply and story.currentReply is not None and story.currentReply.hasUtterances():
|
if story.currentReply and story.currentReply is not None and story.currentReply.hasUtterances():
|
||||||
logger.log(LOG_BS, f'Only if no reply has text! {story.currentReply.getText()}')
|
story.logger.log(LOG_BS, f'Only if no reply has text! {story.currentReply.getText()}')
|
||||||
# 'onlyIfNoReply': only use this timeout if participants doesn't speak.
|
# 'onlyIfNoReply': only use this timeout if participants doesn't speak.
|
||||||
return False
|
return False
|
||||||
# else:
|
# else:
|
||||||
# logger.debug('Only if no reply has no text yet!')
|
# story.logger.debug('Only if no reply has no text yet!')
|
||||||
|
|
||||||
hasMetTimeout = now - story.lastMsgFinishTime >= float(self.vars['seconds'])
|
hasMetTimeout = now - story.lastMsgFinishTime >= float(self.vars['seconds'])
|
||||||
if not hasMetTimeout:
|
if not hasMetTimeout:
|
||||||
|
@ -278,12 +280,12 @@ class Condition(object):
|
||||||
self.vars['regexCompiled'] = re.compile(self.vars['regex'])
|
self.vars['regexCompiled'] = re.compile(self.vars['regex'])
|
||||||
|
|
||||||
t = r.getText().lower()
|
t = r.getText().lower()
|
||||||
logger.log(LOG_BS, 'attempt regex: {} on {}'.format(self.vars['regex'], t))
|
story.logger.log(LOG_BS, 'attempt regex: {} on {}'.format(self.vars['regex'], t))
|
||||||
result = self.vars['regexCompiled'].search(t)
|
result = self.vars['regexCompiled'].search(t)
|
||||||
if result is None:
|
if result is None:
|
||||||
#if there is something to match, but not found, it's never ok
|
#if there is something to match, but not found, it's never ok
|
||||||
return False
|
return False
|
||||||
logger.debug('Got match on {}'.format(self.vars['regex']))
|
story.logger.debug('Got match on {}'.format(self.vars['regex']))
|
||||||
|
|
||||||
if ('instantMatch' in self.vars and self.vars['instantMatch']) or not r.isSpeaking():
|
if ('instantMatch' in self.vars and self.vars['instantMatch']) or not r.isSpeaking():
|
||||||
# try to avoid setting variables for intermediate strings
|
# try to avoid setting variables for intermediate strings
|
||||||
|
@ -292,19 +294,19 @@ class Condition(object):
|
||||||
story.setVariableValue(captureGroup, results[captureGroup])
|
story.setVariableValue(captureGroup, results[captureGroup])
|
||||||
|
|
||||||
if 'instantMatch' in self.vars and self.vars['instantMatch']:
|
if 'instantMatch' in self.vars and self.vars['instantMatch']:
|
||||||
logger.info(f"Instant match on {self.vars['regex']}, {self.vars}")
|
story.logger.info(f"Instant match on {self.vars['regex']}, {self.vars}")
|
||||||
return True
|
return True
|
||||||
# TODO: implement 'instant match' -> don't wait for isFinished()
|
# TODO: implement 'instant match' -> don't wait for isFinished()
|
||||||
|
|
||||||
if r.isSpeaking():
|
if r.isSpeaking():
|
||||||
logger.log(LOG_BS, f"is speaking: {r.getLastUtterance().text} - {r.getLastUtterance().startTime}")
|
story.logger.log(LOG_BS, f"is speaking: {r.getLastUtterance().text} - {r.getLastUtterance().startTime}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# print(self.vars)
|
# print(self.vars)
|
||||||
# either there's a match, or nothing to match at all
|
# either there's a match, or nothing to match at all
|
||||||
if 'delays' in self.vars:
|
if 'delays' in self.vars:
|
||||||
if story.lastMsgFinishTime is None:
|
if story.lastMsgFinishTime is None:
|
||||||
logger.debug("not finished playback yet")
|
story.logger.debug("not finished playback yet")
|
||||||
return False
|
return False
|
||||||
# time between finishing playback and ending of speaking:
|
# time between finishing playback and ending of speaking:
|
||||||
replyDuration = r.getLastUtterance().endTime - story.lastMsgFinishTime
|
replyDuration = r.getLastUtterance().endTime - story.lastMsgFinishTime
|
||||||
|
@ -312,12 +314,12 @@ class Condition(object):
|
||||||
for delay in delays:
|
for delay in delays:
|
||||||
if replyDuration > float(delay['minReplyDuration']):
|
if replyDuration > float(delay['minReplyDuration']):
|
||||||
timeSinceReply = story.timer.getElapsed() - r.getLastUtterance().endTime
|
timeSinceReply = story.timer.getElapsed() - r.getLastUtterance().endTime
|
||||||
logger.log(LOG_BS, f"check delay duration is now {replyDuration}, already waiting for {timeSinceReply}, have to wait {delay['waitTime']}")
|
story.logger.log(LOG_BS, f"check delay duration is now {replyDuration}, already waiting for {timeSinceReply}, have to wait {delay['waitTime']}")
|
||||||
if timeSinceReply > float(delay['waitTime']):
|
if timeSinceReply > float(delay['waitTime']):
|
||||||
return True
|
return True
|
||||||
break # don't check other delays
|
break # don't check other delays
|
||||||
# wait for delay to match
|
# wait for delay to match
|
||||||
logger.debug("Wait for it...")
|
story.logger.debug("Wait for it...")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# There is a match and no delay say, person finished speaking. Go ahead sir!
|
# There is a match and no delay say, person finished speaking. Go ahead sir!
|
||||||
|
@ -425,10 +427,10 @@ class Diversion(object):
|
||||||
story.stats['diversions']['no_response'] += 1
|
story.stats['diversions']['no_response'] += 1
|
||||||
msg = story.get(self.params['msgId'])
|
msg = story.get(self.params['msgId'])
|
||||||
if msg is None:
|
if msg is None:
|
||||||
logger.critical(f"Not a valid message id for diversion: {self.params['msgId']}")
|
story.logger.critical(f"Not a valid message id for diversion: {self.params['msgId']}")
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.info(f"Diverge: No response {self.id} {story.stats}")
|
story.logger.info(f"Diverge: No response {self.id} {story.stats}")
|
||||||
self.returnMessage = msgTo
|
self.returnMessage = msgTo
|
||||||
await story.setCurrentMessage(msg)
|
await story.setCurrentMessage(msg)
|
||||||
story.currentDiversion = self
|
story.currentDiversion = self
|
||||||
|
@ -437,7 +439,7 @@ class Diversion(object):
|
||||||
return
|
return
|
||||||
|
|
||||||
async def _returnAfterNoResponse(self, story):
|
async def _returnAfterNoResponse(self, story):
|
||||||
logger.info(f"Finalise diversion: {self.id}")
|
story.logger.info(f"Finalise diversion: {self.id}")
|
||||||
story.stats['consecutiveSilentTimeouts'] = 0 # reset counter after diverging
|
story.stats['consecutiveSilentTimeouts'] = 0 # reset counter after diverging
|
||||||
if self.params['returnAfterStrand']:
|
if self.params['returnAfterStrand']:
|
||||||
await story.setCurrentMessage(self.returnMessage)
|
await story.setCurrentMessage(self.returnMessage)
|
||||||
|
@ -525,6 +527,7 @@ class Story(object):
|
||||||
self.events = [] # queue of received events
|
self.events = [] # queue of received events
|
||||||
self.commands = [] # queue of commands to send
|
self.commands = [] # queue of commands to send
|
||||||
self.log = [] # all nodes/elements that are triggered
|
self.log = [] # all nodes/elements that are triggered
|
||||||
|
self.logger = mainLogger.getChild(f"{self.hugvey.id}").getChild("story")
|
||||||
self.currentMessage = None
|
self.currentMessage = None
|
||||||
self.currentDiversion = None
|
self.currentDiversion = None
|
||||||
self.currentReply = None
|
self.currentReply = None
|
||||||
|
@ -534,11 +537,11 @@ class Story(object):
|
||||||
self.variables = {}
|
self.variables = {}
|
||||||
|
|
||||||
def pause(self):
|
def pause(self):
|
||||||
logger.debug('pause hugvey')
|
self.logger.debug('pause hugvey')
|
||||||
self.timer.pause()
|
self.timer.pause()
|
||||||
|
|
||||||
def resume(self):
|
def resume(self):
|
||||||
logger.debug('resume hugvey')
|
self.logger.debug('resume hugvey')
|
||||||
self.timer.resume()
|
self.timer.resume()
|
||||||
|
|
||||||
def getLogSummary(self):
|
def getLogSummary(self):
|
||||||
|
@ -559,7 +562,7 @@ class Story(object):
|
||||||
|
|
||||||
def setVariableValue(self, name, value):
|
def setVariableValue(self, name, value):
|
||||||
if name not in self.variables:
|
if name not in self.variables:
|
||||||
logger.warn(f"Set variable that is not needed in the story: {name}")
|
self.logger.warn(f"Set variable that is not needed in the story: {name}")
|
||||||
self.variableValues[name] = value
|
self.variableValues[name] = value
|
||||||
|
|
||||||
for message in self.variables[name]:
|
for message in self.variables[name]:
|
||||||
|
@ -586,18 +589,18 @@ class Story(object):
|
||||||
obj = className.initFromJson(el, self)
|
obj = className.initFromJson(el, self)
|
||||||
self.add(obj)
|
self.add(obj)
|
||||||
|
|
||||||
logger.debug(self.elements)
|
self.logger.debug(self.elements)
|
||||||
logger.debug(self.directionsPerMsg)
|
self.logger.debug(self.directionsPerMsg)
|
||||||
|
|
||||||
self.diversions = [el for el in self.elements.values() if type(el) == Diversion]
|
self.diversions = [el for el in self.elements.values() if type(el) == Diversion]
|
||||||
|
|
||||||
if currentId:
|
if currentId:
|
||||||
self.currentMessage = self.get(currentId)
|
self.currentMessage = self.get(currentId)
|
||||||
if self.currentMessage:
|
if self.currentMessage:
|
||||||
logger.info(
|
self.logger.info(
|
||||||
f"Reinstantiated current message: {self.currentMessage.id}")
|
f"Reinstantiated current message: {self.currentMessage.id}")
|
||||||
else:
|
else:
|
||||||
logger.warn(
|
self.logger.warn(
|
||||||
"Could not reinstatiate current message. Starting over")
|
"Could not reinstatiate current message. Starting over")
|
||||||
|
|
||||||
# Register variables
|
# Register variables
|
||||||
|
@ -610,7 +613,7 @@ class Story(object):
|
||||||
self.registerVariable(var, msg)
|
self.registerVariable(var, msg)
|
||||||
|
|
||||||
|
|
||||||
logger.info(f'has variables: {self.variables}')
|
self.logger.info(f'has variables: {self.variables}')
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
self.timer.reset()
|
self.timer.reset()
|
||||||
|
@ -672,7 +675,7 @@ class Story(object):
|
||||||
return [el for el in self.elements.values() if type(el) == Message]
|
return [el for el in self.elements.values() if type(el) == Message]
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
logger.info("Stop Story")
|
self.logger.info("Stop Story")
|
||||||
if self.isRunning:
|
if self.isRunning:
|
||||||
self.isRunning = False
|
self.isRunning = False
|
||||||
|
|
||||||
|
@ -681,7 +684,7 @@ class Story(object):
|
||||||
nr = len(self.events)
|
nr = len(self.events)
|
||||||
for i in range(nr):
|
for i in range(nr):
|
||||||
e = self.events.pop(0)
|
e = self.events.pop(0)
|
||||||
logger.info("handle '{}'".format(e))
|
self.logger.debug("handle '{}'".format(e))
|
||||||
if e['event'] == "exit":
|
if e['event'] == "exit":
|
||||||
self.stop()
|
self.stop()
|
||||||
if e['event'] == 'connect':
|
if e['event'] == 'connect':
|
||||||
|
@ -697,16 +700,16 @@ class Story(object):
|
||||||
|
|
||||||
# 2019-02-22 temporary disable listening while playing audio:
|
# 2019-02-22 temporary disable listening while playing audio:
|
||||||
# if self.hugvey.google is not None:
|
# if self.hugvey.google is not None:
|
||||||
# logger.warn("Temporary 'fix' -> resume recording?")
|
# self.logger.warn("Temporary 'fix' -> resume recording?")
|
||||||
# self.hugvey.google.resume()
|
# self.hugvey.google.resume()
|
||||||
|
|
||||||
if self.currentMessage.id not in self.directionsPerMsg:
|
if self.currentMessage.id not in self.directionsPerMsg:
|
||||||
if self.currentDiversion is not None:
|
if self.currentDiversion is not None:
|
||||||
logger.info("end of diversion")
|
self.logger.info("end of diversion")
|
||||||
await self.currentDiversion.finalise(self)
|
await self.currentDiversion.finalise(self)
|
||||||
self.currentDiversion = None
|
self.currentDiversion = None
|
||||||
else:
|
else:
|
||||||
logger.info("THE END!")
|
self.logger.info("THE END!")
|
||||||
self.stop()
|
self.stop()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -719,7 +722,7 @@ class Story(object):
|
||||||
timeDiff = self.timer.getElapsed() - self.previousReply.forMessage.getFinishedTime()
|
timeDiff = self.timer.getElapsed() - self.previousReply.forMessage.getFinishedTime()
|
||||||
if self.previousReply.forMessage.afterrunTime > timeDiff:
|
if self.previousReply.forMessage.afterrunTime > timeDiff:
|
||||||
#interrupt only in given interval:
|
#interrupt only in given interval:
|
||||||
logger.warn("Interrupt message, replay {}".format(self.previousReply.forMessage.id))
|
self.logger.warn("Interrupt message, replay {}".format(self.previousReply.forMessage.id))
|
||||||
self.currentReply = self.previousReply
|
self.currentReply = self.previousReply
|
||||||
self.previousReply.forMessage.interruptCount += 1
|
self.previousReply.forMessage.interruptCount += 1
|
||||||
self.currentMessage = await self.setCurrentMessage(self.previousReply.forMessage, self.previousReply)
|
self.currentMessage = await self.setCurrentMessage(self.previousReply.forMessage, self.previousReply)
|
||||||
|
@ -727,6 +730,7 @@ class Story(object):
|
||||||
# log if somebody starts speaking
|
# log if somebody starts speaking
|
||||||
# TODO: implement interrupt
|
# TODO: implement interrupt
|
||||||
if self.currentReply is None:
|
if self.currentReply is None:
|
||||||
|
self.logger.info("Start speaking")
|
||||||
self.currentReply= Reply(self.currentMessage)
|
self.currentReply= Reply(self.currentMessage)
|
||||||
|
|
||||||
utterance = self.currentReply.getActiveUtterance(self.timer.getElapsed())
|
utterance = self.currentReply.getActiveUtterance(self.timer.getElapsed())
|
||||||
|
@ -741,7 +745,7 @@ class Story(object):
|
||||||
for direction in directions:
|
for direction in directions:
|
||||||
for condition in direction.conditions:
|
for condition in direction.conditions:
|
||||||
if condition.isMet(self):
|
if condition.isMet(self):
|
||||||
logger.info("Condition is met: {0}, going to {1}".format(
|
self.logger.info("Condition is met: {0}, going to {1}".format(
|
||||||
condition.id, direction.msgTo.id))
|
condition.id, direction.msgTo.id))
|
||||||
direction.setMetCondition(condition)
|
direction.setMetCondition(condition)
|
||||||
self.addToLog(condition)
|
self.addToLog(condition)
|
||||||
|
@ -772,7 +776,7 @@ class Story(object):
|
||||||
"""
|
"""
|
||||||
loopDuration = 0.1 # Configure fps
|
loopDuration = 0.1 # Configure fps
|
||||||
lastTime = time.time()
|
lastTime = time.time()
|
||||||
logger.info("Start renderer")
|
self.logger.debug("Start renderer")
|
||||||
while self.isRunning:
|
while self.isRunning:
|
||||||
if self.isRunning is False:
|
if self.isRunning is False:
|
||||||
break
|
break
|
||||||
|
@ -797,14 +801,14 @@ class Story(object):
|
||||||
await asyncio.sleep(max(0, loopDuration - (t - lastTime)))
|
await asyncio.sleep(max(0, loopDuration - (t - lastTime)))
|
||||||
lastTime = t
|
lastTime = t
|
||||||
|
|
||||||
logger.info("Stop renderer")
|
self.logger.debug("Stop renderer")
|
||||||
|
|
||||||
async def setCurrentMessage(self, message, useReply = None):
|
async def setCurrentMessage(self, message, useReply = None):
|
||||||
"""
|
"""
|
||||||
Use Reply allows to pre-initiate a reply to use with the message. This is used eg. when doing an interruption.
|
Use Reply allows to pre-initiate a reply to use with the message. This is used eg. when doing an interruption.
|
||||||
"""
|
"""
|
||||||
if self.currentMessage and not self.lastMsgFinishTime:
|
if self.currentMessage and not self.lastMsgFinishTime:
|
||||||
logger.info("Interrupt playback {}".format(self.currentMessage.id))
|
self.logger.info("Interrupt playback {}".format(self.currentMessage.id))
|
||||||
# message is playing
|
# message is playing
|
||||||
self.hugvey.sendCommand({
|
self.hugvey.sendCommand({
|
||||||
'action': 'stop',
|
'action': 'stop',
|
||||||
|
@ -823,7 +827,7 @@ class Story(object):
|
||||||
# self.previousReply = self.currentReply # we can use this for interrptions
|
# self.previousReply = self.currentReply # we can use this for interrptions
|
||||||
# self.currentReply = self.currentMessage.reply
|
# self.currentReply = self.currentMessage.reply
|
||||||
|
|
||||||
logger.info("Current message: ({0}) \"{1}\"".format(
|
self.logger.info("Current message: ({0}) \"{1}\"".format(
|
||||||
message.id, message.text))
|
message.id, message.text))
|
||||||
self.addToLog(message)
|
self.addToLog(message)
|
||||||
# TODO: prep events & timer etc.
|
# TODO: prep events & timer etc.
|
||||||
|
@ -837,14 +841,14 @@ class Story(object):
|
||||||
|
|
||||||
# 2019-02-22 temporary disable listening while playing audio:
|
# 2019-02-22 temporary disable listening while playing audio:
|
||||||
# if self.hugvey.google is not None:
|
# if self.hugvey.google is not None:
|
||||||
# logger.warn("Temporary 'fix' -> stop recording")
|
# self.logger.warn("Temporary 'fix' -> stop recording")
|
||||||
# self.hugvey.google.pause()
|
# self.hugvey.google.pause()
|
||||||
|
|
||||||
logger.debug("Pending directions: ")
|
self.logger.debug("Pending directions: ")
|
||||||
|
|
||||||
for direction in self.getCurrentDirections():
|
for direction in self.getCurrentDirections():
|
||||||
conditions = [c.id for c in direction.conditions]
|
conditions = [c.id for c in direction.conditions]
|
||||||
logger.debug(
|
self.logger.debug(
|
||||||
"- {0} -> {1} (when: {2}) ".format(direction.msgFrom.id, direction.msgTo.id, conditions))
|
"- {0} -> {1} (when: {2}) ".format(direction.msgFrom.id, direction.msgTo.id, conditions))
|
||||||
|
|
||||||
def getCurrentDirections(self):
|
def getCurrentDirections(self):
|
||||||
|
@ -854,7 +858,7 @@ class Story(object):
|
||||||
return self.directionsPerMsg[self.currentMessage.id]
|
return self.directionsPerMsg[self.currentMessage.id]
|
||||||
|
|
||||||
async def run(self, customStartMsgId = None):
|
async def run(self, customStartMsgId = None):
|
||||||
logger.info("Starting story")
|
self.logger.info("Starting story")
|
||||||
self.timer.reset()
|
self.timer.reset()
|
||||||
self.isRunning = True
|
self.isRunning = True
|
||||||
if customStartMsgId is not None:
|
if customStartMsgId is not None:
|
||||||
|
@ -871,7 +875,7 @@ class Story(object):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def finish(self):
|
def finish(self):
|
||||||
logger.info(f"Finished story for {self.hugvey.id}")
|
self.logger.info(f"Finished story for {self.hugvey.id}")
|
||||||
self.hugvey.pause()
|
self.hugvey.pause()
|
||||||
self.finish_time = time.time()
|
self.finish_time = time.time()
|
||||||
self.timer.pause()
|
self.timer.pause()
|
||||||
|
|
|
@ -8,7 +8,8 @@ from hashlib import sha1
|
||||||
import asyncio
|
import asyncio
|
||||||
from tornado.httpclient import AsyncHTTPClient, HTTPRequest
|
from tornado.httpclient import AsyncHTTPClient, HTTPRequest
|
||||||
|
|
||||||
logger = logging.getLogger("voice")
|
mainLogger = logging.getLogger("hugvey")
|
||||||
|
logger = mainLogger.getChild("voice")
|
||||||
|
|
||||||
class VoiceStorage(object):
|
class VoiceStorage(object):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -38,6 +38,12 @@ if __name__ == '__main__':
|
||||||
fmt="%(asctime)s %(hostname)s %(name)s[%(process)d,%(threadName)s] %(levelname)s %(message)s"
|
fmt="%(asctime)s %(hostname)s %(name)s[%(process)d,%(threadName)s] %(levelname)s %(message)s"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
logger = logging.getLogger("hugvey")
|
||||||
|
# logger.setLevel(1) # to send all records to cutelog
|
||||||
|
socket_handler = logging.handlers.SocketHandler('127.0.0.1', 19996) # default listening address
|
||||||
|
logger.addHandler(socket_handler);
|
||||||
|
logger.info("Start server")
|
||||||
|
|
||||||
command = CentralCommand(args=args, debug_mode=args.verbose > 0)
|
command = CentralCommand(args=args, debug_mode=args.verbose > 0)
|
||||||
command.loadConfig(args.config)
|
command.loadConfig(args.config)
|
||||||
command.start()
|
command.start()
|
||||||
|
|
Loading…
Reference in a new issue