2022-03-13 19:24:02 +01:00
|
|
|
import argparse, json, sys, time, random, logging, signal, threading
|
2022-03-13 17:09:05 +01:00
|
|
|
import utterance.voice
|
|
|
|
|
import utterance.utils
|
|
|
|
|
import utterance.osc
|
|
|
|
|
import examine.metric
|
|
|
|
|
|
2022-03-20 16:06:57 +01:00
|
|
|
logging.basicConfig(level=logging.INFO)
|
2022-03-17 15:29:44 +01:00
|
|
|
|
2022-03-13 19:24:02 +01:00
|
|
|
UTTERANCE_LEN = 16 #<--------------- these should be in config
|
2022-04-04 09:12:49 +02:00
|
|
|
NUM_METRIC_GEN = 75
|
2022-03-13 18:56:35 +01:00
|
|
|
NUM_SAMPLE_VOICES = 3
|
2022-04-04 09:12:49 +02:00
|
|
|
RANDOM_SEED_TIMER_MIN = 2
|
2022-03-13 17:09:05 +01:00
|
|
|
broadcast = None
|
2022-03-13 18:56:35 +01:00
|
|
|
metric = None
|
|
|
|
|
exit = False
|
2022-03-17 15:29:44 +01:00
|
|
|
terminal = False
|
2022-03-20 16:06:57 +01:00
|
|
|
debug = False
|
2022-03-13 17:09:05 +01:00
|
|
|
|
2022-03-13 18:56:35 +01:00
|
|
|
def format_str(text) -> str:
|
2022-03-13 17:09:05 +01:00
|
|
|
t = utterance.utils.clean(text)
|
2022-03-13 18:56:35 +01:00
|
|
|
return utterance.utils.format(t)
|
|
|
|
|
|
|
|
|
|
def utter_one(v) -> str:
|
|
|
|
|
u = v.utter_one()
|
|
|
|
|
return format_str(u)
|
|
|
|
|
|
|
|
|
|
def utter_one_vectorise(v):
|
|
|
|
|
global metric
|
|
|
|
|
uv = utter_one(v)
|
|
|
|
|
uv_vec = metric.vector(uv)
|
|
|
|
|
return uv, uv_vec
|
|
|
|
|
|
|
|
|
|
def utter_n_vectorise_distance(v, n, vec):
|
|
|
|
|
global metric
|
|
|
|
|
results = []
|
|
|
|
|
texts = v.utter_n(n=n)
|
|
|
|
|
for t in texts:
|
|
|
|
|
t = format_str(t)
|
|
|
|
|
t_vec = metric.vector(t)
|
|
|
|
|
d = examine.metric.cos_dist(vec, t_vec)
|
|
|
|
|
results.append([d, t, v])
|
|
|
|
|
return results
|
2022-03-13 17:09:05 +01:00
|
|
|
|
2022-03-17 15:29:44 +01:00
|
|
|
def terminal_utterance(utterance):
|
|
|
|
|
if terminal:
|
|
|
|
|
print(utterance, end="")
|
|
|
|
|
|
2022-03-13 17:09:05 +01:00
|
|
|
def broadcast_utterance(v, utterance):
|
|
|
|
|
|
2022-03-20 16:06:57 +01:00
|
|
|
global broadcast, exit, debug
|
2022-03-13 17:09:05 +01:00
|
|
|
|
2022-03-20 16:06:57 +01:00
|
|
|
if debug:
|
|
|
|
|
temp = format(v.temp, '.2f')
|
|
|
|
|
text = f"{v.name.upper()}: {temp}\n"
|
|
|
|
|
else:
|
2022-04-04 09:12:49 +02:00
|
|
|
text = f""
|
|
|
|
|
|
|
|
|
|
# Send all text to server to calculate bounds in advance
|
|
|
|
|
broadcast.utterance(utterance, v.calculate)
|
|
|
|
|
|
2022-03-13 17:09:05 +01:00
|
|
|
|
|
|
|
|
broadcast.utterance(text, v.channel)
|
2022-03-17 15:29:44 +01:00
|
|
|
terminal_utterance(text)
|
2022-03-13 17:09:05 +01:00
|
|
|
time.sleep(2)
|
|
|
|
|
|
|
|
|
|
frags = v.fragments(utterance)
|
|
|
|
|
|
|
|
|
|
for f in frags:
|
|
|
|
|
text += f
|
|
|
|
|
broadcast.utterance(text, v.channel)
|
2022-03-17 15:29:44 +01:00
|
|
|
terminal_utterance(f)
|
2022-03-13 17:09:05 +01:00
|
|
|
time.sleep(2)
|
2022-03-13 18:56:35 +01:00
|
|
|
if exit:
|
|
|
|
|
return
|
2022-03-13 17:09:05 +01:00
|
|
|
|
|
|
|
|
broadcast.command('clear')
|
2022-03-17 15:29:44 +01:00
|
|
|
print("==========")
|
|
|
|
|
|
2022-03-13 17:09:05 +01:00
|
|
|
time.sleep(2)
|
|
|
|
|
|
2022-03-13 19:24:02 +01:00
|
|
|
def find_candidates(v, uv_vec, voices, results):
|
|
|
|
|
logging.info(f"LOOP::finding candidates")
|
|
|
|
|
|
|
|
|
|
start = time.time()
|
|
|
|
|
candidates = random.sample(voices, NUM_SAMPLE_VOICES)
|
|
|
|
|
for c in candidates:
|
|
|
|
|
if exit:
|
|
|
|
|
break
|
|
|
|
|
if c == v:
|
|
|
|
|
continue
|
|
|
|
|
results += utter_n_vectorise_distance(c, NUM_METRIC_GEN, uv_vec)
|
|
|
|
|
|
|
|
|
|
results.sort(key=lambda t: t[0], reverse=True)
|
|
|
|
|
|
|
|
|
|
lapse = time.time() - start
|
|
|
|
|
logging.info(f"LOOP::done - {lapse} secs")
|
|
|
|
|
|
2022-03-20 10:45:12 +01:00
|
|
|
def update():
|
|
|
|
|
global exit
|
|
|
|
|
while not exit:
|
2022-03-20 16:06:57 +01:00
|
|
|
try:
|
|
|
|
|
utterance.osc.update()
|
|
|
|
|
except Exception as e:
|
|
|
|
|
logging.error(e)
|
|
|
|
|
pass
|
|
|
|
|
|
2022-03-20 10:45:12 +01:00
|
|
|
time.sleep(0.2)
|
2022-03-13 19:24:02 +01:00
|
|
|
|
2022-03-13 18:56:35 +01:00
|
|
|
def signal_terminate(signum, frame):
|
|
|
|
|
global exit
|
|
|
|
|
logging.warning("::SIGNAL TERMINATE::")
|
|
|
|
|
exit = True
|
|
|
|
|
|
2022-03-13 17:09:05 +01:00
|
|
|
def main() -> int:
|
|
|
|
|
|
2022-03-20 16:06:57 +01:00
|
|
|
global broadcast, metric, terminal, debug
|
2022-03-13 17:09:05 +01:00
|
|
|
|
|
|
|
|
p = argparse.ArgumentParser()
|
|
|
|
|
p.add_argument("-c", "--config", type=str, default="voice.config.json", help="configuratin file")
|
|
|
|
|
p.add_argument("-i", "--iterations", type=int, default=10, help="number of iterations")
|
2022-04-04 09:12:49 +02:00
|
|
|
p.add_argument("-t", "--terminal", action='store_true', help="print to terminal")
|
2022-03-17 15:29:44 +01:00
|
|
|
args = p.parse_args()
|
2022-03-13 18:56:35 +01:00
|
|
|
|
|
|
|
|
logging.info(f"INIT::loading config file - {args.config}")
|
|
|
|
|
|
2022-03-13 17:09:05 +01:00
|
|
|
with open(args.config) as f:
|
|
|
|
|
conf = json.load(f)
|
|
|
|
|
|
2022-03-13 18:56:35 +01:00
|
|
|
logging.info(conf)
|
|
|
|
|
|
2022-03-17 15:29:44 +01:00
|
|
|
terminal = args.terminal
|
|
|
|
|
|
2022-03-13 18:56:35 +01:00
|
|
|
#--------------------#
|
|
|
|
|
# VOICES
|
|
|
|
|
#--------------------#
|
|
|
|
|
logging.info(f"INIT::creating voices")
|
|
|
|
|
|
2022-03-13 17:09:05 +01:00
|
|
|
voices = []
|
|
|
|
|
for v in conf['voices']:
|
|
|
|
|
model = v['model']
|
|
|
|
|
voice = utterance.voice.Voice(name=v["name"].upper(), model=model['model_dir'], tokenizer=model['tokeniser_file'], temp=float(model["temperature"]), lenght=UTTERANCE_LEN)
|
|
|
|
|
voice.set_channel(v['osc_channel']['root'], v['osc_channel']['utterance'])
|
2022-04-04 09:12:49 +02:00
|
|
|
voice.set_calculate(v['osc_channel']['root'], v['osc_channel']['calculate'])
|
|
|
|
|
voice.set_temperature(v['osc_channel']['root'], v['osc_channel']['temperature'])
|
2022-03-13 17:09:05 +01:00
|
|
|
voices.append(voice)
|
|
|
|
|
|
|
|
|
|
|
2022-03-13 18:56:35 +01:00
|
|
|
#--------------------#
|
|
|
|
|
# NET
|
|
|
|
|
#--------------------#
|
|
|
|
|
logging.info(f"INIT::setting up OSC")
|
2022-03-20 10:45:12 +01:00
|
|
|
|
|
|
|
|
utterance.osc.start_osc()
|
|
|
|
|
|
|
|
|
|
broadcast = utterance.osc.OscBroadcaster(name="osc_broadcast", host=conf['host_voicemachine'], port=conf['port_voicemachine'], command_channel=conf['command_osc_channel'])
|
|
|
|
|
|
2022-03-20 16:06:57 +01:00
|
|
|
def receiver_cb(temp, name):
|
|
|
|
|
global debug
|
|
|
|
|
if type(temp) == str and temp == "DEBUG":
|
|
|
|
|
debug = name
|
|
|
|
|
logging.info(f"DEBUG MODE: {debug}")
|
2022-04-04 09:12:49 +02:00
|
|
|
else: # temperature
|
2022-03-20 16:06:57 +01:00
|
|
|
for v in voices:
|
|
|
|
|
if v.name == name:
|
|
|
|
|
print(f'{name} - {temp}')
|
|
|
|
|
v.temp = temp
|
2022-04-04 09:12:49 +02:00
|
|
|
broadcast.temperature(temp, v.temperature)
|
2022-03-20 10:45:12 +01:00
|
|
|
|
2022-03-20 16:06:57 +01:00
|
|
|
receiver = utterance.osc.OscReceiver(name="osc_receiver", host=conf['host_machinespeak'], port=conf['port_machinespeak'], callback_fn=receiver_cb)
|
2022-03-20 10:45:12 +01:00
|
|
|
|
2022-03-13 17:09:05 +01:00
|
|
|
|
2022-03-13 18:56:35 +01:00
|
|
|
#--------------------#
|
|
|
|
|
# METRIC
|
|
|
|
|
#--------------------#
|
|
|
|
|
logging.info(f"INIT::loading doc2vec metrics")
|
2022-03-13 17:09:05 +01:00
|
|
|
metric = examine.metric.Metric(model_input='data/models/doc2vec.model')
|
|
|
|
|
|
2022-03-20 16:06:57 +01:00
|
|
|
#--------------------#
|
|
|
|
|
# RANDOM
|
|
|
|
|
#--------------------#
|
|
|
|
|
|
|
|
|
|
def random_seed():
|
|
|
|
|
global t_random_seed
|
|
|
|
|
logging.info("INIT::SEEDING RANDOM")
|
|
|
|
|
random.seed(time.time())
|
|
|
|
|
if not exit:
|
2022-04-04 09:12:49 +02:00
|
|
|
t_random_seed = threading.Timer(random.randint(60, 60 * RANDOM_SEED_TIMER_MIN), random_seed)
|
2022-03-20 16:06:57 +01:00
|
|
|
t_random_seed.start()
|
|
|
|
|
|
2022-04-04 09:12:49 +02:00
|
|
|
t_random_seed = threading.Timer(random.randint(60, 60 * RANDOM_SEED_TIMER_MIN), random_seed)
|
2022-03-20 16:06:57 +01:00
|
|
|
t_random_seed.start()
|
|
|
|
|
|
2022-03-13 18:56:35 +01:00
|
|
|
#--------------------#
|
|
|
|
|
# A
|
|
|
|
|
#--------------------#
|
|
|
|
|
logging.info(f"INIT::generating first utterance")
|
2022-03-20 16:06:57 +01:00
|
|
|
|
2022-03-13 18:56:35 +01:00
|
|
|
v = random.choice(voices)
|
|
|
|
|
uv, uv_vec = utter_one_vectorise(v)
|
2022-03-20 10:45:12 +01:00
|
|
|
|
|
|
|
|
t_update = threading.Thread(target=update)
|
|
|
|
|
t_update.start()
|
2022-03-13 17:09:05 +01:00
|
|
|
|
2022-03-13 18:56:35 +01:00
|
|
|
while not exit:
|
2022-03-13 17:09:05 +01:00
|
|
|
|
2022-03-13 19:24:02 +01:00
|
|
|
results = []
|
|
|
|
|
t = threading.Thread(target=find_candidates, args=[v, uv_vec, voices, results])
|
|
|
|
|
t.start()
|
|
|
|
|
|
2022-03-13 18:56:35 +01:00
|
|
|
logging.info(f"LOOP::broadcasting {v.name}")
|
|
|
|
|
broadcast_utterance(v, uv)
|
2022-03-13 17:09:05 +01:00
|
|
|
|
2022-03-13 19:24:02 +01:00
|
|
|
t.join()
|
2022-03-13 17:09:05 +01:00
|
|
|
|
2022-03-13 18:56:35 +01:00
|
|
|
# ok here we need to randomise maybe...?!
|
|
|
|
|
# ([d, t, v])
|
2022-04-04 09:12:49 +02:00
|
|
|
|
|
|
|
|
|
2022-03-13 18:56:35 +01:00
|
|
|
choice = results[0]
|
2022-04-04 09:12:49 +02:00
|
|
|
# makse sure we don't say the same thing over and over again
|
|
|
|
|
for r in results:
|
|
|
|
|
v = r[2]
|
|
|
|
|
u = r[1]
|
|
|
|
|
if v.select(u):
|
|
|
|
|
choice = r
|
|
|
|
|
break
|
|
|
|
|
else:
|
|
|
|
|
logging.info(f"LOOP::reduncancy {v.name}")
|
|
|
|
|
|
2022-03-13 18:56:35 +01:00
|
|
|
v = choice[2]
|
|
|
|
|
uv = choice[1]
|
|
|
|
|
uv_vec = metric.vector(uv)
|
|
|
|
|
logging.info(f"LOOP::next {v.name}")
|
2022-03-13 17:09:05 +01:00
|
|
|
|
2022-03-20 10:45:12 +01:00
|
|
|
t_update.join()
|
2022-03-13 17:09:05 +01:00
|
|
|
|
2022-03-13 18:56:35 +01:00
|
|
|
logging.info(f"TERMINATE::terminating OSC")
|
2022-03-20 10:45:12 +01:00
|
|
|
utterance.osc.terminate_osc()
|
2022-03-13 17:09:05 +01:00
|
|
|
|
2022-03-20 16:06:57 +01:00
|
|
|
# if t_random_seed:
|
|
|
|
|
logging.info(f"TERMINATE::random seed")
|
|
|
|
|
t_random_seed.cancel()
|
|
|
|
|
t_random_seed.join()
|
|
|
|
|
|
2022-03-13 18:56:35 +01:00
|
|
|
logging.info(f"FIN")
|
|
|
|
|
|
2022-03-13 17:09:05 +01:00
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
2022-03-13 18:56:35 +01:00
|
|
|
signal.signal(signal.SIGINT, signal_terminate)
|
|
|
|
|
sys.exit(main())
|