Compare commits
6 commits
f6aeeec3d3
...
db211e7357
Author | SHA1 | Date | |
---|---|---|---|
|
db211e7357 | ||
|
dbafd3d80d | ||
|
3832652dc9 | ||
|
7d23e4a478 | ||
|
c59a07b333 | ||
|
2a1ba69a52 |
8 changed files with 156 additions and 10 deletions
|
@ -273,3 +273,10 @@ alias.url = ("/local/" => "/home/hugvey/hugvey/local/")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## When Telegram is blocked
|
||||||
|
|
||||||
|
In Russia, Telegram is blocked, to circumvent this, we set it to run over a SOCKS proxy:
|
||||||
|
|
||||||
|
`autossh -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -N -D 9090 rubenvandeven.com`
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -216,7 +216,7 @@ class VoiceServer(object):
|
||||||
try:
|
try:
|
||||||
address = "tcp://*:{}".format(self.config['voice']['port'] + self.hugvey.id)
|
address = "tcp://*:{}".format(self.config['voice']['port'] + self.hugvey.id)
|
||||||
self.voice_socket = self.ctx.socket(zmq.PUB)
|
self.voice_socket = self.ctx.socket(zmq.PUB)
|
||||||
self.voice_socket.set_hwm(15)
|
self.voice_socket.set_hwm(25) # not too high, otherwise we flood the network after a short interuption (with stuff that is 'old' anyway)
|
||||||
self.voice_socket.bind(address)
|
self.voice_socket.bind(address)
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
|
|
|
@ -1090,6 +1090,7 @@ class Diversion(object):
|
||||||
"""
|
"""
|
||||||
(1) last spoken at all
|
(1) last spoken at all
|
||||||
(2) or duration for this last reply only
|
(2) or duration for this last reply only
|
||||||
|
Only can kick in if there's no 'timeout' condition set.
|
||||||
"""
|
"""
|
||||||
if story.currentDiversion:
|
if story.currentDiversion:
|
||||||
return
|
return
|
||||||
|
|
|
@ -121,6 +121,13 @@ class Toolbox:
|
||||||
|
|
||||||
logger.info("{} files missing".format(len(missingFiles)))
|
logger.info("{} files missing".format(len(missingFiles)))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def find_direction_for_condition(cls, conditionId, story):
|
||||||
|
for i, item in enumerate(story):
|
||||||
|
if item['@type'] == 'Direction':
|
||||||
|
for dConditionId in item['conditions']:
|
||||||
|
if dConditionId == conditionId:
|
||||||
|
return item
|
||||||
|
|
||||||
def fix_story_file(self, lang_code):
|
def fix_story_file(self, lang_code):
|
||||||
if lang_code not in self.languages.keys():
|
if lang_code not in self.languages.keys():
|
||||||
|
@ -136,10 +143,11 @@ class Toolbox:
|
||||||
if len(beginnings) < 1:
|
if len(beginnings) < 1:
|
||||||
logger.critical("No beginning set")
|
logger.critical("No beginning set")
|
||||||
if len(beginnings) > 1:
|
if len(beginnings) > 1:
|
||||||
logger.warn(f"{len(beginnings)} beginning messages configured. Set only one")
|
beginningIds = [i['@id'] for i in beginnings]
|
||||||
|
logger.warn(f"{len(beginnings)} beginning messages configured. Set only one of {beginningIds}")
|
||||||
|
|
||||||
itemsPerId = {item['@id']: item for item in story}
|
itemsPerId = {item['@id']: item for item in story}
|
||||||
|
orphans = 0
|
||||||
for i, item in enumerate(story):
|
for i, item in enumerate(story):
|
||||||
if item['@type'] == 'Direction':
|
if item['@type'] == 'Direction':
|
||||||
if type(item['source']) == dict:
|
if type(item['source']) == dict:
|
||||||
|
@ -152,11 +160,21 @@ class Toolbox:
|
||||||
logger.info(f"Direction pointed to {item['source']}")
|
logger.info(f"Direction pointed to {item['source']}")
|
||||||
logger.info(f"Will now point to {validMsg}")
|
logger.info(f"Will now point to {validMsg}")
|
||||||
item['source'] = item['source']['@id']
|
item['source'] = item['source']['@id']
|
||||||
|
for conditionId in item['conditions']:
|
||||||
|
if conditionId not in itemsPerId:
|
||||||
|
logger.critical(f"Direction {item['@id']} refers to non-existing condition {conditionId}! (This will result in a crash when playing the message)")
|
||||||
if item['@type'] == 'Condition':
|
if item['@type'] == 'Condition':
|
||||||
|
direction = self.find_direction_for_condition(item['@id'], story)
|
||||||
|
if not direction:
|
||||||
|
orphans +=1
|
||||||
|
# This should be fine, but I don't dare to do it yet...
|
||||||
|
# logger.info("Clear residu condition {item['@id']} ... this is not properly done by the editor.")
|
||||||
|
# del story[i]
|
||||||
|
continue
|
||||||
if item['type'] == 'messagePlayed':
|
if item['type'] == 'messagePlayed':
|
||||||
msgId = item['vars']['msgId'].strip()
|
msgId = item['vars']['msgId'].strip()
|
||||||
if msgId not in itemsPerId:
|
if msgId not in itemsPerId:
|
||||||
logger.critical(f"Message played condition for non-existing message {msgId}!")
|
logger.warning(f"Message played condition for non-existing message {msgId} when going from {direction['source']} to {direction['target']}! (this will ignore the condition)")
|
||||||
if item['type'] == 'replyContains':
|
if item['type'] == 'replyContains':
|
||||||
if 'regex' in item['vars'] and len(item['vars']['regex'].rstrip()):
|
if 'regex' in item['vars'] and len(item['vars']['regex'].rstrip()):
|
||||||
try:
|
try:
|
||||||
|
@ -165,6 +183,8 @@ class Toolbox:
|
||||||
logger.critical(f"Invalid regex for condition {item['@id']}: {item['vars']['regex'].rstrip()}")
|
logger.critical(f"Invalid regex for condition {item['@id']}: {item['vars']['regex'].rstrip()}")
|
||||||
logger.exception(e)
|
logger.exception(e)
|
||||||
|
|
||||||
|
logger.debug( f"Can clear {orphans} orphaned conditions (uncomment code in tools.py)")
|
||||||
|
|
||||||
with open(filename, 'w') as fp:
|
with open(filename, 'w') as fp:
|
||||||
json.dump(story, fp, indent=2)
|
json.dump(story, fp, indent=2)
|
||||||
logger.info(f"Wrote to {filename}")
|
logger.info(f"Wrote to {filename}")
|
||||||
|
@ -274,4 +294,36 @@ class Toolbox:
|
||||||
json.dump(story, fp, indent=2)
|
json.dump(story, fp, indent=2)
|
||||||
logger.info(f"Wrote to {filename}")
|
logger.info(f"Wrote to {filename}")
|
||||||
|
|
||||||
|
def parse_cutelog(self, filename):
|
||||||
|
with open(filename,'r') as fp:
|
||||||
|
cutelog = json.load(fp);
|
||||||
|
|
||||||
|
hugvey_ids = list(range(1,30))
|
||||||
|
hugveys_stats = {}
|
||||||
|
for id in hugvey_ids:
|
||||||
|
print(f"HUGVEY {id}")
|
||||||
|
log = [i for i in cutelog if 'name' in i and i['name'].startswith(f'hugvey.{id}.')]
|
||||||
|
|
||||||
|
txts = [i for i in log if 'msg' in i and ((i['msg'].startswith('Text: ') and i['msg'] != "Text: ") or i['msg'].startswith('Current message') or i['msg'].startswith('ignore'))]
|
||||||
|
last = None
|
||||||
|
for txt in txts:
|
||||||
|
if last:
|
||||||
|
if txt['msg'].startswith('Current'):
|
||||||
|
print('--------------------', txt['created'])
|
||||||
|
elif txt['msg'].startswith('ignore'):
|
||||||
|
print('/////////////////////', txt['created'])
|
||||||
|
else:
|
||||||
|
print(txt['created'] - last['created'], txt['msg'], txt['levelname']
|
||||||
|
)
|
||||||
|
last = txt
|
||||||
|
else:
|
||||||
|
last = txt
|
||||||
|
tC = [i for i in log if 'msg' in i and (i['msg'].startswith("Condition is met"))]
|
||||||
|
tR = [i for i in log if 'msg' in i and (i['msg'].startswith("Received {'file"))]
|
||||||
|
tP = [i for i in log if 'msg' in i and (i['msg'].startswith("['play'"))]
|
||||||
|
for i, txt in enumerate(tP):
|
||||||
|
print(txt['created']-tC[i]['created'], txt['msg'], tC[i]['msg'], tR[i]['msg'])
|
||||||
|
|
||||||
|
|
||||||
|
print('===================')
|
||||||
|
|
||||||
|
|
17
tools.py
17
tools.py
|
@ -40,11 +40,24 @@ if __name__ == '__main__':
|
||||||
metavar=("LANG_CODE", "CVS_FILE"),
|
metavar=("LANG_CODE", "CVS_FILE"),
|
||||||
nargs=2
|
nargs=2
|
||||||
)
|
)
|
||||||
|
argParser.add_argument(
|
||||||
|
'--parse-cutelog',
|
||||||
|
default=None,
|
||||||
|
help="Parse the speech of a cutelog logfile",
|
||||||
|
metavar="CUTELOG STORED FILE",
|
||||||
|
)
|
||||||
|
argParser.add_argument(
|
||||||
|
'--verbose',
|
||||||
|
'-v',
|
||||||
|
action='count', default=0
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
args = argParser.parse_args()
|
args = argParser.parse_args()
|
||||||
|
|
||||||
|
loglevel = logging.NOTSET if args.verbose > 1 else logging.DEBUG if args.verbose > 0 else logging.INFO
|
||||||
coloredlogs.install(
|
coloredlogs.install(
|
||||||
level=logging.DEBUG
|
level=loglevel
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = logging.getLogger("toolbox")
|
logger = logging.getLogger("toolbox")
|
||||||
|
@ -61,3 +74,5 @@ if __name__ == '__main__':
|
||||||
tools.generate_story_csv(args.csv)
|
tools.generate_story_csv(args.csv)
|
||||||
if args.import_csv:
|
if args.import_csv:
|
||||||
tools.import_story_csv(*args.import_csv)
|
tools.import_story_csv(*args.import_csv)
|
||||||
|
if args.parse_cutelog:
|
||||||
|
tools.parse_cutelog(args.parse_cutelog)
|
1
www/css/vis-timeline-graph2d.min.css
vendored
Normal file
1
www/css/vis-timeline-graph2d.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -16,7 +16,7 @@
|
||||||
<div id="interface" class='showStatus'>
|
<div id="interface" class='showStatus'>
|
||||||
<div id='status'>
|
<div id='status'>
|
||||||
<div id='overview'>
|
<div id='overview'>
|
||||||
<span class="loop_time" title="uptime: {{uptime}}" onclick="document.getElementById('time_update').classList.toggle('visible')">{{loop_timer}}</span>
|
<span class="loop_time" :title="['uptime', uptime]" onclick="document.getElementById('time_update').classList.toggle('visible')">{{loop_timer}}</span>
|
||||||
<div id='time_update'>
|
<div id='time_update'>
|
||||||
<input type="text" value="00:00:00" name="loop_time_value" id="loop_time_value" />
|
<input type="text" value="00:00:00" name="loop_time_value" id="loop_time_value" />
|
||||||
<input type="button" onclick="panopticon.change_loop_time(document.getElementById('loop_time_value').value)" value="set time">
|
<input type="button" onclick="panopticon.change_loop_time(document.getElementById('loop_time_value').value)" value="set time">
|
||||||
|
@ -94,6 +94,7 @@
|
||||||
<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 id="btn-config" class="btn">Configuration</div>
|
||||||
|
<form id='search'><input type='text' id='search-field'> <input type='submit' id='search-go' value='Search'></form>
|
||||||
</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"
|
||||||
|
|
|
@ -354,6 +354,8 @@ class Graph {
|
||||||
this.directions = []; // initialise empty array. For the simulation, make sure we keep the same array object
|
this.directions = []; // initialise empty array. For the simulation, make sure we keep the same array object
|
||||||
this.conditions = []; // initialise empty array. For the simulation, make sure we keep the same array object
|
this.conditions = []; // initialise empty array. For the simulation, make sure we keep the same array object
|
||||||
this.diversions = []; // initialise empty array. For the simulation, make sure we keep the same array object
|
this.diversions = []; // initialise empty array. For the simulation, make sure we keep the same array object
|
||||||
|
this.previousSearch = "";
|
||||||
|
this.searchStep = 0;
|
||||||
|
|
||||||
let graph = this;
|
let graph = this;
|
||||||
this.controlDown = false;
|
this.controlDown = false;
|
||||||
|
@ -372,9 +374,11 @@ class Graph {
|
||||||
|
|
||||||
let c = this.container;
|
let c = this.container;
|
||||||
let zoomed = function() {
|
let zoomed = function() {
|
||||||
|
console.log(d3.event);
|
||||||
c.attr( "transform", d3.event.transform );
|
c.attr( "transform", d3.event.transform );
|
||||||
}
|
}
|
||||||
this.svg.call( d3.zoom()
|
this.zoom = d3.zoom();
|
||||||
|
this.svg.call( this.zoom
|
||||||
.scaleExtent( [1 / 16, 8] )
|
.scaleExtent( [1 / 16, 8] )
|
||||||
.on( "zoom", zoomed ) );
|
.on( "zoom", zoomed ) );
|
||||||
|
|
||||||
|
@ -398,6 +402,71 @@ class Graph {
|
||||||
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(); } );
|
document.getElementById( 'btn-config' ).addEventListener( 'click', function( e ) { graph.showConfiguration(); } );
|
||||||
|
document.getElementById( 'search' ).addEventListener( 'submit', function( e ) { e.preventDefault(); graph.searchSubmit(); } );
|
||||||
|
}
|
||||||
|
|
||||||
|
searchSubmit() {
|
||||||
|
let query = document.getElementById( 'search-field' ).value;
|
||||||
|
if(query.length < 1) {
|
||||||
|
console.log('no query');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(query == this.previousSearch) {
|
||||||
|
this.searchStep++;
|
||||||
|
} else{
|
||||||
|
this.searchStep = 0;
|
||||||
|
}
|
||||||
|
this.previousSearch = query;
|
||||||
|
let results = this.findMessages(query);
|
||||||
|
if(results.length < 1) {
|
||||||
|
alert("No message found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ri = this.searchStep % results.length;
|
||||||
|
let msg = results[ri];
|
||||||
|
|
||||||
|
console.log(msg);
|
||||||
|
|
||||||
|
this.zoom.scaleTo(this.svg, 1);
|
||||||
|
this.zoom.translateTo(this.svg, msg.x + 1280/2, msg.y + 1024/2);
|
||||||
|
this.selectMsg(msg);
|
||||||
|
|
||||||
|
document.getElementById("search-go").value = "Search ("+(ri+1) + "/" + results.length +")";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
findMessages(query) {
|
||||||
|
let results = [];
|
||||||
|
|
||||||
|
for(let msg of this.messages) {
|
||||||
|
if(msg['@id'] == query || msg['@id'].indexOf(query) > -1) {
|
||||||
|
results.push(msg);
|
||||||
|
}
|
||||||
|
if(msg['text'] == query || (msg.hasOwnProperty('label') && msg['label'] == query)) {
|
||||||
|
results.push(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// second loop for priority
|
||||||
|
for(let msg of this.messages) {
|
||||||
|
if(msg['text'].indexOf(query) > -1 || (msg.hasOwnProperty('label') && msg['label'].indexOf(query) > -1)) {
|
||||||
|
results.push(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
findMessage(query, matchNr) {
|
||||||
|
if(typeof matchNr == 'undefined') {
|
||||||
|
matchNr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let results = this.findMessages(query)
|
||||||
|
|
||||||
|
if(results.length) {
|
||||||
|
return results[matchNr % results.length];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clickMsg( msg ) {
|
clickMsg( msg ) {
|
||||||
|
|
Loading…
Reference in a new issue