Merge branch 'master' of gitlab.com:hugvey/hugvey
This commit is contained in:
commit
90b63b24d2
6 changed files with 113 additions and 20 deletions
22
README.md
22
README.md
|
@ -92,18 +92,27 @@ chown=pi:pi
|
||||||
|
|
||||||
## Deploy / usefull commands
|
## Deploy / usefull commands
|
||||||
|
|
||||||
|
rsync them all
|
||||||
```bash
|
```bash
|
||||||
for i in {1..26}; do echo $i; rsync -av ~/hugvey/ pi@hugvey$i.local:/home/pi/hugvey/ --exclude=www --exclude=venv --exclude=local --exclude=*.pyc --exclude=.git --exclude=recordings --exclude=/voice* --exclude=/pd; done
|
for i in {1..26}; do echo $i; rsync -av ~/hugvey/ pi@hugvey$i.local:/home/pi/hugvey/ --exclude=www --exclude=venv --exclude=local --exclude=*.pyc --exclude=.git --exclude=recordings --exclude=/voice* --exclude=/pd; done
|
||||||
```
|
```
|
||||||
|
|
||||||
|
shut all of them down
|
||||||
```bash
|
```bash
|
||||||
for i in {1..6}; do ssh pi@hugvey$i.local "sudo shutdown -h now"; done
|
for i in {1..26}; do ssh pi@hugvey$i.local "sudo shutdown -h now"; done
|
||||||
```
|
```
|
||||||
|
|
||||||
|
restart supervisor on all of them
|
||||||
```bash
|
```bash
|
||||||
for i in {1..6}; do ssh pi@hugvey$i.local "supervisorctl restart hugvey_client"; done
|
for i in {1..26}; do ssh pi@hugvey$i.local "supervisorctl restart hugvey_client"; done
|
||||||
```
|
```
|
||||||
|
|
||||||
|
install bash on all of them
|
||||||
|
```bash
|
||||||
|
for i in {1..26}; do echo $i;ssh pi@hugvey$i.local "cd hugvey && sudo bash install_server.sh"; done
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Monitoring the server processes
|
### Monitoring the server processes
|
||||||
|
|
||||||
|
@ -205,3 +214,12 @@ times occured/only on n-th instance: determines the order of diversions of the s
|
||||||
|
|
||||||
Visit 192.168.5.1
|
Visit 192.168.5.1
|
||||||
The password is at the bottom of the device.
|
The password is at the bottom of the device.
|
||||||
|
|
||||||
|
|
||||||
|
# Restoring a hugvey
|
||||||
|
|
||||||
|
- Write image `/mnt/stash/hugvey.img` to the microSD card.
|
||||||
|
+ You can use `gnome-disks` 'restore image' for that
|
||||||
|
- Open partition called rootfs, and `sudo nano etc/hostname`
|
||||||
|
+ Change hugvey20 into hugveyX (the number you need)
|
||||||
|
- Start it, rsync, install_server.sh as mentioned above.
|
||||||
|
|
|
@ -103,6 +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'])
|
||||||
|
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
def parseForVariables(self):
|
def parseForVariables(self):
|
||||||
|
@ -937,12 +940,23 @@ class Diversion(object):
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
class Configuration(object):
|
||||||
|
id = 'configuration'
|
||||||
|
volume = 1
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def initFromJson(configClass, data, story):
|
||||||
|
config = Configuration()
|
||||||
|
config.__dict__.update(data)
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
storyClasses = {
|
storyClasses = {
|
||||||
'Msg': Message,
|
'Msg': Message,
|
||||||
'Direction': Direction,
|
'Direction': Direction,
|
||||||
'Condition': Condition,
|
'Condition': Condition,
|
||||||
'Diversion': Diversion,
|
'Diversion': Diversion,
|
||||||
|
'Configuration': Configuration,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1158,6 +1172,8 @@ class Story(object):
|
||||||
|
|
||||||
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]
|
||||||
self.interruptionDiversions = [el for el in self.elements.values() if type(el) == Diversion and el.type == 'interrupt']
|
self.interruptionDiversions = [el for el in self.elements.values() if type(el) == Diversion and el.type == 'interrupt']
|
||||||
|
configurations = [el for el in self.elements.values() if type(el) == Configuration]
|
||||||
|
self.configuration = configurations[0] if len(configurations) else Configuration()
|
||||||
|
|
||||||
if currentId:
|
if currentId:
|
||||||
self.currentMessage = self.get(currentId)
|
self.currentMessage = self.get(currentId)
|
||||||
|
@ -1536,13 +1552,16 @@ 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['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',
|
||||||
'file': fn,
|
'file': fn,
|
||||||
'id': message.id,
|
'id': message.id,
|
||||||
'params': message.getParams(),
|
'params': params,
|
||||||
'duration': duration
|
'duration': duration
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1628,19 +1647,24 @@ class Story(object):
|
||||||
self.finish_time = time.time()
|
self.finish_time = time.time()
|
||||||
self.timer.pause()
|
self.timer.pause()
|
||||||
|
|
||||||
def calculateFinishesForMsg(self, msgId, depth = 0):
|
def calculateFinishesForMsg(self, msgId, depth = 0, checked = []):
|
||||||
|
if msgId in checked:
|
||||||
|
return []
|
||||||
|
|
||||||
|
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 > 40:
|
if depth > 200:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
finishes = []
|
finishes = []
|
||||||
for d in self.directionsPerMsg[msgId]:
|
for d in self.directionsPerMsg[msgId]:
|
||||||
if d.msgTo.id == msgId:
|
if d.msgTo.id == msgId:
|
||||||
continue
|
continue
|
||||||
finishes.extend(self.calculateFinishesForMsg(d.msgTo.id, depth+1))
|
finishes.extend(self.calculateFinishesForMsg(d.msgTo.id, depth+1, checked))
|
||||||
|
|
||||||
# de-duplicate before returning
|
# de-duplicate before returning
|
||||||
return list(set(finishes))
|
return list(set(finishes))
|
||||||
|
|
|
@ -44,13 +44,14 @@ img.icon {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
width: 100vw; }
|
width: 100vw; }
|
||||||
#interface #audioFiles {
|
#interface #audioFiles, #interface #configuration {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 10%;
|
top: 30%;
|
||||||
left: 10%;
|
left: 30%;
|
||||||
right: 10%;
|
right: 30%;
|
||||||
bottom: 10%;
|
bottom: 30%;
|
||||||
background: #ccc; }
|
background: #ccc;
|
||||||
|
overflow: auto; }
|
||||||
|
|
||||||
#status {
|
#status {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -105,7 +106,7 @@ img.icon {
|
||||||
bottom: 3px;
|
bottom: 3px;
|
||||||
right: 3px; }
|
right: 3px; }
|
||||||
#status .hugvey .light input {
|
#status .hugvey .light input {
|
||||||
width: 2em; }
|
width: 3.2em; }
|
||||||
#status .hugvey .stats .count {
|
#status .hugvey .stats .count {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-right: 10px; }
|
margin-right: 10px; }
|
||||||
|
|
|
@ -81,6 +81,7 @@
|
||||||
<div id="btn-addMsg" class="btn">Create message</div>
|
<div id="btn-addMsg" class="btn">Create message</div>
|
||||||
<div id="btn-diversions" class="btn">View Diversions</div>
|
<div id="btn-diversions" class="btn">View Diversions</div>
|
||||||
<div id="btn-audio" class="btn">View Audio Files</div>
|
<div id="btn-audio" class="btn">View Audio Files</div>
|
||||||
|
<div id="btn-config" class="btn">Configuration</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="msg"></div>
|
<div id="msg"></div>
|
||||||
<svg id='graph' viewbox="-640 -512 1280 1024"
|
<svg id='graph' viewbox="-640 -512 1280 1024"
|
||||||
|
|
|
@ -301,6 +301,7 @@ class Graph {
|
||||||
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(); } );
|
||||||
document.getElementById( 'btn-audio' ).addEventListener( 'click', function( e ) { graph.showAudioFiles(); } );
|
document.getElementById( 'btn-audio' ).addEventListener( 'click', function( e ) { graph.showAudioFiles(); } );
|
||||||
|
document.getElementById( 'btn-config' ).addEventListener( 'click', function( e ) { graph.showConfiguration(); } );
|
||||||
}
|
}
|
||||||
|
|
||||||
clickMsg( msg ) {
|
clickMsg( msg ) {
|
||||||
|
@ -343,6 +344,10 @@ class Graph {
|
||||||
return `http://localhost:8888/voice?text=${encodeURIComponent(msg['text'])}&variable=${isVariable}&lang=${lang}&filename=0`;
|
return `http://localhost:8888/voice?text=${encodeURIComponent(msg['text'])}&variable=${isVariable}&lang=${lang}&filename=0`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getConfig() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
getNumericId(prefix) {
|
getNumericId(prefix) {
|
||||||
let id, i = 0;
|
let id, i = 0;
|
||||||
let hasId= function(a, id) {
|
let hasId= function(a, id) {
|
||||||
|
@ -854,6 +859,42 @@ class Graph {
|
||||||
document.getElementById("interface").appendChild(audioFilesEl);
|
document.getElementById("interface").appendChild(audioFilesEl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showConfiguration( ) {
|
||||||
|
let configEl = crel('div',{
|
||||||
|
'id':'configuration'
|
||||||
|
},
|
||||||
|
crel(
|
||||||
|
'div',
|
||||||
|
{
|
||||||
|
'class':'btn btn-close',
|
||||||
|
'on': {
|
||||||
|
'click': function() {
|
||||||
|
configEl.parentNode.removeChild(configEl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'close'
|
||||||
|
),
|
||||||
|
crel('h2', `Language based settings for ${this.language_code}`),
|
||||||
|
crel(
|
||||||
|
'label',
|
||||||
|
'volume',
|
||||||
|
crel('input', {
|
||||||
|
'type': 'number',
|
||||||
|
'step': 0.05,
|
||||||
|
'on': {
|
||||||
|
'change': function(e){
|
||||||
|
panopticon.graph.configuration['volume'] = parseFloat(e.target.value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'value': this.configuration.hasOwnProperty('volume') ? this.configuration.volume : 1
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
document.getElementById("interface").appendChild(configEl);
|
||||||
|
}
|
||||||
|
|
||||||
showMsg( msg ) {
|
showMsg( msg ) {
|
||||||
let msgEl = document.getElementById( 'msg' );
|
let msgEl = document.getElementById( 'msg' );
|
||||||
msgEl.innerHTML = "";
|
msgEl.innerHTML = "";
|
||||||
|
@ -1654,7 +1695,7 @@ class Graph {
|
||||||
|
|
||||||
getJsonString() {
|
getJsonString() {
|
||||||
// recreate array to have the right order of items.
|
// recreate array to have the right order of items.
|
||||||
this.data = [...this.messages, ...this.conditions,
|
this.data = [this.configuration, ...this.messages, ...this.conditions,
|
||||||
...this.directions, ...this.diversions]
|
...this.directions, ...this.diversions]
|
||||||
let d = [];
|
let d = [];
|
||||||
// let toRemove = ['sourceX', 'sourceY', 'targetX', 'targetY', 'x', 'y', 'vx', 'vy']
|
// let toRemove = ['sourceX', 'sourceY', 'targetX', 'targetY', 'x', 'y', 'vx', 'vy']
|
||||||
|
@ -1736,6 +1777,12 @@ class Graph {
|
||||||
this.conditions = this.data.filter(( node ) => node['@type'] == 'Condition' );
|
this.conditions = this.data.filter(( node ) => node['@type'] == 'Condition' );
|
||||||
this.diversions = this.data.filter(( node ) => node['@type'] == 'Diversion' );
|
this.diversions = this.data.filter(( node ) => node['@type'] == 'Diversion' );
|
||||||
|
|
||||||
|
let configurations = this.data.filter(( node ) => node['@type'] == 'Configuration' );
|
||||||
|
this.configuration = configurations.length > 0 ? configurations[0] : {
|
||||||
|
"@id": "config",
|
||||||
|
"@type": "Configuration"
|
||||||
|
};
|
||||||
|
|
||||||
document.getElementById('current_lang').innerHTML = "";
|
document.getElementById('current_lang').innerHTML = "";
|
||||||
document.getElementById('current_lang').appendChild(crel('span', {
|
document.getElementById('current_lang').appendChild(crel('span', {
|
||||||
'class': 'flag-icon ' + this.language_code
|
'class': 'flag-icon ' + this.language_code
|
||||||
|
|
|
@ -64,14 +64,16 @@ img.icon{
|
||||||
&.showStatus{
|
&.showStatus{
|
||||||
}
|
}
|
||||||
|
|
||||||
#audioFiles {
|
#audioFiles, #configuration {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 10%;
|
top: 30%;
|
||||||
left: 10%;
|
left: 30%;
|
||||||
right: 10%;
|
right: 30%;
|
||||||
bottom: 10%;
|
bottom: 30%;
|
||||||
background: #ccc;
|
background: #ccc;
|
||||||
|
overflow:auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#status{
|
#status{
|
||||||
|
|
Loading…
Reference in a new issue