Skip to content

Commit 1b388bb

Browse files
author
Attila Ujj
committed
Merge remote-tracking branch 'origin/master'
2 parents 0438555 + 0d7e560 commit 1b388bb

30 files changed

+988
-2
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module.exports = {
2+
env: {
3+
browser: true,
4+
commonjs: true,
5+
es2021: true
6+
},
7+
extends: [
8+
'standard'
9+
],
10+
parserOptions: {
11+
ecmaVersion: 12
12+
},
13+
rules: {
14+
}
15+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
node_modules
2+
package-lock.json
3+
yarn.lock
4+
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Socket.IO chat</title>
5+
<style>
6+
body { margin: 0; padding-bottom: 3rem; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }
7+
8+
#form { background: rgba(0, 0, 0, 0.15); padding: 0.25rem; position: fixed; bottom: 0; left: 0; right: 0; display: flex; height: 3rem; box-sizing: border-box; backdrop-filter: blur(10px); }
9+
#input { border: none; padding: 0 1rem; flex-grow: 1; border-radius: 2rem; margin: 0.25rem; }
10+
#input:focus { outline: none; }
11+
#form > button { background: #333; border: none; padding: 0 1rem; margin: 0.25rem; border-radius: 3px; outline: none; color: #fff; }
12+
13+
#messages { list-style-type: none; margin: 0; padding: 0; }
14+
#messages > li { padding: 0.5rem 1rem; }
15+
#messages > li:nth-child(odd) { background: #efefef; }
16+
</style>
17+
</head>
18+
<body>
19+
<ul id="messages"></ul>
20+
<form id="form" action="">
21+
<input id="input" autocomplete="off" /><button>Send</button>
22+
</form>
23+
<script src="/socket.io/socket.io.js"></script>
24+
<script>
25+
var socket = io();
26+
27+
var form = document.getElementById('form');
28+
var input = document.getElementById('input');
29+
30+
form.addEventListener('submit', function(e) {
31+
e.preventDefault();
32+
if (input.value) {
33+
socket.emit('user_uttered', { message: input.value });
34+
var item = document.createElement('li');
35+
item.textContent = 'ME: ' + input.value;
36+
messages.appendChild(item);
37+
window.scrollTo(0, document.body.scrollHeight);
38+
input.value = '';
39+
}
40+
});
41+
socket.on('bot_uttered', function(msg) {
42+
var item = document.createElement('li');
43+
item.textContent = 'BOT: ' + msg.text;
44+
messages.appendChild(item);
45+
window.scrollTo(0, document.body.scrollHeight);
46+
});
47+
</script>
48+
</body>
49+
</html>

connectors/sapcai/server/index.js

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
const path = require('path')
2+
const { nanoid } = require('nanoid')
3+
const cors = require('cors')
4+
const axios = require('axios')
5+
const app = require('express')()
6+
const http = require('http').Server(app)
7+
const io = require('socket.io')(http)
8+
9+
const SAPCAI_TOKEN = process.env.SAPCAI_TOKEN
10+
11+
app.use(cors())
12+
13+
app.get('/', (req, res) => {
14+
res.sendFile(path.join(__dirname, 'index.html'))
15+
})
16+
17+
io.on('connection', (socket) => {
18+
console.log('user connected')
19+
socket.on('disconnect', () => {
20+
console.log('user disconnected')
21+
})
22+
socket.on('session_request', (msg) => {
23+
console.log('session_request', msg)
24+
if (msg && msg.session_id) {
25+
socket.emit('session_confirm', { session_id: msg.session_id })
26+
} else {
27+
socket.emit('session_confirm', { session_id: nanoid() })
28+
}
29+
})
30+
socket.on('user_uttered', async (msg) => {
31+
if (msg && msg.message) {
32+
let textInput = msg.message
33+
34+
if (msg.message.startsWith('data:')) {
35+
console.log('user_uttered audio')
36+
37+
const base64Data = msg.message.substring(msg.message.indexOf(',') + 1)
38+
const audioData = Buffer.from(base64Data, 'base64')
39+
console.log(`Received data length ${audioData.length}`)
40+
41+
const wavToMonoWavRequestOptions = {
42+
method: 'POST',
43+
url: 'https://speech.botiumbox.com/api/convert/WAVTOMONOWAV',
44+
data: audioData,
45+
headers: {
46+
'content-type': 'audio/wav'
47+
},
48+
responseType: 'arraybuffer'
49+
}
50+
const wavToMonoWavResponse = await axios(wavToMonoWavRequestOptions)
51+
console.log(`Converted to mono wav length ${wavToMonoWavResponse.data.length}`)
52+
53+
const sttRequestOptions = {
54+
method: 'POST',
55+
url: 'https://speech.botiumbox.com/api/stt/en',
56+
data: wavToMonoWavResponse.data,
57+
headers: {
58+
'content-type': 'audio/wav'
59+
},
60+
responseType: 'json'
61+
}
62+
const sttResponse = await axios(sttRequestOptions)
63+
console.log('sttResponse', JSON.stringify(sttResponse.data, null, 2))
64+
65+
textInput = sttResponse.data.text
66+
} else {
67+
console.log('user_uttered text', msg)
68+
}
69+
70+
const requestOptions = {
71+
method: 'POST',
72+
url: 'https://api.cai.tools.sap/build/v1/dialog',
73+
headers: {
74+
Authorization: `Token ${SAPCAI_TOKEN}`
75+
},
76+
data: {
77+
message: {
78+
type: 'text',
79+
content: textInput
80+
},
81+
conversation_id: msg.session_id || nanoid()
82+
}
83+
}
84+
try {
85+
const response = await axios(requestOptions)
86+
console.log('sap response', JSON.stringify(response.data, null, 2))
87+
88+
for (const message of response.data.results.messages.filter(t => t.type === 'text')) {
89+
const botUttered = {
90+
text: message.content.replace(/([\u2700-\u27BF]|[\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2011-\u26FF]|\uD83E[\uDD10-\uDDFF])/g, '')
91+
}
92+
93+
const ttsRequestOptions = {
94+
method: 'GET',
95+
url: 'https://speech.botiumbox.com/api/tts/en',
96+
params: {
97+
text: message.content,
98+
voice: 'dfki-poppy-hsmm'
99+
},
100+
responseType: 'arraybuffer'
101+
}
102+
const ttsResponse = await axios(ttsRequestOptions)
103+
botUttered.link = 'data:audio/wav;base64,' + Buffer.from(ttsResponse.data, 'binary').toString('base64')
104+
105+
socket.emit('bot_uttered', botUttered)
106+
}
107+
} catch (err) {
108+
console.log(err.message)
109+
}
110+
}
111+
})
112+
})
113+
114+
const port = process.env.PORT || 5005
115+
http.listen(port, () => {
116+
console.log('listening on *:' + port)
117+
})
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "botium-speech-processing-sapcai-server",
3+
"version": "1.0.0",
4+
"main": "index.js",
5+
"license": "MIT",
6+
"scripts": {
7+
"eslint": "eslint --fix index.js",
8+
"start": "node index.js"
9+
},
10+
"dependencies": {
11+
"axios": "^0.21.1",
12+
"cors": "^2.8.5",
13+
"express": "^4.17.1",
14+
"nanoid": "^3.1.20",
15+
"socket.io": "^2.2.0"
16+
},
17+
"devDependencies": {
18+
"eslint": "^7.20.0",
19+
"eslint-config-standard": "^16.0.2",
20+
"eslint-plugin-import": "^2.22.1",
21+
"eslint-plugin-node": "^11.1.0",
22+
"eslint-plugin-promise": "^4.3.1"
23+
}
24+
}

frontend/src/swagger.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"openapi": "3.0.0",
33
"info": {
44
"title": "Botium Speech Processing API",
5-
"version": "1.0.2",
5+
"version": "1.0.3",
66
"description": "Botium Speech Processing API"
77
},
88
"basePath": "/",

frontend/src/swaggerDef.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"openapi": "3.0.0",
33
"info": {
44
"title": "Botium Speech Processing API",
5-
"version": "1.0.2",
5+
"version": "1.0.3",
66
"description": "Botium Speech Processing API"
77
},
88
"basePath": "/"

scripts/k8s/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
##k8s
2+
Some predefined kubernetes workload collection:
3+
* default: marytts+kaldi (see docker-compose.yaml)
4+
* google: just google (see docker-compose-google.yaml)
5+
* picotts picotts+kaldi (see docker-compose-picotts.yaml)
6+
7+
To use it:
8+
* replace placeholders in a dir
9+
* deploy it `kubectl apply -R -f default`
10+
* undeploy it `kubectl delete -R -f default`
11+
12+
Do not modify and commit directly. Workload files are generated from helm chat!

scripts/k8s/default/01-secrets.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
# Source: botium-speech-processing/templates/01-secrets.yml
3+
apiVersion: v1
4+
kind: Secret
5+
metadata:
6+
name: botium-speech-processing-secrets
7+
labels:
8+
name: secrets
9+
app: botium-speech-processing
10+
stringData:
11+
AUTH_APIKEYS: ""
12+
BOTIUM_SPEECH_GOOGLE_CLIENT_EMAIL: ""
13+
data:
14+
BOTIUM_SPEECH_GOOGLE_PRIVATE_KEY: ""
15+
type: Opaque
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
# Source: botium-speech-processing/templates/02-configmap.yml
3+
apiVersion: v1
4+
kind: ConfigMap
5+
metadata:
6+
name: botium-speech-processing-configmap
7+
labels:
8+
name: config
9+
app: botium-speech-processing
10+
data:
11+
BOTIUM_SPEECH_PROVIDER_TTS: "marytts"
12+
BOTIUM_SPEECH_PROVIDER_STT: "kaldi"

0 commit comments

Comments
 (0)