Change for working version

This commit is contained in:
Hugvey Central Command 2019-05-12 19:51:54 +02:00
parent 90b63b24d2
commit b8b912a10a
3 changed files with 76 additions and 73 deletions

View file

@ -12,4 +12,4 @@ voice:
input_volume: 100 input_volume: 100
output_volume: 30 output_volume: 30
file_address: "http://hugveycmd.local:8888" file_address: "http://hugveycmd.local:8888"
output_driver: pulseaudio output_driver: null

View file

@ -40,8 +40,8 @@ class Utterance(object):
def isFinished(self): def isFinished(self):
return self.endTime is not None return self.endTime is not None
def __getstate__(self): def __getstate__(self):
# print(f'get utterance {self}') # print(f'get utterance {self}')
state = self.__dict__.copy() state = self.__dict__.copy()
@ -68,7 +68,7 @@ class Message(object):
self.parseForVariables() self.parseForVariables()
self.uuid = None # Have a unique id each time the message is played back. self.uuid = None # Have a unique id each time the message is played back.
self.color = None self.color = None
def __getstate__(self): def __getstate__(self):
# Copy the object's state from self.__dict__ which contains # Copy the object's state from self.__dict__ which contains
# all our instance attributes. Always use the dict.copy() # all our instance attributes. Always use the dict.copy()
@ -78,7 +78,7 @@ class Message(object):
# Remove the unpicklable entries. # Remove the unpicklable entries.
del state['filenameFetchLock'] del state['filenameFetchLock']
return state return state
def __setstate__(self, state): def __setstate__(self, state):
self.__dict__.update(state) self.__dict__.update(state)
self.filenameFetchLock = asyncio.Lock() self.filenameFetchLock = asyncio.Lock()
@ -103,9 +103,9 @@ class Message(object):
if not 'vol' in msg.params: if not 'vol' in msg.params:
# prevent clipping on some Lyrebird tracks # prevent clipping on some Lyrebird tracks
msg.params['vol'] = .8 msg.params['vol'] = .8
msg.params['vol'] = float(msg.params['vol']) msg.params['vol'] = float(msg.params['vol'])
return msg return msg
def parseForVariables(self): def parseForVariables(self):
@ -215,8 +215,8 @@ class Reply(object):
self.forMessage = None self.forMessage = None
self.utterances = [] self.utterances = []
self.setForMessage(message) self.setForMessage(message)
def __getstate__(self): def __getstate__(self):
# print(f'get reply {self}') # print(f'get reply {self}')
state = self.__dict__.copy() state = self.__dict__.copy()
@ -297,8 +297,8 @@ class Condition(object):
self.logInfo = None self.logInfo = None
self.originalJsonString = None self.originalJsonString = None
self.usedContainsDuration = None self.usedContainsDuration = None
def __getstate__(self): def __getstate__(self):
# print(f'get condition {self.id}') # print(f'get condition {self.id}')
state = self.__dict__.copy() state = self.__dict__.copy()
@ -500,8 +500,8 @@ class Direction(object):
self.conditions = [] self.conditions = []
self.conditionMet = None self.conditionMet = None
self.isDiversionReturn = False self.isDiversionReturn = False
def __getstate__(self): def __getstate__(self):
# print(f'get direction {self.id}') # print(f'get direction {self.id}')
state = self.__dict__.copy() state = self.__dict__.copy()
@ -568,8 +568,8 @@ class Diversion(object):
if not self.method: if not self.method:
raise Exception("No valid type given for diversion") raise Exception("No valid type given for diversion")
def __getstate__(self): def __getstate__(self):
# print(f'get diversion {self.id}') # print(f'get diversion {self.id}')
state = self.__dict__.copy() state = self.__dict__.copy()
@ -628,7 +628,7 @@ class Diversion(object):
}] }]
""" """
self.counter +=1 self.counter +=1
# story.logger.warn(f"CREATING DIRECTIONS FOR {startMsg.id}")
finishMessageIds = story.getFinishesForMsg(startMsg) finishMessageIds = story.getFinishesForMsg(startMsg)
finalTimeoutDuration = timeoutDuration finalTimeoutDuration = timeoutDuration
finalContainsDurations = replyContainsDurations finalContainsDurations = replyContainsDurations
@ -647,6 +647,7 @@ class Diversion(object):
finalContainsDurations = json.loads(condition.originalJsonString)['vars']['delays'] finalContainsDurations = json.loads(condition.originalJsonString)['vars']['delays']
i = 0 i = 0
# story.logger.warn(f"FINISHES: {finishMessageIds}")
for msgId in finishMessageIds: for msgId in finishMessageIds:
# Some very ugly hack to add a direction & condition # Some very ugly hack to add a direction & condition
i+=1 i+=1
@ -693,6 +694,7 @@ class Diversion(object):
story.logger.info(f"Created direction: {direction.id} {condition.id} with timeout {finalTimeoutDuration}s") story.logger.info(f"Created direction: {direction.id} {condition.id} with timeout {finalTimeoutDuration}s")
story.add(condition) story.add(condition)
story.add(direction) story.add(direction)
# story.logger.warn(f"ADDED DIRECTION {direction.id}")
@ -943,7 +945,7 @@ class Diversion(object):
class Configuration(object): class Configuration(object):
id = 'configuration' id = 'configuration'
volume = 1 volume = 1
@classmethod @classmethod
def initFromJson(configClass, data, story): def initFromJson(configClass, data, story):
config = Configuration() config = Configuration()
@ -1006,22 +1008,22 @@ class Stopwatch(object):
def clearMark(self, name): def clearMark(self, name):
if name in self.marks: if name in self.marks:
self.marks.pop(name) self.marks.pop(name)
def __getstate__(self): def __getstate__(self):
# print(f'get stopwatch') # print(f'get stopwatch')
state = self.__dict__.copy() state = self.__dict__.copy()
state['isRunning'] = self.isRunning.is_set() state['isRunning'] = self.isRunning.is_set()
return state return state
def __setstate__(self, state): def __setstate__(self, state):
self.__dict__.update(state) self.__dict__.update(state)
self.isRunning = asyncio.Event() self.isRunning = asyncio.Event()
if 'isRunning' in state and state['isRunning']: if 'isRunning' in state and state['isRunning']:
self.isRunning.set() self.isRunning.set()
else: else:
self.isRunning.clear() self.isRunning.clear()
class StoryState(object): class StoryState(object):
""" """
@ -1064,7 +1066,7 @@ class StoryState(object):
def __init__(self): def __init__(self):
pass pass
# #
class Story(object): class Story(object):
"""Story represents and manages a story/narrative flow""" """Story represents and manages a story/narrative flow"""
@ -1484,7 +1486,7 @@ class Story(object):
# TODO create timer event # TODO create timer event
# self.commands.append({'msg':'TEST!'}) # self.commands.append({'msg':'TEST!'})
# Test stability of Central Command with deliberate crash # Test stability of Central Command with deliberate crash
# if self.timer.getElapsed() > 10: # if self.timer.getElapsed() > 10:
# raise Exception("Test exception") # raise Exception("Test exception")
@ -1552,10 +1554,10 @@ class Story(object):
self.logger.critical(f"error: crash when reading wave file: {fn}") self.logger.critical(f"error: crash when reading wave file: {fn}")
self.logger.exception(e) self.logger.exception(e)
duration = 10 # some default duration to have something to fall back to duration = 10 # some default duration to have something to fall back to
params = message.getParams().copy() params = message.getParams().copy()
params['vol'] = params['vol'] * self.configuration.volume if 'vol' in params else self.configuration.volume params['vol'] = params['vol'] * self.configuration.volume if 'vol' in params else self.configuration.volume
# 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',
@ -1620,7 +1622,7 @@ class Story(object):
self.isRunning = True self.isRunning = True
if not self.lastMsgFinishTime and self.currentMessage: if not self.lastMsgFinishTime and self.currentMessage:
await self.setCurrentMessage(self.currentMessage) await self.setCurrentMessage(self.currentMessage)
await self._renderer() await self._renderer()
def isFinished(self): def isFinished(self):
@ -1648,16 +1650,16 @@ class Story(object):
self.timer.pause() self.timer.pause()
def calculateFinishesForMsg(self, msgId, depth = 0, checked = []): def calculateFinishesForMsg(self, msgId, depth = 0, checked = []):
if msgId in checked: # if msgId in 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:
# is finish # is finish
return [msgId] return [msgId]
if depth > 200: if depth > 100:
return [] return []
finishes = [] finishes = []
@ -1690,6 +1692,7 @@ class Story(object):
returns message ids returns message ids
""" """
print(msg.id, self.strands)
if msg.id in self.strands: if msg.id in self.strands:
return self.strands[msg.id] return self.strands[msg.id]
@ -1709,22 +1712,22 @@ class Story(object):
# TODO: should the direction have at least a timeout condition set, or not perse? # TODO: should the direction have at least a timeout condition set, or not perse?
return self.directionsPerMsg[msg.id][0] return self.directionsPerMsg[msg.id][0]
@classmethod @classmethod
def getStateDir(self): def getStateDir(self):
return "/tmp" return "/tmp"
# day = time.strftime("%Y%m%d") # day = time.strftime("%Y%m%d")
# t = time.strftime("%H:%M:%S") # t = time.strftime("%H:%M:%S")
# #
# self.out_folder = os.path.join(self.main_folder, day, f"{self.hv_id}", t) # self.out_folder = os.path.join(self.main_folder, day, f"{self.hv_id}", t)
# if not os.path.exists(self.out_folder): # if not os.path.exists(self.out_folder):
# self.logger.debug(f"Create directory {self.out_folder}") # self.logger.debug(f"Create directory {self.out_folder}")
# self.target_folder = os.makedirs(self.out_folder, exist_ok=True) # self.target_folder = os.makedirs(self.out_folder, exist_ok=True)
@classmethod @classmethod
def getStateFilename(cls, hv_id): def getStateFilename(cls, hv_id):
return os.path.join(cls.getStateDir(), f"hugvey{hv_id}") return os.path.join(cls.getStateDir(), f"hugvey{hv_id}")
def storeState(self): def storeState(self):
# TODO: stop stopwatch # TODO: stop stopwatch
fn = self.getStateFilename(self.hugvey.id) fn = self.getStateFilename(self.hugvey.id)
@ -1734,49 +1737,48 @@ class Story(object):
pickle.dump(self, fp) pickle.dump(self, fp)
# write atomic to disk: flush, close, rename # write atomic to disk: flush, close, rename
fp.flush() fp.flush()
os.fsync(fp.fileno()) os.fsync(fp.fileno())
os.rename(tmpfn, fn) os.rename(tmpfn, fn)
self.logger.debug(f"saved state to {fn}") self.logger.debug(f"saved state to {fn}")
def hasSavedState(self): def hasSavedState(self):
return self.hugveyHasSavedState(self.hugvey.id) return self.hugveyHasSavedState(self.hugvey.id)
@classmethod @classmethod
def hugveyHasSavedState(cls, hv_id): def hugveyHasSavedState(cls, hv_id):
return os.path.exists(cls.getStateFilename(hv_id)) return os.path.exists(cls.getStateFilename(hv_id))
@classmethod @classmethod
def loadStoryFromState(cls, hugvey_state): def loadStoryFromState(cls, hugvey_state):
# restart stopwatch # restart stopwatch
with open(cls.getStateFilename(hugvey_state.id), 'rb') as fp: with open(cls.getStateFilename(hugvey_state.id), 'rb') as fp:
story = pickle.load(fp) story = pickle.load(fp)
story.hugvey = hugvey_state story.hugvey = hugvey_state
story.logger = mainLogger.getChild(f"{story.hugvey.id}").getChild("story") story.logger = mainLogger.getChild(f"{story.hugvey.id}").getChild("story")
return story return story
# TODO: take running state etc. # TODO: take running state etc.
@classmethod @classmethod
def clearSavedState(cls, hv_id): def clearSavedState(cls, hv_id):
fn = cls.getStateFilename(hv_id) fn = cls.getStateFilename(hv_id)
if os.path.exists(fn): if os.path.exists(fn):
os.unlink(fn) os.unlink(fn)
mainLogger.info(f"Removed state: {fn}") mainLogger.info(f"Removed state: {fn}")
# #
def __getstate__(self): def __getstate__(self):
# Copy the object's state from self.__dict__ which contains # Copy the object's state from self.__dict__ which contains
# all our instance attributes. Always use the dict.copy() # all our instance attributes. Always use the dict.copy()
# method to avoid modifying the original state. # method to avoid modifying the original state.
state = self.__dict__.copy() state = self.__dict__.copy()
# Remove the unpicklable entries. # Remove the unpicklable entries.
del state['hugvey'] del state['hugvey']
del state['logger'] del state['logger']
# del state['isRunning'] # del state['isRunning']
return state return state
def __setstate__(self, state): def __setstate__(self, state):
self.__dict__.update(state) self.__dict__.update(state)

