first commit
commit
a01b5221b6
@ -0,0 +1,22 @@
|
|||||||
|
# Pick something random app for Snips
|
||||||
|
|
||||||
|
[![Build status](https://api.travis-ci.com/koenvervloesem/snips-app-pick-something-random.svg?branch=master)](https://travis-ci.com/koenvervloesem/snips-app-pick-something-random) [![Maintainability](https://api.codeclimate.com/v1/badges/b02b8ff9a4ebd13f9e3f/maintainability)](https://codeclimate.com/github/koenvervloesem/snips-app-pick-something-random/maintainability) [![Code quality](https://api.codacy.com/project/badge/Grade/178255b06d224fabb2aae5b83827de3f)](https://www.codacy.com/app/koenvervloesem/snips-app-pick-something-random) [![Python versions](https://img.shields.io/badge/python-3.5|3.6|3.7-blue.svg)](https://www.python.org) [![GitHub license](https://img.shields.io/github/license/koenvervloesem/snips-app-pick-something-random.svg)](https://github.com/koenvervloesem/snips-app-pick-something-random/blob/master/LICENSE) [![Languages](https://img.shields.io/badge/i18n-en-brown.svg)](https://github.com/koenvervloesem/snips-app-pick-something-random/tree/master/translations) [![Snips App Store](https://img.shields.io/badge/snips-app-blue.svg)](https://console.snips.ai/store/en/skill_NmlgOeBBO13)
|
||||||
|
|
||||||
|
With this [Snips](https://snips.ai/) app, you can ask for random numbers and dates, to flip a coin and to roll a die or multiple dice.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
The easiest way to install this app is by adding the Snips app [Pick something random](https://console.snips.ai/store/en/skill_NmlgOeBBO13) to your assistant in the [Snips Console](https://console.snips.ai).
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
This app recognizes the following intents:
|
||||||
|
|
||||||
|
* FlipCoin - The user asks to flip a coin. The app reasponds with heads or tails.
|
||||||
|
* RandomNumber - The user asks to pick a random number between two numbers. The app responds with a number.
|
||||||
|
* RandomDate - The user asks to pick a random date, optionally in a specific period. The app responds with a date in the specified time period.
|
||||||
|
* RollDice - The user asks to roll a die or multiple dice (specified in words or in [dice notation](https://en.wikipedia.org/wiki/Dice_notation)). The app responds with the numbers.
|
||||||
|
|
||||||
|
## Copyright
|
||||||
|
|
||||||
|
This app is provided by [Koen Vervloesem](mailto:koen@vervloesem.eu) as open source software. See LICENSE for more information.
|
@ -0,0 +1,79 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
|
# Fuction recognize intents and connect them to the right actions
|
||||||
|
import paho.mqtt.client as mqtt
|
||||||
|
import json
|
||||||
|
from time import sleep
|
||||||
|
from logic import tts, read_script
|
||||||
|
from config import characters, directions
|
||||||
|
|
||||||
|
HOST = 'localhost'
|
||||||
|
PORT = 1883
|
||||||
|
|
||||||
|
|
||||||
|
def on_connect(client, userdata, flags, rc):
|
||||||
|
print("Connected to {0} with result code {1}".format(HOST, rc))
|
||||||
|
# Subscribe to the text detected topic
|
||||||
|
client.subscribe("hermes/asr/textCaptured")
|
||||||
|
client.subscribe("hermes/nlu/intentNotRecognized")
|
||||||
|
client.subscribe('hermes/intent/jocavdh:ask')
|
||||||
|
client.subscribe('hermes/intent/jocavdh:answer_yes')
|
||||||
|
client.subprocess('hermes/dialogueManager/sessionEnded')
|
||||||
|
client.subprocess('hermes/dialogueManager/sessionStarted')
|
||||||
|
|
||||||
|
def on_introduce(client,data,msg):
|
||||||
|
data = json.loads(msg.payload)
|
||||||
|
sessionId = data['sessionId']
|
||||||
|
|
||||||
|
for character, line, direction in read_script('play_scripts/demo.txt'):
|
||||||
|
input_text = line
|
||||||
|
voice = characters.get(character)[0]
|
||||||
|
speaker = characters.get(character)[1]
|
||||||
|
#speaker = 'default'
|
||||||
|
# Some way to do something with the stage directions will come here
|
||||||
|
action = directions.get(direction[0])
|
||||||
|
tts(voice, input_text, speaker)
|
||||||
|
|
||||||
|
client.publish('hermes/dialogueManager/endSession', json.dumps({
|
||||||
|
'sessionId': sessionId
|
||||||
|
}))
|
||||||
|
|
||||||
|
client.publish('hermes/dialogueManager/startSession', json.dumps({
|
||||||
|
'siteId': 'default',
|
||||||
|
'init': {'type': 'action', 'canBeEnqueued': False, 'intentFilter':['jocavdh:answer_yes']}
|
||||||
|
}))
|
||||||
|
|
||||||
|
|
||||||
|
def on_answer(client,data,msg):
|
||||||
|
|
||||||
|
data = json.loads(msg.payload)
|
||||||
|
answer_value = data['slots'][0]['value']['value']
|
||||||
|
print(answer_value)
|
||||||
|
|
||||||
|
if answer_value == 'yes':
|
||||||
|
input_text = 'Lorem ipsum'
|
||||||
|
|
||||||
|
if answer_value == 'no':
|
||||||
|
input_text = 'nope nope nope'
|
||||||
|
|
||||||
|
voice = "dfki-obadiah"
|
||||||
|
speaker = 'default'
|
||||||
|
|
||||||
|
tts(voice, input_text, speaker)
|
||||||
|
|
||||||
|
print('The play is over.')
|
||||||
|
|
||||||
|
|
||||||
|
client = mqtt.Client()
|
||||||
|
client.connect(HOST, PORT, 60)
|
||||||
|
client.on_connect = on_connect
|
||||||
|
client.connected_flag=False
|
||||||
|
client.message_callback_add('hermes/intent/jocavdh:ask', on_introduce)
|
||||||
|
client.message_callback_add('hermes/intent/jocavdh:answer_yes', on_answer)
|
||||||
|
client.message_callback_add('hermes/intent/jocavdh:no', on_answer)
|
||||||
|
print('main')
|
||||||
|
listening = False
|
||||||
|
|
||||||
|
client.loop_forever()
|
@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# play_config.py
|
||||||
|
# This script contains the basic configuration of the play
|
||||||
|
# A list of the characters and their voices
|
||||||
|
# A list of stage directions which connect to formal instructions for the hardware
|
||||||
|
# ---
|
||||||
|
|
||||||
|
# Define sound output device here
|
||||||
|
# sound_output_device = sc.get_speaker('Scarlett')
|
||||||
|
|
||||||
|
# Dictionary to link characters to the right voice
|
||||||
|
characters = {"ROGUE":["dfki-prudence", "mono1"], "SAINT":["dfki-obadiah", "mono2"], "RASA":["dfki-poppy-hsmm", "mono3"] }
|
||||||
|
|
||||||
|
# Dictionary to link stage directions to a particular formal action
|
||||||
|
directions = {
|
||||||
|
'Wait for audience':'listen_audience',
|
||||||
|
'Listens to Google Home':'listen_google_home',
|
||||||
|
'Music':'audio'
|
||||||
|
}
|
@ -0,0 +1,185 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
|
# play_logic.py
|
||||||
|
# This script contains the logic to turn the play_script into instructions for the hardware
|
||||||
|
# ---
|
||||||
|
|
||||||
|
# 01 FUNTION TO PROCESS THEATRE SCRIPT
|
||||||
|
import re
|
||||||
|
from config import characters, directions
|
||||||
|
|
||||||
|
|
||||||
|
def read_script(filename):
|
||||||
|
lines = []
|
||||||
|
|
||||||
|
with open(filename, 'r') as f:
|
||||||
|
for line in f.readlines():
|
||||||
|
#print(line)
|
||||||
|
parts = re.match(r'(?P<character>^.+?):\s?(\[(?P<stage_directions>[^]]+)\])?\s?(?P<text>.*)', line)
|
||||||
|
parts_character = parts.group('character')
|
||||||
|
parts_text = parts.group('text')
|
||||||
|
parts_directions = str(parts.group('stage_directions')).split(".")
|
||||||
|
|
||||||
|
lines.append((parts_character,parts_text,parts_directions))
|
||||||
|
|
||||||
|
#print(lines)
|
||||||
|
return lines;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 02 FUNCTION TO SYNTHESIZE TEXT
|
||||||
|
# based on https://github.com/marytts/marytts-txt2wav/tree/python
|
||||||
|
|
||||||
|
# To play wave files
|
||||||
|
from subprocess import call
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
# Mary server informations
|
||||||
|
mary_host = "localhost"
|
||||||
|
mary_port = "59125"
|
||||||
|
|
||||||
|
# HTTP + URL packages
|
||||||
|
import httplib2
|
||||||
|
import os
|
||||||
|
from urllib.parse import urlencode, quote # For URL creation
|
||||||
|
|
||||||
|
def tts(voice, input_text, speaker):
|
||||||
|
# Build the query
|
||||||
|
query_hash = {"INPUT_TEXT": input_text,
|
||||||
|
"INPUT_TYPE":"TEXT", # Input text
|
||||||
|
"LOCALE":"en_GB",
|
||||||
|
"VOICE": voice, # Voice informations (need to be compatible)
|
||||||
|
"OUTPUT_TYPE":"AUDIO",
|
||||||
|
"AUDIO":"WAVE", # Audio informations (need both)
|
||||||
|
}
|
||||||
|
query = urlencode(query_hash)
|
||||||
|
print("query = \"http://%s:%s/process?%s\"" % (mary_host, mary_port, query))
|
||||||
|
|
||||||
|
# Run the query to mary http server
|
||||||
|
h_mary = httplib2.Http()
|
||||||
|
resp, content = h_mary.request("http://%s:%s/process?" % (mary_host, mary_port), "POST", query)
|
||||||
|
|
||||||
|
# Decode the wav file or raise an exception if no wav files
|
||||||
|
if (resp["content-type"] == "audio/x-wav"):
|
||||||
|
|
||||||
|
# Write the wav file
|
||||||
|
fpath = os.path.join(os.path.dirname(__file__), '/tmp/output_wav.wav')
|
||||||
|
f = open(fpath, "wb")
|
||||||
|
f.write(content)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
# aplay -D mono3 /tmp/output_wav.wav
|
||||||
|
|
||||||
|
call(["aplay", fpath])
|
||||||
|
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise Exception(content)
|
||||||
|
|
||||||
|
|
||||||
|
# 03 FUNCTIONS TO RUN THE PLAY ON THE SPEAKERS
|
||||||
|
import paho.mqtt.client as mqtt
|
||||||
|
import json
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
HOST = 'localhost'
|
||||||
|
PORT = 1883
|
||||||
|
|
||||||
|
|
||||||
|
def on_connect(client, userdata, flags, rc):
|
||||||
|
print("Connected to {0} with result code {1}".format(HOST, rc))
|
||||||
|
# Subscribe to the text detected topic
|
||||||
|
client.subscribe("hermes/asr/textCaptured")
|
||||||
|
client.subscribe("hermes/nlu/intentNotRecognized")
|
||||||
|
client.subscribe('hermes/intent/jocavdh:ask')
|
||||||
|
client.subscribe('hermes/intent/jocavdh:answer_yes')
|
||||||
|
client.subprocess('hermes/dialogueManager/sessionEnded')
|
||||||
|
client.subprocess('hermes/dialogueManager/sessionStarted')
|
||||||
|
|
||||||
|
|
||||||
|
def on_message(client, userdata, msg):
|
||||||
|
print('Google Home is not speaking anymore')
|
||||||
|
client.connected_flag=True
|
||||||
|
|
||||||
|
# def on_waiting(client, userdata, msg):
|
||||||
|
# sessionId = json.loads(id.payload)
|
||||||
|
# print('delete mistaken intent')
|
||||||
|
# client.publish("hermes/dialogueManager/endSession", json.dumps({
|
||||||
|
# 'sessionId': sessionId,
|
||||||
|
# }))
|
||||||
|
|
||||||
|
client = mqtt.Client()
|
||||||
|
client.connect(HOST, PORT, 60)
|
||||||
|
client.on_connect = on_connect
|
||||||
|
client.connected_flag=False
|
||||||
|
|
||||||
|
listening = False
|
||||||
|
|
||||||
|
|
||||||
|
def play():
|
||||||
|
for character, line, direction in read_script('play_scripts/demo.txt'):
|
||||||
|
input_text = line
|
||||||
|
voice = characters.get(character)[0]
|
||||||
|
speaker = characters.get(character)[1]
|
||||||
|
#speaker = 'default'
|
||||||
|
# Some way to do something with the stage directions will come here
|
||||||
|
action = directions.get(direction[0])
|
||||||
|
tts(voice, input_text, speaker)
|
||||||
|
|
||||||
|
if action == 'listen_google_home':
|
||||||
|
print('Waiting for the Google Home to finish its talk')
|
||||||
|
|
||||||
|
# # start voice activity detection
|
||||||
|
# client.publish("hermes/asr/startListening", json.dumps({
|
||||||
|
# 'siteId': 'default',
|
||||||
|
# 'init': {
|
||||||
|
# 'type': 'action',
|
||||||
|
# 'canBeEnqueued': True
|
||||||
|
# }
|
||||||
|
# }))
|
||||||
|
|
||||||
|
client.publish("hermes/asr/startListening", json.dumps({
|
||||||
|
'siteId': 'default'
|
||||||
|
}))
|
||||||
|
|
||||||
|
# create callback
|
||||||
|
client.on_message = on_message
|
||||||
|
listening = True
|
||||||
|
|
||||||
|
while listening:
|
||||||
|
client.loop()
|
||||||
|
|
||||||
|
#client.on_message = on_message
|
||||||
|
client.message_callback_add('hermes/asr/textCaptured', on_message)
|
||||||
|
|
||||||
|
if client.connected_flag:
|
||||||
|
sleep(1)
|
||||||
|
print('Continue the play')
|
||||||
|
client.connected_flag = False
|
||||||
|
# client.message_callback_add('hermes/dialogueManager/sessionQueued', on_waiting)
|
||||||
|
break
|
||||||
|
|
||||||
|
if action == 'audio':
|
||||||
|
print('play audioclip')
|
||||||
|
playing = True
|
||||||
|
|
||||||
|
while playing:
|
||||||
|
call(["aplay", "-D", speaker, "/usr/share/snips/congress.wav"])
|
||||||
|
playing = False
|
||||||
|
|
||||||
|
if action == 'listen_audience':
|
||||||
|
print('ask the audience')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
sleep(1)
|
||||||
|
|
||||||
|
|
||||||
|
print('This act is done.')
|
||||||
|
|
||||||
|
return
|
@ -0,0 +1 @@
|
|||||||
|
ROGUE: Give me
|
@ -0,0 +1 @@
|
|||||||
|
ROGUE: Hi, I am rogue. Are you Joca?
|
@ -0,0 +1,3 @@
|
|||||||
|
# Needed for Snips platform 1.1.0 (0.61.1)
|
||||||
|
hermes-python>=0.3.3
|
||||||
|
toml
|
@ -0,0 +1,34 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Copy config.ini.default if it exists and config.ini doesn't exist.
|
||||||
|
if [ -e config.ini.default ] && [ ! -e config.ini ]; then
|
||||||
|
cp config.ini.default config.ini
|
||||||
|
chmod a+w config.ini
|
||||||
|
fi
|
||||||
|
|
||||||
|
PYTHON=$(command -v python3)
|
||||||
|
VENV=venv
|
||||||
|
|
||||||
|
if [ -f "$PYTHON" ]; then
|
||||||
|
|
||||||
|
if [ ! -d $VENV ]; then
|
||||||
|
# Create a virtual environment if it doesn't exist.
|
||||||
|
$PYTHON -m venv $VENV
|
||||||
|
else
|
||||||
|
if [ -e $VENV/bin/python2 ]; then
|
||||||
|
# If a Python2 environment exists, delete it first
|
||||||
|
# before creating a new Python 3 virtual environment.
|
||||||
|
rm -r $VENV
|
||||||
|
$PYTHON -m venv $VENV
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Activate the virtual environment and install requirements.
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
. $VENV/bin/activate
|
||||||
|
pip3 install -r requirements.txt
|
||||||
|
|
||||||
|
else
|
||||||
|
>&2 echo "Cannot find Python 3. Please install it."
|
||||||
|
fi
|
Binary file not shown.
Loading…
Reference in New Issue