Pitch modifier for story configuration
This commit is contained in:
parent
7c7fcf071a
commit
ac11645dd0
2 changed files with 112 additions and 92 deletions
160
hugvey/story.py
160
hugvey/story.py
|
@ -25,8 +25,10 @@ from .communication import LOG_BS
|
||||||
mainLogger = logging.getLogger("hugvey")
|
mainLogger = logging.getLogger("hugvey")
|
||||||
logger = mainLogger.getChild("narrative")
|
logger = mainLogger.getChild("narrative")
|
||||||
|
|
||||||
|
|
||||||
class Utterance(object):
|
class Utterance(object):
|
||||||
"""Part of a reply"""
|
"""Part of a reply"""
|
||||||
|
|
||||||
def __init__(self, startTime):
|
def __init__(self, startTime):
|
||||||
self.startTime = startTime
|
self.startTime = startTime
|
||||||
self.endTime = None
|
self.endTime = None
|
||||||
|
@ -34,9 +36,9 @@ class Utterance(object):
|
||||||
self.lastUpdateTime = startTime
|
self.lastUpdateTime = startTime
|
||||||
|
|
||||||
def setText(self, text, now):
|
def setText(self, text, now):
|
||||||
self.text = text.lower() # always lowercase
|
self.text = text.lower() # always lowercase
|
||||||
self.lastUpdateTime = now
|
self.lastUpdateTime = now
|
||||||
|
|
||||||
def hasText(self):
|
def hasText(self):
|
||||||
return len(self.text) > 0
|
return len(self.text) > 0
|
||||||
|
|
||||||
|
@ -77,7 +79,7 @@ class Message(object):
|
||||||
self.lightChange = None
|
self.lightChange = None
|
||||||
self.didRepeat = False
|
self.didRepeat = False
|
||||||
self.fileError = False
|
self.fileError = False
|
||||||
|
|
||||||
# Used by diversions, autogenerated directions should link to next chapter mark instead of the given msgTo
|
# Used by diversions, autogenerated directions should link to next chapter mark instead of the given msgTo
|
||||||
self.generatedDirectionsJumpToChapter = False
|
self.generatedDirectionsJumpToChapter = False
|
||||||
|
|
||||||
|
@ -151,7 +153,7 @@ class Message(object):
|
||||||
# if not None in self.variableValues.values():
|
# if not None in self.variableValues.values():
|
||||||
# self.logger.warn(f"now fetch {name} for {self.id}")
|
# self.logger.warn(f"now fetch {name} for {self.id}")
|
||||||
# asyncio.get_event_loop().create_task(self.getAudioFilePath())
|
# asyncio.get_event_loop().create_task(self.getAudioFilePath())
|
||||||
|
|
||||||
def getVariableValue(self, var):
|
def getVariableValue(self, var):
|
||||||
return self.variableValues[var] if (self.variableValues[var] is not None) else self.story.configuration.nothing_text #TODO: translate nothing to each language
|
return self.variableValues[var] if (self.variableValues[var] is not None) else self.story.configuration.nothing_text #TODO: translate nothing to each language
|
||||||
|
|
||||||
|
@ -173,7 +175,7 @@ class Message(object):
|
||||||
if self.label and len(self.label):
|
if self.label and len(self.label):
|
||||||
return self.label
|
return self.label
|
||||||
return self.getText()
|
return self.getText()
|
||||||
|
|
||||||
def getTextLabel(self):
|
def getTextLabel(self):
|
||||||
"""
|
"""
|
||||||
A combination of getText and getLabel for maximum verbosity
|
A combination of getText and getLabel for maximum verbosity
|
||||||
|
@ -236,8 +238,8 @@ class Message(object):
|
||||||
await s.send_json(info)
|
await s.send_json(info)
|
||||||
filename = await s.recv_string()
|
filename = await s.recv_string()
|
||||||
s.close()
|
s.close()
|
||||||
|
|
||||||
# TODO: should this go trough the event Queue? risking a too long delay though
|
# TODO: should this go trough the event Queue? risking a too long delay though
|
||||||
if filename == 'local/crash.wav' or len(filename) < 1:
|
if filename == 'local/crash.wav' or len(filename) < 1:
|
||||||
self.logger.warning("Noting crash")
|
self.logger.warning("Noting crash")
|
||||||
self.fileError = True
|
self.fileError = True
|
||||||
|
@ -246,7 +248,7 @@ class Message(object):
|
||||||
|
|
||||||
self.logger.debug(f"Fetched audio for {textlabel}: {filename}")
|
self.logger.debug(f"Fetched audio for {textlabel}: {filename}")
|
||||||
return filename
|
return filename
|
||||||
|
|
||||||
|
|
||||||
class Reply(object):
|
class Reply(object):
|
||||||
def __init__(self, message: Message):
|
def __init__(self, message: Message):
|
||||||
|
@ -373,7 +375,7 @@ class Condition(object):
|
||||||
|
|
||||||
if 'vars' in data:
|
if 'vars' in data:
|
||||||
condition.vars = data['vars']
|
condition.vars = data['vars']
|
||||||
|
|
||||||
if 'regex' in condition.vars:
|
if 'regex' in condition.vars:
|
||||||
condition.vars['regex'] = condition.vars['regex'].rstrip()
|
condition.vars['regex'] = condition.vars['regex'].rstrip()
|
||||||
|
|
||||||
|
@ -435,7 +437,7 @@ class Condition(object):
|
||||||
self.vars['variable']
|
self.vars['variable']
|
||||||
)
|
)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def _hasTimer(self, story) -> bool:
|
def _hasTimer(self, story) -> bool:
|
||||||
if not story.lastMsgFinishTime:
|
if not story.lastMsgFinishTime:
|
||||||
return False
|
return False
|
||||||
|
@ -443,7 +445,7 @@ class Condition(object):
|
||||||
loopTime = story.hugvey.command.timer.getElapsed() % 3600
|
loopTime = story.hugvey.command.timer.getElapsed() % 3600
|
||||||
ltTime = int(self.vars['less_than'])
|
ltTime = int(self.vars['less_than'])
|
||||||
gtTime = int(self.vars['more_than'])
|
gtTime = int(self.vars['more_than'])
|
||||||
|
|
||||||
if not ltTime and not gtTime:
|
if not ltTime and not gtTime:
|
||||||
# ignore invalid times
|
# ignore invalid times
|
||||||
return
|
return
|
||||||
|
@ -455,21 +457,21 @@ class Condition(object):
|
||||||
r = True
|
r = True
|
||||||
else:
|
else:
|
||||||
r = False
|
r = False
|
||||||
|
|
||||||
if 'inverseMatch' in self.vars and self.vars['inverseMatch']:
|
if 'inverseMatch' in self.vars and self.vars['inverseMatch']:
|
||||||
r = not r
|
r = not r
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
self.logInfo = "Looptime is {} {} < {} < {}".format(
|
self.logInfo = "Looptime is {} {} < {} < {}".format(
|
||||||
'' if r else 'not',
|
'' if r else 'not',
|
||||||
f'{gtTime}' if gtTime else '-',
|
f'{gtTime}' if gtTime else '-',
|
||||||
loopTime,
|
loopTime,
|
||||||
f'{ltTime}' if ltTime else '-',
|
f'{ltTime}' if ltTime else '-',
|
||||||
)
|
)
|
||||||
|
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def _variableEquals(self, story) -> bool:
|
def _variableEquals(self, story) -> bool:
|
||||||
v1 = story.variableValues[self.vars['variable1']] if story.hasVariableSet(self.vars['variable1']) else None
|
v1 = story.variableValues[self.vars['variable1']] if story.hasVariableSet(self.vars['variable1']) else None
|
||||||
v2 = story.variableValues[self.vars['variable2']] if story.hasVariableSet(self.vars['variable2']) else None
|
v2 = story.variableValues[self.vars['variable2']] if story.hasVariableSet(self.vars['variable2']) else None
|
||||||
|
@ -483,10 +485,10 @@ class Condition(object):
|
||||||
r = (v1 != v2)
|
r = (v1 != v2)
|
||||||
else:
|
else:
|
||||||
r = (v1 == v2)
|
r = (v1 == v2)
|
||||||
|
|
||||||
story.logger.info("'{}' {} '{}' ({})".format(v1, '==' if v1 == v2 else '!=', v2, r))
|
story.logger.info("'{}' {} '{}' ({})".format(v1, '==' if v1 == v2 else '!=', v2, r))
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def _hasDiverged(self, story) -> bool:
|
def _hasDiverged(self, story) -> bool:
|
||||||
if not story.lastMsgFinishTime:
|
if not story.lastMsgFinishTime:
|
||||||
return False
|
return False
|
||||||
|
@ -509,15 +511,15 @@ class Condition(object):
|
||||||
)
|
)
|
||||||
|
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def _hasAudioError(self, story) -> bool:
|
def _hasAudioError(self, story) -> bool:
|
||||||
if not story.currentMessage or not story.currentMessage.fileError:
|
if not story.currentMessage or not story.currentMessage.fileError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.logInfo = f"Has error loading audio file for {story.currentMessage.id}"
|
self.logInfo = f"Has error loading audio file for {story.currentMessage.id}"
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _hasPlayed(self, story) -> bool:
|
def _hasPlayed(self, story) -> bool:
|
||||||
if not story.lastMsgFinishTime:
|
if not story.lastMsgFinishTime:
|
||||||
return False
|
return False
|
||||||
|
@ -547,12 +549,12 @@ class Condition(object):
|
||||||
)
|
)
|
||||||
|
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
def _hasVariableStorage(self, story) -> bool:
|
def _hasVariableStorage(self, story) -> bool:
|
||||||
if not story.lastMsgFinishTime:
|
if not story.lastMsgFinishTime:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if self.hasRan:
|
if self.hasRan:
|
||||||
# Prevent multiple runs of the same query within eg. waiting for a timeout.
|
# Prevent multiple runs of the same query within eg. waiting for a timeout.
|
||||||
return False
|
return False
|
||||||
|
@ -561,11 +563,11 @@ class Condition(object):
|
||||||
unique = bool(self.vars['unique']) if 'unique' in self.vars else False
|
unique = bool(self.vars['unique']) if 'unique' in self.vars else False
|
||||||
varValues = story.hugvey.command.variableStore.getLastOfName(self.vars['var_name'], story.language_code, number, unique)
|
varValues = story.hugvey.command.variableStore.getLastOfName(self.vars['var_name'], story.language_code, number, unique)
|
||||||
self.hasRan = True
|
self.hasRan = True
|
||||||
|
|
||||||
if len(varValues) < number:
|
if len(varValues) < number:
|
||||||
story.logger.warn(f"{self.id}: Too few instances of {self.vars['var_name']}, only {len(varValues)} in store")
|
story.logger.warn(f"{self.id}: Too few instances of {self.vars['var_name']}, only {len(varValues)} in store")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
for i in range(number):
|
for i in range(number):
|
||||||
story.setVariableValue(
|
story.setVariableValue(
|
||||||
f"stored_{self.vars['var_name']}_{i+1}",
|
f"stored_{self.vars['var_name']}_{i+1}",
|
||||||
|
@ -574,7 +576,7 @@ class Condition(object):
|
||||||
)
|
)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _hasMetReplyContains(self, story) -> bool:
|
def _hasMetReplyContains(self, story) -> bool:
|
||||||
"""
|
"""
|
||||||
Check the reply for specific characteristics:
|
Check the reply for specific characteristics:
|
||||||
|
@ -789,15 +791,15 @@ class Diversion(object):
|
||||||
if self.type != 'repeat' and self.type !='interrupt':
|
if self.type != 'repeat' and self.type !='interrupt':
|
||||||
# repeat diversion should be usable infinte times
|
# repeat diversion should be usable infinte times
|
||||||
self.hasHit = True
|
self.hasHit = True
|
||||||
|
|
||||||
story.addToLog(self)
|
story.addToLog(self)
|
||||||
story.hugvey.eventLogger.info(f"diverge {self.id}")
|
story.hugvey.eventLogger.info(f"diverge {self.id}")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
story.logger.critical("Exception when attempting diversion")
|
story.logger.critical("Exception when attempting diversion")
|
||||||
story.logger.exception(e)
|
story.logger.exception(e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def createReturnDirectionsTo(self, story, startMsg, returnMsg, originalDirection = None, inheritTiming = True, timeoutDuration = .5, replyContainsDurations = None):
|
def createReturnDirectionsTo(self, story, startMsg, returnMsg, originalDirection = None, inheritTiming = True, timeoutDuration = .5, replyContainsDurations = None):
|
||||||
|
@ -840,11 +842,11 @@ class Diversion(object):
|
||||||
msg = story.get(msgId)
|
msg = story.get(msgId)
|
||||||
if not msg:
|
if not msg:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
usedReturnMessage = returnMsg
|
usedReturnMessage = returnMsg
|
||||||
if msg.generatedDirectionsJumpToChapter:
|
if msg.generatedDirectionsJumpToChapter:
|
||||||
usedReturnMessage = story.getNextChapterForMsg(returnMsg, canIncludeSelf=True)
|
usedReturnMessage = story.getNextChapterForMsg(returnMsg, canIncludeSelf=True)
|
||||||
|
|
||||||
if not usedReturnMessage:
|
if not usedReturnMessage:
|
||||||
# in case of a diversion in the last bit of the story, it can be there there is no return message.
|
# in case of a diversion in the last bit of the story, it can be there there is no return message.
|
||||||
raise Exception(f"No return message found for {msg.id}")
|
raise Exception(f"No return message found for {msg.id}")
|
||||||
|
@ -885,7 +887,7 @@ class Diversion(object):
|
||||||
story.add(condition2)
|
story.add(condition2)
|
||||||
|
|
||||||
direction.isDiversionReturn = True # will clear the currentDiversion on story
|
direction.isDiversionReturn = True # will clear the currentDiversion on story
|
||||||
story.diversionDirections.append(direction)
|
story.diversionDirections.append(direction)
|
||||||
story.logger.info(f"Created direction: {direction.id} ({msg.id} -> {usedReturnMessage.id}) {condition.id} with timeout {finalTimeoutDuration}s")
|
story.logger.info(f"Created direction: {direction.id} ({msg.id} -> {usedReturnMessage.id}) {condition.id} with timeout {finalTimeoutDuration}s")
|
||||||
story.add(condition)
|
story.add(condition)
|
||||||
story.add(direction)
|
story.add(direction)
|
||||||
|
@ -962,7 +964,7 @@ class Diversion(object):
|
||||||
if not direction:
|
if not direction:
|
||||||
# ignore the direction argument, and only check if the current message has a valid default
|
# ignore the direction argument, and only check if the current message has a valid default
|
||||||
return
|
return
|
||||||
|
|
||||||
waitTime = story.applyTimeFactor(1.8 if 'waitTime' not in self.params else float(self.params['waitTime']))
|
waitTime = story.applyTimeFactor(1.8 if 'waitTime' not in self.params else float(self.params['waitTime']))
|
||||||
timeSince = story.currentReply.getTimeSinceLastUtterance()
|
timeSince = story.currentReply.getTimeSinceLastUtterance()
|
||||||
if timeSince < waitTime:
|
if timeSince < waitTime:
|
||||||
|
@ -986,7 +988,7 @@ class Diversion(object):
|
||||||
story.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
|
||||||
|
|
||||||
|
|
||||||
if 'nextChapterOnReturn' in self.params and self.params['nextChapterOnReturn']:
|
if 'nextChapterOnReturn' in self.params and self.params['nextChapterOnReturn']:
|
||||||
msgTo = story.getNextChapterForMsg(story.currentMessage, False) or direction.msgTo
|
msgTo = story.getNextChapterForMsg(story.currentMessage, False) or direction.msgTo
|
||||||
returnInheritTiming = False
|
returnInheritTiming = False
|
||||||
|
@ -1014,33 +1016,33 @@ class Diversion(object):
|
||||||
#: :var story: Story
|
#: :var story: Story
|
||||||
if story.currentDiversion or not msgFrom or not msgTo:
|
if story.currentDiversion or not msgFrom or not msgTo:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if not msgTo.chapterStart:
|
if not msgTo.chapterStart:
|
||||||
# only when changing chapter
|
# only when changing chapter
|
||||||
return
|
return
|
||||||
|
|
||||||
window_open_second = float(self.params['start_second'])
|
window_open_second = float(self.params['start_second'])
|
||||||
window_close_second = window_open_second + float(self.params['window'])
|
window_close_second = window_open_second + float(self.params['window'])
|
||||||
|
|
||||||
# Only keep a 1h loop
|
# Only keep a 1h loop
|
||||||
now = story.hugvey.command.timer.getElapsed() % 3600
|
now = story.hugvey.command.timer.getElapsed() % 3600
|
||||||
if now < window_open_second or now > window_close_second:
|
if now < window_open_second or now > window_close_second:
|
||||||
return
|
return
|
||||||
|
|
||||||
#open!
|
#open!
|
||||||
msg = story.get(self.params['msgId'])
|
msg = story.get(self.params['msgId'])
|
||||||
if msg is None:
|
if msg is None:
|
||||||
story.logger.critical(f"Not a valid message id for diversion: {self.id} {self.params['msgId']}")
|
story.logger.critical(f"Not a valid message id for diversion: {self.id} {self.params['msgId']}")
|
||||||
return
|
return
|
||||||
|
|
||||||
self.returnMessage = msgTo
|
self.returnMessage = msgTo
|
||||||
|
|
||||||
self.createReturnDirectionsTo(story, msg, msgTo, direction, inheritTiming=True)
|
self.createReturnDirectionsTo(story, msg, msgTo, direction, inheritTiming=True)
|
||||||
|
|
||||||
await story.setCurrentMessage(msg)
|
await story.setCurrentMessage(msg)
|
||||||
story.currentDiversion = self
|
story.currentDiversion = self
|
||||||
return True
|
return True
|
||||||
|
|
||||||
async def _divergeIfRepeatRequest(self, story, msgFrom, msgTo, direction):
|
async def _divergeIfRepeatRequest(self, story, msgFrom, msgTo, direction):
|
||||||
"""
|
"""
|
||||||
Participant asks if message can be repeated.
|
Participant asks if message can be repeated.
|
||||||
|
@ -1052,7 +1054,7 @@ class Diversion(object):
|
||||||
# Perhaps set isFinished when matching condition.
|
# Perhaps set isFinished when matching condition.
|
||||||
if story.currentReply is None or story.currentReply.getTimeSinceLastUtterance() < story.applyTimeFactor(1.8):
|
if story.currentReply is None or story.currentReply.getTimeSinceLastUtterance() < story.applyTimeFactor(1.8):
|
||||||
return
|
return
|
||||||
|
|
||||||
if story.currentMessage.didRepeat:
|
if story.currentMessage.didRepeat:
|
||||||
# repeat only once
|
# repeat only once
|
||||||
return
|
return
|
||||||
|
@ -1151,7 +1153,6 @@ class Diversion(object):
|
||||||
async def _returnAfterTimeout(self, story):
|
async def _returnAfterTimeout(self, story):
|
||||||
story.logger.info(f"Finalise diversion: {self.id}")
|
story.logger.info(f"Finalise diversion: {self.id}")
|
||||||
|
|
||||||
|
|
||||||
async def _divergeIfInterrupted(self, story, msgFrom, msgTo, direction):
|
async def _divergeIfInterrupted(self, story, msgFrom, msgTo, direction):
|
||||||
"""
|
"""
|
||||||
This is here as a placeholder for the interruption diversion.
|
This is here as a placeholder for the interruption diversion.
|
||||||
|
@ -1177,14 +1178,16 @@ class Diversion(object):
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
class Configuration(object):
|
class Configuration(object):
|
||||||
id = 'configuration'
|
id = 'configuration'
|
||||||
volume = 1 # Volume multiplier for 'play' command
|
volume = 1 # Volume multiplier for 'play' command
|
||||||
nothing_text = "nothing" # When variable is not set, but used in sentence, replace it with this word.
|
nothing_text = "nothing" # When variable is not set, but used in sentence, replace it with this word.
|
||||||
time_factor = 1
|
time_factor = 1 # time is multiplied to timeouts etc. (not playback)
|
||||||
tempo_factor = 1
|
tempo_factor = 1 # tempo is multiplied (playback)
|
||||||
|
pitch_modifier = 1 # pitch is added (playback)
|
||||||
light0_intensity = 0
|
light0_intensity = 0
|
||||||
light0_fade = 30. # fade duration in seconds
|
light0_fade = 30. # fade duration in seconds
|
||||||
light0_isSophie = False
|
light0_isSophie = False
|
||||||
light1_intensity = 150
|
light1_intensity = 150
|
||||||
light1_fade = 10.
|
light1_fade = 10.
|
||||||
|
@ -1210,7 +1213,7 @@ class Configuration(object):
|
||||||
l = []
|
l = []
|
||||||
for i in range(5):
|
for i in range(5):
|
||||||
l.append({
|
l.append({
|
||||||
'intensity': int(c[f"light{i}_intensity"]),
|
'intensity': int(c[f"light{i}_intensity"]),
|
||||||
'fade': float(c[f"light{i}_fade"]),
|
'fade': float(c[f"light{i}_fade"]),
|
||||||
'isSophie': float(c[f"light{i}_isSophie"])
|
'isSophie': float(c[f"light{i}_isSophie"])
|
||||||
})
|
})
|
||||||
|
@ -1396,13 +1399,13 @@ class Story(object):
|
||||||
def setVariableValue(self, name, value, store=True):
|
def setVariableValue(self, name, value, store=True):
|
||||||
if name not in self.variables:
|
if name not in self.variables:
|
||||||
self.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}")
|
||||||
|
|
||||||
if name in self.variableValues and self.variableValues[name] == value:
|
if name in self.variableValues and self.variableValues[name] == value:
|
||||||
self.logger.debug(f"Skip double setting of variable {name} to {value}")
|
self.logger.debug(f"Skip double setting of variable {name} to {value}")
|
||||||
return
|
return
|
||||||
|
|
||||||
self.logger.debug(f"Set variable {name} to {value}")
|
self.logger.debug(f"Set variable {name} to {value}")
|
||||||
|
|
||||||
self.variableValues[name] = value
|
self.variableValues[name] = value
|
||||||
if store:
|
if store:
|
||||||
self.hugvey.command.variableStore.addVariable(self.runId, name, value, self.hugvey.id, self.language_code)
|
self.hugvey.command.variableStore.addVariable(self.runId, name, value, self.hugvey.id, self.language_code)
|
||||||
|
@ -1604,7 +1607,7 @@ class Story(object):
|
||||||
if len(e['transcript'].strip()) < 1:
|
if len(e['transcript'].strip()) < 1:
|
||||||
self.logger.warning(f'ignore empty transcription {e}')
|
self.logger.warning(f'ignore empty transcription {e}')
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# participants speaks, reset counter
|
# participants speaks, reset counter
|
||||||
self.stats['consecutiveSilentTimeouts'] = 0
|
self.stats['consecutiveSilentTimeouts'] = 0
|
||||||
|
|
||||||
|
@ -1641,7 +1644,7 @@ class Story(object):
|
||||||
utterance.setText(e['transcript'], utterance.lastUpdateTime)
|
utterance.setText(e['transcript'], utterance.lastUpdateTime)
|
||||||
else:
|
else:
|
||||||
utterance.setText(e['transcript'], now)
|
utterance.setText(e['transcript'], now)
|
||||||
|
|
||||||
self.hugvey.eventLogger.debug("speaking: content {} \"{}\"".format(id(utterance), e['transcript']))
|
self.hugvey.eventLogger.debug("speaking: content {} \"{}\"".format(id(utterance), e['transcript']))
|
||||||
if not self.timer.hasMark('first_speech'):
|
if not self.timer.hasMark('first_speech'):
|
||||||
self.timer.setMark('first_speech')
|
self.timer.setMark('first_speech')
|
||||||
|
@ -1678,7 +1681,7 @@ class Story(object):
|
||||||
# back to a previous point in time.
|
# back to a previous point in time.
|
||||||
# self.logger.warn("Skipping double direction for diversion")
|
# self.logger.warn("Skipping double direction for diversion")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
condition = self._processDirection(direction)
|
condition = self._processDirection(direction)
|
||||||
if not condition:
|
if not condition:
|
||||||
continue
|
continue
|
||||||
|
@ -1688,7 +1691,7 @@ class Story(object):
|
||||||
chosenDirection = direction
|
chosenDirection = direction
|
||||||
metCondition = condition
|
metCondition = condition
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
isDiverging = await self._processDiversions(chosenDirection)
|
isDiverging = await self._processDiversions(chosenDirection)
|
||||||
|
|
||||||
|
@ -1706,12 +1709,12 @@ class Story(object):
|
||||||
if direction.isDiversionReturn and not direction.diversionHasReturned:
|
if direction.isDiversionReturn and not direction.diversionHasReturned:
|
||||||
self.logger.info(f"Mark diversion as returned for return direction {direction.id}")
|
self.logger.info(f"Mark diversion as returned for return direction {direction.id}")
|
||||||
direction.diversionHasReturned = True
|
direction.diversionHasReturned = True
|
||||||
|
|
||||||
# chosenDirection.diversionHasReturned = True
|
# chosenDirection.diversionHasReturned = True
|
||||||
await self.currentDiversion.finalise(self)
|
await self.currentDiversion.finalise(self)
|
||||||
|
|
||||||
await self.setCurrentMessage(chosenDirection.msgTo, allowReplyInterrupt=allowReplyInterrupt)
|
await self.setCurrentMessage(chosenDirection.msgTo, allowReplyInterrupt=allowReplyInterrupt)
|
||||||
|
|
||||||
|
|
||||||
return chosenDirection
|
return chosenDirection
|
||||||
|
|
||||||
|
@ -1782,22 +1785,22 @@ class Story(object):
|
||||||
|
|
||||||
def logHasMsg(self, node):
|
def logHasMsg(self, node):
|
||||||
return node in self.msgLog
|
return node in self.msgLog
|
||||||
|
|
||||||
def checkIfGone(self):
|
def checkIfGone(self):
|
||||||
'''
|
'''
|
||||||
Make a guestimation if the audience has left... just really a simple timer check.
|
Make a guestimation if the audience has left... just really a simple timer check.
|
||||||
|
|
||||||
If we do think so, give an error and stop the conversation
|
If we do think so, give an error and stop the conversation
|
||||||
'''
|
'''
|
||||||
if not self.lastMsgFinishTime:
|
if not self.lastMsgFinishTime:
|
||||||
# don't do it when hugvey is speaking
|
# don't do it when hugvey is speaking
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.timer.hasMark('last_speech') and self.timer.getElapsed('last_speech') > 30*60:
|
if self.timer.hasMark('last_speech') and self.timer.getElapsed('last_speech') > 30*60:
|
||||||
self.hugvey.eventLogger.warning("Audience is quiet for too long...stopping")
|
self.hugvey.eventLogger.warning("Audience is quiet for too long...stopping")
|
||||||
self.logger.warning("Audience is quiet, force END!")
|
self.logger.warning("Audience is quiet, force END!")
|
||||||
self._finish()
|
self._finish()
|
||||||
|
|
||||||
def checkIfHanging(self):
|
def checkIfHanging(self):
|
||||||
'''
|
'''
|
||||||
Make a guestimation if the story is hanging at a message. Raise exception once.
|
Make a guestimation if the story is hanging at a message. Raise exception once.
|
||||||
|
@ -1807,9 +1810,9 @@ class Story(object):
|
||||||
# or when it already gave the error for this message
|
# or when it already gave the error for this message
|
||||||
return
|
return
|
||||||
diff = self.timer.getElapsed() - self.lastMsgFinishTime
|
diff = self.timer.getElapsed() - self.lastMsgFinishTime
|
||||||
|
|
||||||
safeDiff = self.hugvey.command.config['story']['hugvey_critical_silence'] if 'hugvey_critical_silence' in self.hugvey.command.config['story'] else 90
|
safeDiff = self.hugvey.command.config['story']['hugvey_critical_silence'] if 'hugvey_critical_silence' in self.hugvey.command.config['story'] else 90
|
||||||
|
|
||||||
if diff > safeDiff:
|
if diff > safeDiff:
|
||||||
self.hugvey.eventLogger.warning("Hugvey is quiet for very long!")
|
self.hugvey.eventLogger.warning("Hugvey is quiet for very long!")
|
||||||
self.logger.critical("Hugvey is quiet for very long!") # critical messages are forwarded to telegram
|
self.logger.critical("Hugvey is quiet for very long!") # critical messages are forwarded to telegram
|
||||||
|
@ -1896,7 +1899,7 @@ class Story(object):
|
||||||
message.id, message.getTextLabel()))
|
message.id, message.getTextLabel()))
|
||||||
if message.id != self.startMessage.id:
|
if message.id != self.startMessage.id:
|
||||||
self.addToLog(message)
|
self.addToLog(message)
|
||||||
|
|
||||||
self.hugvey.eventLogger.info(f"message: {message.id} {message.uuid} start \"{message.getLabel()}\"")
|
self.hugvey.eventLogger.info(f"message: {message.id} {message.uuid} start \"{message.getLabel()}\"")
|
||||||
|
|
||||||
# TODO: prep events & timer etc.
|
# TODO: prep events & timer etc.
|
||||||
|
@ -1916,9 +1919,12 @@ class Story(object):
|
||||||
params['vol'] = "{:.4f}".format(params['vol'])
|
params['vol'] = "{:.4f}".format(params['vol'])
|
||||||
params['tempo'] = (float(params['tempo']) if 'tempo' in params else 1) * (float(self.configuration.tempo_factor) if hasattr(self.configuration, 'tempo_factor') else 1)
|
params['tempo'] = (float(params['tempo']) if 'tempo' in params else 1) * (float(self.configuration.tempo_factor) if hasattr(self.configuration, 'tempo_factor') else 1)
|
||||||
duration = float(duration) / params['tempo']
|
duration = float(duration) / params['tempo']
|
||||||
|
|
||||||
params['tempo'] = "{:.4f}".format(params['tempo'])
|
params['tempo'] = "{:.4f}".format(params['tempo'])
|
||||||
|
|
||||||
|
params['pitch'] = (float(params['pitch']) if 'pitch' in params else 0)\
|
||||||
|
+ (float(self.configuration.pitch_modifier) if hasattr(self.configuration, 'pitch_modifier') else 0)
|
||||||
|
params['pitch'] = "{:.4f}".format(params['pitch'])
|
||||||
|
|
||||||
# self.hugvey.google.pause() # pause STT to avoid text events while decision is made
|
# self.hugvey.google.pause() # pause STT to avoid text events while decision is made
|
||||||
self.hugvey.sendCommand({
|
self.hugvey.sendCommand({
|
||||||
'action': 'play',
|
'action': 'play',
|
||||||
|
@ -1927,7 +1933,7 @@ class Story(object):
|
||||||
'params': params,
|
'params': params,
|
||||||
'duration': duration
|
'duration': duration
|
||||||
})
|
})
|
||||||
|
|
||||||
if message.lightChange is not None:
|
if message.lightChange is not None:
|
||||||
self.fadeLightPreset(message.lightChange)
|
self.fadeLightPreset(message.lightChange)
|
||||||
# self.hugvey.setLightStatus(message.lightChange)
|
# self.hugvey.setLightStatus(message.lightChange)
|
||||||
|
@ -1944,18 +1950,18 @@ class Story(object):
|
||||||
logmsg += "\n- {0} -> {1} (when: {2}) ".format(direction.msgFrom.id, direction.msgTo.id, conditions)
|
logmsg += "\n- {0} -> {1} (when: {2}) ".format(direction.msgFrom.id, direction.msgTo.id, conditions)
|
||||||
|
|
||||||
self.logger.log(LOG_BS,logmsg)
|
self.logger.log(LOG_BS,logmsg)
|
||||||
|
|
||||||
# if message.id != self.startMessage.id:
|
# if message.id != self.startMessage.id:
|
||||||
# self.storeState()
|
# self.storeState()
|
||||||
|
|
||||||
def fadeLightPreset(self, presetNr: int):
|
def fadeLightPreset(self, presetNr: int):
|
||||||
if presetNr < 0 or presetNr > 4:
|
if presetNr < 0 or presetNr > 4:
|
||||||
self.logger.critical(f"Error parsing light fade preset code '{presetNr}'")
|
self.logger.critical(f"Error parsing light fade preset code '{presetNr}'")
|
||||||
return
|
return
|
||||||
|
|
||||||
preset = self.configuration.getLightPresets()[presetNr]
|
preset = self.configuration.getLightPresets()[presetNr]
|
||||||
self.currentLightPresetNr = presetNr
|
self.currentLightPresetNr = presetNr
|
||||||
|
|
||||||
self.hugvey.transitionLight(preset['intensity'], preset['fade'], preset['isSophie'])
|
self.hugvey.transitionLight(preset['intensity'], preset['fade'], preset['isSophie'])
|
||||||
|
|
||||||
def getCurrentDirections(self):
|
def getCurrentDirections(self):
|
||||||
|
@ -2039,7 +2045,7 @@ class Story(object):
|
||||||
if msgId in checked:
|
if msgId in checked:
|
||||||
# self.logger.log(LOG_BS, f"Finish for {msgId} already checked")
|
# self.logger.log(LOG_BS, f"Finish for {msgId} already checked")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
checked.append(msgId)
|
checked.append(msgId)
|
||||||
|
|
||||||
if not msgId in self.directionsPerMsg or len(self.directionsPerMsg[msgId]) < 1:
|
if not msgId in self.directionsPerMsg or len(self.directionsPerMsg[msgId]) < 1:
|
||||||
|
@ -2085,7 +2091,7 @@ class Story(object):
|
||||||
return self.strands[msg.id]
|
return self.strands[msg.id]
|
||||||
|
|
||||||
return self.calculateFinishesForMsg(msg.id, checked=[])
|
return self.calculateFinishesForMsg(msg.id, checked=[])
|
||||||
|
|
||||||
def applyTimeFactor(self, time) -> float:
|
def applyTimeFactor(self, time) -> float:
|
||||||
"""
|
"""
|
||||||
Apply the particularities of the configuration.time_factor
|
Apply the particularities of the configuration.time_factor
|
||||||
|
|
|
@ -190,18 +190,18 @@ class Panopticon {
|
||||||
if(this.hugveys.selectedId) {
|
if(this.hugveys.selectedId) {
|
||||||
this.updateSelectedHugvey();
|
this.updateSelectedHugvey();
|
||||||
}
|
}
|
||||||
|
|
||||||
let avail = 0;
|
let avail = 0;
|
||||||
let blocked = 0;
|
let blocked = 0;
|
||||||
for(let hv of this.hugveys.hugveys) {
|
for(let hv of this.hugveys.hugveys) {
|
||||||
if(hv.status =='available') avail ++;
|
if(hv.status =='available') avail ++;
|
||||||
if(hv.status =='blocked') blocked ++;
|
if(hv.status =='blocked') blocked ++;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.hugveys.blockedHugveys = blocked;
|
this.hugveys.blockedHugveys = blocked;
|
||||||
this.hugveys.availableHugveys = avail;
|
this.hugveys.availableHugveys = avail;
|
||||||
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'log':
|
case 'log':
|
||||||
|
@ -209,12 +209,12 @@ class Panopticon {
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
selectHugvey(hv_id) {
|
selectHugvey(hv_id) {
|
||||||
this.hugveys.selectedId = hv_id;
|
this.hugveys.selectedId = hv_id;
|
||||||
this.send({ action: 'selection', selected_id: hv_id });
|
this.send({ action: 'selection', selected_id: hv_id });
|
||||||
}
|
}
|
||||||
|
|
||||||
change_loop_time(newTime) {
|
change_loop_time(newTime) {
|
||||||
console.log('update', newTime);
|
console.log('update', newTime);
|
||||||
this.send({ action: 'loop_time', time: newTime });
|
this.send({ action: 'loop_time', time: newTime });
|
||||||
|
@ -288,7 +288,7 @@ class Panopticon {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.hugveys.selectedLang = code;
|
this.hugveys.selectedLang = code;
|
||||||
|
|
||||||
let req = new XMLHttpRequest();
|
let req = new XMLHttpRequest();
|
||||||
let graph = this.graph;
|
let graph = this.graph;
|
||||||
req.addEventListener( "load", function( e ) {
|
req.addEventListener( "load", function( e ) {
|
||||||
|
@ -392,7 +392,7 @@ class Graph {
|
||||||
graph.saveJson();
|
graph.saveJson();
|
||||||
el.classList.remove('loading');
|
el.classList.remove('loading');
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
} );
|
} );
|
||||||
document.getElementById( 'btn-addMsg' ).addEventListener( 'click', function( e ) { graph.createMsg(); } );
|
document.getElementById( 'btn-addMsg' ).addEventListener( 'click', function( e ) { graph.createMsg(); } );
|
||||||
document.getElementById( 'btn-diversions' ).addEventListener( 'click', function( e ) { graph.showDiversions(); } );
|
document.getElementById( 'btn-diversions' ).addEventListener( 'click', function( e ) { graph.showDiversions(); } );
|
||||||
|
@ -497,7 +497,7 @@ class Graph {
|
||||||
}
|
}
|
||||||
else if(type == 'repeat') {
|
else if(type == 'repeat') {
|
||||||
div['params']['regex'] = "can you repeat that\\?";
|
div['params']['regex'] = "can you repeat that\\?";
|
||||||
}
|
}
|
||||||
else if(type == 'collective_moment') {
|
else if(type == 'collective_moment') {
|
||||||
div['params']['start_second'] = 20 * 60; // second to start
|
div['params']['start_second'] = 20 * 60; // second to start
|
||||||
div['params']['window'] = 60; // how long to wait, in seconds
|
div['params']['window'] = 60; // how long to wait, in seconds
|
||||||
|
@ -1122,6 +1122,20 @@ class Graph {
|
||||||
'step': 0.01
|
'step': 0.01
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
|
crel(
|
||||||
|
'label',
|
||||||
|
"Playback pitch modifier: (< 0 is lower, >0 is higher)",
|
||||||
|
crel('input', {
|
||||||
|
'type': 'number',
|
||||||
|
'on': {
|
||||||
|
'change': function(e){
|
||||||
|
panopticon.graph.configuration['pitch_modifier'] = parseFloat(e.target.value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'value': this.configuration.hasOwnProperty('pitch_modifier') ? this.configuration.pitch_modifier : 0,
|
||||||
|
'step': 1
|
||||||
|
})
|
||||||
|
),
|
||||||
crel('hr'),
|
crel('hr'),
|
||||||
crel('h2', 'Light fade setting #0'),
|
crel('h2', 'Light fade setting #0'),
|
||||||
crel(
|
crel(
|
||||||
|
@ -1444,7 +1458,7 @@ class Graph {
|
||||||
"uploaded"
|
"uploaded"
|
||||||
) : 'Auto-generated')
|
) : 'Auto-generated')
|
||||||
);
|
);
|
||||||
|
|
||||||
let lightOptions = [
|
let lightOptions = [
|
||||||
crel("option", {'value': null}, "Do nothing")
|
crel("option", {'value': null}, "Do nothing")
|
||||||
];
|
];
|
||||||
|
@ -1463,18 +1477,18 @@ class Graph {
|
||||||
}
|
}
|
||||||
lightOptions.push(crel("option", l, `Fade preset #${i} (${intensity} in ${duration}s)`));
|
lightOptions.push(crel("option", l, `Fade preset #${i} (${intensity} in ${duration}s)`));
|
||||||
}
|
}
|
||||||
|
|
||||||
// let lightOptionNone = {'value': null}
|
// let lightOptionNone = {'value': null}
|
||||||
//
|
//
|
||||||
// let lightOptionOn = {'value': 1}
|
// let lightOptionOn = {'value': 1}
|
||||||
// let lightOptionOff = {'value': 0}
|
// let lightOptionOff = {'value': 0}
|
||||||
//
|
//
|
||||||
// if(msg.hasOwnProperty('light')) {
|
// if(msg.hasOwnProperty('light')) {
|
||||||
// if(msg['light'] === 1) lightOptionOn['selected'] = 'selected';
|
// if(msg['light'] === 1) lightOptionOn['selected'] = 'selected';
|
||||||
// if(msg['light'] === 0) lightOptionOff['selected'] = 'selected';
|
// if(msg['light'] === 0) lightOptionOff['selected'] = 'selected';
|
||||||
// if(msg['light'] === null) lightOptionNone['selected'] = 'selected';
|
// if(msg['light'] === null) lightOptionNone['selected'] = 'selected';
|
||||||
// }
|
// }
|
||||||
|
|
||||||
let msgInfoEl = crel( 'div', { 'class': 'msg__info' },
|
let msgInfoEl = crel( 'div', { 'class': 'msg__info' },
|
||||||
crel('div', {
|
crel('div', {
|
||||||
'class':'btn btn--delete btn--delete-msg',
|
'class':'btn btn--delete btn--delete-msg',
|
||||||
|
@ -1893,7 +1907,7 @@ class Graph {
|
||||||
if(attr.hasOwnProperty('description')) {
|
if(attr.hasOwnProperty('description')) {
|
||||||
inputs.push(crel('div', {'class':'description'}, attr['description']));
|
inputs.push(crel('div', {'class':'description'}, attr['description']));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return inputs;
|
return inputs;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue