mirror of
https://github.com/jambonz/speech-utils.git
synced 2026-05-06 08:47:02 +00:00
add testcase
This commit is contained in:
@@ -1,10 +1,20 @@
|
|||||||
version: '3'
|
version: '3.9'
|
||||||
|
|
||||||
|
networks:
|
||||||
|
speech-utils:
|
||||||
|
driver: bridge
|
||||||
|
ipam:
|
||||||
|
config:
|
||||||
|
- subnet: 172.41.0.0/16
|
||||||
|
|
||||||
services:
|
services:
|
||||||
redis:
|
redis:
|
||||||
image: redis:alpine
|
image: redis:alpine
|
||||||
ports:
|
ports:
|
||||||
- "3379:6379"
|
- "3379:6379"
|
||||||
|
networks:
|
||||||
|
speech-utils:
|
||||||
|
ipv4_address: 172.41.0.5
|
||||||
|
|
||||||
redis-auth:
|
redis-auth:
|
||||||
image: redis:alpine
|
image: redis:alpine
|
||||||
@@ -13,3 +23,17 @@ services:
|
|||||||
- "3380:6379"
|
- "3380:6379"
|
||||||
volumes:
|
volumes:
|
||||||
- ./tmp:/tmp
|
- ./tmp:/tmp
|
||||||
|
networks:
|
||||||
|
speech-utils:
|
||||||
|
ipv4_address: 172.41.0.6
|
||||||
|
|
||||||
|
webhook-tts-scaffold:
|
||||||
|
image: jambonz/webhook-tts-test-scaffold:latest
|
||||||
|
ports:
|
||||||
|
- "3100:3000/tcp"
|
||||||
|
volumes:
|
||||||
|
- ./test-apps:/tmp
|
||||||
|
networks:
|
||||||
|
speech-utils:
|
||||||
|
ipv4_address: 172.41.0.10
|
||||||
|
|
||||||
|
|||||||
+17
-9
@@ -4,6 +4,8 @@ const opts = config.get('redis');
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const {makeSynthKey} = require('../lib/utils');
|
const {makeSynthKey} = require('../lib/utils');
|
||||||
const logger = require('pino')();
|
const logger = require('pino')();
|
||||||
|
const bent = require('bent');
|
||||||
|
const getJSON = bent('json')
|
||||||
|
|
||||||
process.on('unhandledRejection', (reason, p) => {
|
process.on('unhandledRejection', (reason, p) => {
|
||||||
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
|
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
|
||||||
@@ -330,36 +332,42 @@ test('Custom Vendor speech synth tests', async(t) => {
|
|||||||
const fn = require('..');
|
const fn = require('..');
|
||||||
const {synthAudio, client} = fn(opts, logger);
|
const {synthAudio, client} = fn(opts, logger);
|
||||||
|
|
||||||
if (!process.env.CUSTOM_VENDOR_TTS_URL) {
|
|
||||||
t.pass('skipping Custom Vendor speech synth tests since CUSTOM_VENDOR_TTS_URL not provided');
|
|
||||||
return t.end();
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
let opts = await synthAudio(stats, {
|
let opts = await synthAudio(stats, {
|
||||||
vendor: 'custom:somethingnew',
|
vendor: 'custom:somethingnew',
|
||||||
credentials: {
|
credentials: {
|
||||||
use_for_tts: 1,
|
use_for_tts: 1,
|
||||||
custom_tts_url: process.env.CUSTOM_VENDOR_TTS_URL,
|
custom_tts_url: "http://172.41.0.10:3000/somethingnew",
|
||||||
auth_token: 'some_jwt_token'
|
auth_token: 'some_jwt_token'
|
||||||
},
|
},
|
||||||
language: 'en-US',
|
language: 'en-US',
|
||||||
voice: 'English-US.Female-1',
|
voice: 'English-US.Female-1',
|
||||||
text: 'This is a test. This is only a test',
|
text: 'This is a test. This is only a test',
|
||||||
});
|
});
|
||||||
t.ok(!opts.servedFromCache, `successfully synthesized nuance audio to ${opts.filePath}`);
|
t.ok(!opts.servedFromCache, `successfully synthesized custom vendor audio to ${opts.filePath}`);
|
||||||
|
let obj = await getJSON(`http://127.0.0.1:3100/lastRequest/somethingnew`);
|
||||||
|
t.ok(obj.headers.Authorization == 'Bearer some_jwt_token', 'Custom Vendor Authentication Header is correct');
|
||||||
|
t.ok(obj.body.language == 'en-US', 'Custom Vendor Language is correct');
|
||||||
|
t.ok(obj.body.format == 'audio/mpeg', 'Custom Vendor format is correct');
|
||||||
|
t.ok(obj.body.voice == 'English-US.Female-1', 'Custom Vendor voice is correct');
|
||||||
|
t.ok(obj.body.type == 'text', 'Custom Vendor type is correct');
|
||||||
|
t.ok(obj.body.text == 'This is a test. This is only a test', 'Custom Vendor text is correct');
|
||||||
|
|
||||||
opts = await synthAudio(stats, {
|
opts = await synthAudio(stats, {
|
||||||
vendor: 'custom:somethingnew',
|
vendor: 'custom:somethingnew2',
|
||||||
credentials: {
|
credentials: {
|
||||||
use_for_tts: 1,
|
use_for_tts: 1,
|
||||||
custom_tts_url: process.env.CUSTOM_VENDOR_TTS_URL,
|
custom_tts_url: "http://172.41.0.10:3000/somethingnew2",
|
||||||
auth_token: 'some_jwt_token'
|
auth_token: 'some_jwt_token'
|
||||||
},
|
},
|
||||||
language: 'en-US',
|
language: 'en-US',
|
||||||
voice: 'English-US.Female-1',
|
voice: 'English-US.Female-1',
|
||||||
text: '<speak>This is a test. This is only a test</speak>',
|
text: '<speak>This is a test. This is only a test</speak>',
|
||||||
});
|
});
|
||||||
t.ok(!opts.servedFromCache, `successfully synthesized nuance audio to ${opts.filePath}`);
|
t.ok(!opts.servedFromCache, `successfully synthesized Custom Vendor audio to ${opts.filePath}`);
|
||||||
|
obj = await getJSON(`http://127.0.0.1:3100/lastRequest/somethingnew2`);
|
||||||
|
t.ok(obj.body.type == 'ssml', 'Custom Vendor type is correct');
|
||||||
|
t.ok(obj.body.text == '<speak>This is a test. This is only a test</speak>');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
t.end(err);
|
t.end(err);
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
FROM --platform=linux/amd64 node:18.6.0-alpine as base
|
||||||
|
|
||||||
|
RUN apk --update --no-cache add --virtual .builds-deps build-base python3
|
||||||
|
|
||||||
|
WORKDIR /opt/app/
|
||||||
|
|
||||||
|
FROM base as build
|
||||||
|
|
||||||
|
COPY package.json package-lock.json ./
|
||||||
|
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
FROM base
|
||||||
|
|
||||||
|
COPY --from=build /opt/app /opt/app/
|
||||||
|
|
||||||
|
ARG NODE_ENV
|
||||||
|
|
||||||
|
ENV NODE_ENV $NODE_ENV
|
||||||
|
|
||||||
|
CMD [ "node", "app.js" ]
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const app = express();
|
||||||
|
const Websocket = require('ws');
|
||||||
|
const listenPort = process.env.HTTP_PORT || 3000;
|
||||||
|
let hook_mapping = new Map();
|
||||||
|
let ws_packet_count = new Map();
|
||||||
|
let ws_metadata = new Map();
|
||||||
|
|
||||||
|
/** websocket server for listen audio */
|
||||||
|
const recvAudio = (socket, req) => {
|
||||||
|
let packets = 0;
|
||||||
|
let path = req.url;
|
||||||
|
console.log('received websocket connection');
|
||||||
|
socket.on('message', (data, isBinary) => {
|
||||||
|
if (!isBinary) {
|
||||||
|
try {
|
||||||
|
const msg = JSON.parse(data);
|
||||||
|
console.log({msg}, 'received websocket message');
|
||||||
|
ws_metadata.set(path, msg);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.log({err}, 'error parsing websocket message');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
packets += data.length;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
socket.on('error', (err) => {
|
||||||
|
console.log({err}, 'listen websocket: error');
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('close', () => {
|
||||||
|
ws_packet_count.set(path, packets);
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
const wsServer = new Websocket.Server({ noServer: true });
|
||||||
|
wsServer.setMaxListeners(0);
|
||||||
|
wsServer.on('connection', recvAudio.bind(null));
|
||||||
|
|
||||||
|
const server = app.listen(listenPort, () => {
|
||||||
|
console.log(`sample jambones app server listening on ${listenPort}`);
|
||||||
|
});
|
||||||
|
server.on('upgrade', (request, socket, head) => {
|
||||||
|
console.log('received upgrade request');
|
||||||
|
wsServer.handleUpgrade(request, socket, head, (socket) => {
|
||||||
|
wsServer.emit('connection', socket, request);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(express.urlencoded({ extended: true }));
|
||||||
|
app.use(express.json());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Markup language
|
||||||
|
*/
|
||||||
|
|
||||||
|
app.all('/:key', (req, res) => {
|
||||||
|
let key = req.params.key;
|
||||||
|
console.log(req.body, 'POST /' + key);
|
||||||
|
addRequestToMap(key, req, hook_mapping);
|
||||||
|
return res.json({"audio":"content"})
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fetch Requests
|
||||||
|
app.get('/requests/:key', (req, res) => {
|
||||||
|
let key = req.params.key;
|
||||||
|
if (hook_mapping.has(key)) {
|
||||||
|
return res.json(hook_mapping.get(key));
|
||||||
|
} else {
|
||||||
|
return res.sendStatus(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
app.get('/lastRequest/:key', (req, res) => {
|
||||||
|
let key = req.params.key;
|
||||||
|
if (hook_mapping.has(key)) {
|
||||||
|
let requests = hook_mapping.get(key);
|
||||||
|
return res.json(requests[requests.length - 1]);
|
||||||
|
} else {
|
||||||
|
return res.sendStatus(404);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// WS Fetch
|
||||||
|
app.get('/ws_packet_count/:key', (req, res) => {
|
||||||
|
let key = `/${req.params.key}`;
|
||||||
|
console.log(key, ws_packet_count);
|
||||||
|
if (ws_packet_count.has(key)) {
|
||||||
|
return res.json({ count: ws_packet_count.get(key) });
|
||||||
|
} else {
|
||||||
|
return res.sendStatus(404);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.get('/ws_metadata/:key', (req, res) => {
|
||||||
|
let key = `/${req.params.key}`;
|
||||||
|
console.log(key, ws_packet_count);
|
||||||
|
if (ws_metadata.has(key)) {
|
||||||
|
return res.json({ metadata: ws_metadata.get(key) });
|
||||||
|
} else {
|
||||||
|
return res.sendStatus(404);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function addRequestToMap(key, req, map) {
|
||||||
|
let headers = new Map()
|
||||||
|
for(let i = 0; i < req.rawHeaders.length; i++) {
|
||||||
|
if (i % 2 === 0) {
|
||||||
|
headers.set(req.rawHeaders[i], req.rawHeaders[i + 1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let request = {
|
||||||
|
'url': req.url,
|
||||||
|
'headers': Object.fromEntries(headers),
|
||||||
|
'body': req.body
|
||||||
|
}
|
||||||
|
if (map.has(key)) {
|
||||||
|
map.get(key).push(request);
|
||||||
|
} else {
|
||||||
|
map.set(key, [request]);
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+1045
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "webhook_tts",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "simple webhook tts for test purposes",
|
||||||
|
"main": "app.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node app"
|
||||||
|
},
|
||||||
|
"author": "Dave Horton",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^4.18.2",
|
||||||
|
"ws": "^8.12.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user