View file

@ -1,12 +1,11 @@
#N canvas 200 136 660 592 10; #N canvas 976 211 660 592 10;
#X obj 131 277 dac~; #X obj 131 277 dac~;
#X obj 131 227 readsf~; #X obj 131 227 readsf~;
#X obj 209 209 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 #X obj 209 209 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144
-1 -1; -1 -1;
#X text 229 206 (re-)start loop; #X text 229 206 (re-)start loop;
#X msg 132 170 open /home/a/projects/pd-play/testaudio.wav \, 1;
#X obj 208 459 netsend -u -b; #X obj 208 459 netsend -u -b;
#X obj 208 481 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 #X obj 208 481 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1
1; 1;
#X msg 355 464 disconnect; #X msg 355 464 disconnect;
#X obj 208 393 list prepend send; #X obj 208 393 list prepend send;
@ -19,33 +18,35 @@
#X obj 318 84 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 #X obj 318 84 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
-1; -1;
#X text 217 60 START; #X text 217 60 START;
#X obj 436 84 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 #X obj 436 84 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1
1; 1;
#X text 309 61 !STOP!; #X text 309 61 !STOP!;
#X text 422 60 Playing indicator; #X text 422 60 Playing indicator;
#X msg 261 118 1; #X msg 261 118 1;
#X msg 330 117 0; #X msg 330 117 0;
#X obj 208 345 oscformat /loop; #X obj 208 345 oscformat /loop;
#X msg 356 434 connect 192.168.178.15 7400; #X msg 356 434 connect 192.168.1.174 7400;
#X msg 132 170 open /mnt/stash/hugvey/score38_loop_40s_extra.wav \,
1;
#X connect 1 0 0 0; #X connect 1 0 0 0;
#X connect 1 0 0 1; #X connect 1 0 0 1;
#X connect 1 1 2 0; #X connect 1 1 2 0;
#X connect 2 0 4 0; #X connect 2 0 22 0;
#X connect 2 0 13 0; #X connect 2 0 12 0;
#X connect 4 0 1 0; #X connect 4 0 5 0;
#X connect 5 0 6 0; #X connect 6 0 4 0;
#X connect 7 0 5 0; #X connect 7 0 8 0;
#X connect 8 0 9 0; #X connect 8 0 4 0;
#X connect 9 0 5 0; #X connect 9 0 1 0;
#X connect 10 0 1 0; #X connect 10 0 21 0;
#X connect 11 0 22 0; #X connect 10 0 2 0;
#X connect 11 0 2 0; #X connect 10 0 18 0;
#X connect 11 0 19 0; #X connect 12 0 20 0;
#X connect 13 0 21 0; #X connect 13 0 9 0;
#X connect 14 0 10 0; #X connect 13 0 6 0;
#X connect 14 0 7 0; #X connect 13 0 19 0;
#X connect 14 0 20 0; #X connect 18 0 15 0;
#X connect 19 0 16 0; #X connect 19 0 15 0;
#X connect 20 0 16 0; #X connect 20 0 7 0;
#X connect 21 0 8 0; #X connect 21 0 4 0;
#X connect 22 0 5 0; #X connect 22 0 1 0;