first commit
This commit is contained in:
commit
84c303a0c7
|
@ -0,0 +1,35 @@
|
|||
Accueil téléphonique eo
|
||||
-----------------------
|
||||
|
||||
Il nécessite un serveur vocal acceptant des scripts VXML, comme celui d'OVH.
|
||||
|
||||
Script WSGI
|
||||
-----------
|
||||
|
||||
Le script vxml.wsgi est basé sur flask et requests, il propose deux vues:
|
||||
|
||||
/play?text=<utf-8 texte>
|
||||
|
||||
synthèse vocale du texte envoyé, les fichiers wav généré sont mis en cache en utilisant le hash SHA1
|
||||
du texte comme clé. Ils sont conservé dans le répertoire `sounds` du répertoire courant.
|
||||
|
||||
/vxml/<path>
|
||||
|
||||
transforme le fichier VXML donné qui doit se trouver dans le chemin courant de lors de l'exécution
|
||||
du script WSGI, il modifie toutes les balices `voice` pour les faire pointer vers la vue de
|
||||
synthèse vocale.
|
||||
|
||||
Le script record.wsgi est conçu pour recevoir les fichiers wav généré par les balises `record` du
|
||||
VXML sur le serveur vocal d'OVH.
|
||||
|
||||
Script VXML
|
||||
-----------
|
||||
|
||||
entrouvert.vxml
|
||||
|
||||
script VXML principal pour l'accueil téléphonique entrouvert
|
||||
|
||||
record.vxml
|
||||
|
||||
sous script pour la fonctionnalité répondeur, il permet principalement de conserver le
|
||||
numéro de l'appelant dans le nom du fichier wav généré.
|
|
@ -0,0 +1,116 @@
|
|||
<?xml version="1.0"?>
|
||||
<vxml xmlns="http://www.w3.org/2001/vxml" version="2.0" xml:lang="fr-FR">
|
||||
<var name="callDuration"/>
|
||||
<var name="number"/>
|
||||
<property name="inputmodes" value="dtmf"/>
|
||||
<form id="startMenu">
|
||||
<field name="level1" type="digits?length=1">
|
||||
<audio>
|
||||
Bienvenue chez Entr'ouvert.
|
||||
Vous souhaitez parler à une personne en particulier, tapez 1.
|
||||
Vous souhaitez laisser un message au service su porc, tapez 2.
|
||||
Vous souhaitez une information sur nos services, tapez 3.
|
||||
Pour réécouter ce message, tapez 4.
|
||||
</audio>
|
||||
</field>
|
||||
<filled>
|
||||
<if cond="level1 == 1">
|
||||
<goto next="#workers"/>
|
||||
<elseif cond="level1 == 2"/>
|
||||
<audio>
|
||||
Votre demande de support va être enregistrée après le bip; vous pouvez également utiliser l'adresse électronique qui vous a été communiquée.
|
||||
</audio>
|
||||
<goto next="#support"/>
|
||||
<elseif cond="level1 == 3"/>
|
||||
<goto next="#sales"/>
|
||||
</if>
|
||||
<goto next="#startMenu"/>
|
||||
</filled>
|
||||
</form>
|
||||
<form id="workers">
|
||||
<field name="level2" type="digits?length=1">
|
||||
<audio>
|
||||
Pour Mikael Atès, tapez 1.
|
||||
Pour Victor Claudet, le 2.
|
||||
Pierre Crosse, le 3.
|
||||
</audio>
|
||||
<audio>
|
||||
Brice Mallet, le 4.
|
||||
une personne du siège, le 5.
|
||||
et revenir à l'accueil, le 6.
|
||||
</audio>
|
||||
</field>
|
||||
<filled>
|
||||
<if cond="level2 == 3">
|
||||
<goto next="#pierre"/>
|
||||
</if>
|
||||
<if cond="level2 == 2">
|
||||
<goto next="#totor"/>
|
||||
</if>
|
||||
<if cond="level2 == 1">
|
||||
<goto next="#mike"/>
|
||||
</if>
|
||||
<if cond="level2 == 4">
|
||||
<goto next="#brice"/>
|
||||
</if>
|
||||
<if cond="level2 == 5">
|
||||
<goto next="#bureau"/>
|
||||
</if>
|
||||
<goto next="#startMenu"/>
|
||||
</filled>
|
||||
</form>
|
||||
<form id="returnFromTransfer">
|
||||
<block> Au revoir. Durée de l'appel : <value expr="callDuration"/> secondes
|
||||
</block>
|
||||
</form>
|
||||
<form id="bureau">
|
||||
<transfer name="callResult" bridge="true" dest="number/0185098350">
|
||||
<filled>
|
||||
<assign name="callDuration" expr="services$.duration"/>
|
||||
<goto next="#returnFromTransfer"/>
|
||||
</filled>
|
||||
</transfer>
|
||||
</form>
|
||||
<form id="pierre">
|
||||
<transfer name="callResult" bridge="true" dest="number/0184162456">
|
||||
<filled>
|
||||
<assign name="callDuration" expr="services$.duration"/>
|
||||
<goto next="#returnFromTransfer"/>
|
||||
</filled>
|
||||
</transfer>
|
||||
</form>
|
||||
<form id="mike">
|
||||
<transfer name="callResult" bridge="true" dest="number/0184162451">
|
||||
<filled>
|
||||
<assign name="callDuration" expr="services$.duration"/>
|
||||
<goto next="#returnFromTransfer"/>
|
||||
</filled>
|
||||
</transfer>
|
||||
</form>
|
||||
<form id="totor">
|
||||
<transfer name="callResult" bridge="true" dest="number/0184162452">
|
||||
<filled>
|
||||
<assign name="callDuration" expr="services$.duration"/>
|
||||
<goto next="#returnFromTransfer"/>
|
||||
</filled>
|
||||
</transfer>
|
||||
</form>
|
||||
<form id="brice">
|
||||
<transfer name="callResult" bridge="true" dest="number/0184162454">
|
||||
<filled>
|
||||
<assign name="callDuration" expr="services$.duration"/>
|
||||
<goto next="#returnFromTransfer"/>
|
||||
</filled>
|
||||
</transfer>
|
||||
</form>
|
||||
<form id="sales">
|
||||
<transfer name="callResult" bridge="true" dest="number/0185098351">
|
||||
</transfer>
|
||||
</form>
|
||||
<form id="support">
|
||||
<block>
|
||||
<assign name="number" expr="session.connection.remote.uri"/>
|
||||
<submit method="post" next="record.vxml" namelist="number" />
|
||||
</block>
|
||||
</form>
|
||||
</vxml>
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0"?>
|
||||
<vxml xmlns="http://www.w3.org/2001/vxml" version="2.0" xml:lang="fr-FR">
|
||||
<var name="callDuration"/>
|
||||
<property name="inputmodes" value="dtmf"/>
|
||||
<form>
|
||||
<record name="awaymessage" beep="true" maxtime="600s" dest="{number[0]}" finalsilence="20s" dtmfterm="true">
|
||||
</record>
|
||||
</form>
|
||||
</vxml>
|
|
@ -0,0 +1,37 @@
|
|||
import site
|
||||
import sys
|
||||
import os
|
||||
|
||||
prev_sys_path = list(sys.path)
|
||||
|
||||
site.addsitedir('/home/bdauvergne/venv/lib/python2.7/site-packages/')
|
||||
# Reorder sys.path so new directories at the front.
|
||||
new_sys_path = []
|
||||
for item in list(sys.path):
|
||||
if item not in prev_sys_path:
|
||||
new_sys_path.append(item)
|
||||
sys.path.remove(item)
|
||||
sys.path[:0] = new_sys_path
|
||||
|
||||
from flask import Flask, request, Response, __version__
|
||||
from werkzeug.debug import DebuggedApplication
|
||||
from werkzeug.urls import url_encode
|
||||
|
||||
import os
|
||||
import hashlib
|
||||
import requests
|
||||
import subprocess
|
||||
|
||||
secret = 'secret'
|
||||
|
||||
app = Flask(__name__)
|
||||
app.debug = True
|
||||
application = DebuggedApplication(app, evalex=True) # The trick is HERE! Add this extra line!
|
||||
|
||||
@app.route("/", methods=['GET', 'POST'])
|
||||
def record():
|
||||
if request.method == 'POST':
|
||||
f = request.files['file']
|
||||
path = '/tmp/'
|
||||
f.save(os.path.join(path, f.filename))
|
||||
return Response('OK')
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" ?>
|
||||
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml" xml:lang="fr-FR">
|
||||
<property name="inputmodes" value="dtmf"/>
|
||||
<var name="numappelant"/>
|
||||
<form id="guessNumber">
|
||||
<field name="guess1" type="digits?length=1" >
|
||||
<prompt>
|
||||
Guess what the computer is thinking! Pick a number between 0 and 9.
|
||||
</prompt>
|
||||
</field>
|
||||
|
||||
<field name="guess2" type="digits?length=1" >
|
||||
<prompt>
|
||||
Guess what the computer is thinking now! Pick a number between 0 and 9.
|
||||
</prompt>
|
||||
<filled>
|
||||
You guessed <value expr="guess1"/> and <value expr="guess2"/>.
|
||||
</filled>
|
||||
</field>
|
||||
</form>
|
||||
</vxml>
|
|
@ -0,0 +1,66 @@
|
|||
import site
|
||||
import sys
|
||||
|
||||
prev_sys_path = list(sys.path)
|
||||
|
||||
site.addsitedir('/home/bdauvergne/venv/lib/python2.7/site-packages/')
|
||||
# Reorder sys.path so new directories at the front.
|
||||
new_sys_path = []
|
||||
for item in list(sys.path):
|
||||
if item not in prev_sys_path:
|
||||
new_sys_path.append(item)
|
||||
sys.path.remove(item)
|
||||
sys.path[:0] = new_sys_path
|
||||
|
||||
from flask import Flask, request, Response, __version__
|
||||
from werkzeug.debug import DebuggedApplication
|
||||
from werkzeug.urls import url_encode
|
||||
|
||||
import os
|
||||
import hashlib
|
||||
import requests
|
||||
import subprocess
|
||||
|
||||
secret = 'secret'
|
||||
|
||||
app = Flask(__name__)
|
||||
app.debug = True
|
||||
application = DebuggedApplication(app, evalex=True) # The trick is HERE! Add this extra line!
|
||||
|
||||
default_voice = 'Emma' # 'Agnes' # 'Becool' # 'Moussa' # 'Agnes'
|
||||
|
||||
@app.route("/play")
|
||||
def play():
|
||||
text = request.args.get('text')
|
||||
voice = request.args.get('voice', default_voice)
|
||||
key_prehash = secret + voice + text
|
||||
key = hashlib.md5(key_prehash.encode('utf8')).hexdigest()
|
||||
path = os.path.join('sounds', key+'.wav')
|
||||
if not os.path.exists(path):
|
||||
r = requests.get('http://voxygen.fr/sites/all/modules/voxygen_voices/assets/proxy/index.php',
|
||||
params=dict(method='redirect', text=text, voice=voice))
|
||||
p = subprocess.Popen('/usr/bin/sox -t mp3 - -r 8k -c 1 -t wav -'.split(), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
out, err = p.communicate(input=r.content)
|
||||
with file(path, 'w') as f:
|
||||
f.write(out)
|
||||
return Response(file(path), mimetype="audio/x-wav")
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
@app.route("/vxml/<path:path>", methods=['GET', 'POST'])
|
||||
def vxml(path, voice=default_voice):
|
||||
tree = ET.parse(path)
|
||||
root = tree.getroot()
|
||||
if request.form:
|
||||
for node in root.iter():
|
||||
for key in node.attrib:
|
||||
node.attrib[key] = node.attrib[key].format(**request.form)
|
||||
for audio in root.findall('.//{http://www.w3.org/2001/vxml}audio'):
|
||||
play_voice = voice
|
||||
if 'voice' in audio.attrib:
|
||||
play_voice = audio.attrib['voice']
|
||||
del audio.attrib['voice']
|
||||
q = dict(voice=play_voice, text=audio.text)
|
||||
url = '/~bdauvergne/vxml.wsgi/play?%s' % url_encode(q)
|
||||
audio.attrib['src'] = url
|
||||
return Response(ET.tostring(root), mimetype='application/xml')
|
Reference in New Issue