Skip to content

Commit 0853cbf

Browse files
author
Botium
authored
Merge pull request #17 from codeforequity-at/develop
1.0.2
2 parents 52631ae + c7b5c96 commit 0853cbf

File tree

6 files changed

+137
-25
lines changed

6 files changed

+137
-25
lines changed

frontend/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ node_modules
22
package-lock.json
33
*.local
44
resources/.cache
5+
resources/.tmp
56
resources/google.json

frontend/resources/.env

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,41 @@ BOTIUM_SPEECH_KALDI_URL_DE=http://stt_de:80/client/dynamic/recognize
4040

4141
# WAV Conversation Command Line
4242
BOTIUM_SPEECH_CONVERT_PROFILE_WAVTOMONOWAV_CMD=sox -t wav - -r 16k -t wav -c 1 -b 16 -e signed {{{output}}}
43+
BOTIUM_SPEECH_CONVERT_PROFILE_WAVTOMONOWAV_DESC=Converts WAV file to a Mono Wav, 16khz, 16bit
4344
BOTIUM_SPEECH_CONVERT_PROFILE_WAVTOMONOWAV_OUTPUT=output.wav
4445
BOTIUM_SPEECH_CONVERT_PROFILE_MP3TOMONOWAV_CMD=sox -t mp3 - -r 16k -t wav -c 1 -b 16 -e signed {{{output}}}
46+
BOTIUM_SPEECH_CONVERT_PROFILE_MP3TOMONOWAV_DESC=Converts MP3 file to a Mono Wav, 16khz, 16bit
4547
BOTIUM_SPEECH_CONVERT_PROFILE_MP3TOMONOWAV_OUTPUT=output.wav
4648
BOTIUM_SPEECH_CONVERT_PROFILE_WEBMTOMONOWAV_CMD=ffmpeg -i - -f wav - | sox -t wav - -r 16k -t wav -c 1 -b 16 -e signed {{{output}}}
49+
BOTIUM_SPEECH_CONVERT_PROFILE_WEBMTOMONOWAV_DESC=Converts WEBM file to a Mono Wav, 16khz, 16bit
4750
BOTIUM_SPEECH_CONVERT_PROFILE_WEBMTOMONOWAV_OUTPUT=output.wav
51+
52+
# Effects Command Lines
53+
BOTIUM_SPEECH_CONVERT_PROFILE_GSM_CMD=sox -t {{{inputtype}}} - -t {{{inputtype}}} -r 8k -c 1 -b 8 -e signed {{{output}}} lowpass 2000 highpass 500
54+
BOTIUM_SPEECH_CONVERT_PROFILE_GSM_DESC=Makes audio sound like a GSM phone call
55+
BOTIUM_SPEECH_CONVERT_PROFILE_ADDLOWNOISE_CMD=sox -t {{{inputtype}}} {{{input}}} -p synth brownnoise vol 0.1 | sox -m {{{input}}} - {{{output}}}
56+
BOTIUM_SPEECH_CONVERT_PROFILE_ADDLOWNOISE_DESC=Adds low volume background noise
57+
BOTIUM_SPEECH_CONVERT_PROFILE_ADDHIGHNOISE_CMD=sox -t {{{inputtype}}} {{{input}}} -p synth brownnoise vol 0.3 | sox -m {{{input}}} - {{{output}}}
58+
BOTIUM_SPEECH_CONVERT_PROFILE_ADDHIGHNOISE_DESC=Adds high volume background noise
59+
BOTIUM_SPEECH_CONVERT_PROFILE_ADDHIGHESTNOISE_CMD=sox -t {{{inputtype}}} {{{input}}} -p synth brownnoise vol 0.5 | sox -m {{{input}}} - {{{output}}}
60+
BOTIUM_SPEECH_CONVERT_PROFILE_ADDHIGHESTNOISE_DESC=Adds killer background noise
61+
BOTIUM_SPEECH_CONVERT_PROFILE_LOWESTVOL_CMD=sox -t {{{inputtype}}} - -t {{{inputtype}}} {{{output}}} vol 0.1
62+
BOTIUM_SPEECH_CONVERT_PROFILE_LOWESTVOL_DESC=Minimizes the volume
63+
BOTIUM_SPEECH_CONVERT_PROFILE_LOWVOL_CMD=sox -t {{{inputtype}}} - -t {{{inputtype}}} {{{output}}} vol 0.5
64+
BOTIUM_SPEECH_CONVERT_PROFILE_LOWVOL_DESC=Turns down the volume
65+
BOTIUM_SPEECH_CONVERT_PROFILE_HIGHVOL_CMD=sox -t {{{inputtype}}} - -t {{{inputtype}}} {{{output}}} vol 2
66+
BOTIUM_SPEECH_CONVERT_PROFILE_HIGHVOL_DESC=Turns up the volume
67+
BOTIUM_SPEECH_CONVERT_PROFILE_HIGHESTVOL_CMD=sox -t {{{inputtype}}} - -t {{{inputtype}}} {{{output}}} vol 4
68+
BOTIUM_SPEECH_CONVERT_PROFILE_HIGHESTVOL_DESC=Maximizes the volume
69+
BOTIUM_SPEECH_CONVERT_PROFILE_BREAKX1_CMD=sox -t {{{inputtype}}} - -t {{{inputtype}}} {{{output}}} pad [email protected]
70+
BOTIUM_SPEECH_CONVERT_PROFILE_BREAKX1_DESC=Adds one artificial silence break
71+
BOTIUM_SPEECH_CONVERT_PROFILE_BREAKX2_CMD=sox -t {{{inputtype}}} - -t {{{inputtype}}} {{{output}}} pad [email protected] [email protected]
72+
BOTIUM_SPEECH_CONVERT_PROFILE_BREAKX2_DESC=Adds two artificial silence breaks
73+
BOTIUM_SPEECH_CONVERT_PROFILE_BREAKX3_CMD=sox -t {{{inputtype}}} - -t {{{inputtype}}} {{{output}}} pad [email protected] [email protected] [email protected]
74+
BOTIUM_SPEECH_CONVERT_PROFILE_BREAKX3_DESC=Adds three artificial silence breaks
75+
BOTIUM_SPEECH_CONVERT_PROFILE_SILENCEX1_CMD=sox -t {{{inputtype}}} - -t {{{inputtype}}} {{{output}}} pad [email protected] trim 0 1.3 0.3
76+
BOTIUM_SPEECH_CONVERT_PROFILE_SILENCEX1_DESC=Replaces one short section with silence
77+
BOTIUM_SPEECH_CONVERT_PROFILE_SILENCEX2_CMD=sox -t {{{inputtype}}} - -t {{{inputtype}}} {{{output}}} pad [email protected] [email protected] trim 0 1.3 0.3 trim 0 2.3 0.3
78+
BOTIUM_SPEECH_CONVERT_PROFILE_SILENCEX2_DESC=Replaces two short sections with silence
79+
BOTIUM_SPEECH_CONVERT_PROFILE_SILENCEX3_CMD=sox -t {{{inputtype}}} - -t {{{inputtype}}} {{{output}}} pad [email protected] [email protected] [email protected] trim 0 1.3 0.3 trim 0 2.3 0.3 trim 0 3.3 0.3
80+
BOTIUM_SPEECH_CONVERT_PROFILE_SILENCEX3_DESC=Replaces three short sections with silence

frontend/src/convert/convert.js

Lines changed: 79 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,75 @@
11
const fs = require('fs')
22
const Mustache = require('mustache')
3-
const { spawn } = require('child_process')
3+
const { spawn, exec } = require('child_process')
44
const { v1: uuidv1 } = require('uuid')
55
const debug = require('debug')('botium-speech-processing-convert')
66

7-
const runconvert = (cmdLine, outputFile, { inputBuffer, start, end }) => {
7+
const _getSoxFileType = (filename) => {
88
return new Promise((resolve, reject) => {
9-
const output = `${process.env.BOTIUM_SPEECH_TMP_DIR || '/tmp'}/${uuidv1()}_${outputFile}`
10-
11-
let cmdLineFull = Mustache.render(cmdLine, { output })
12-
if (start && end) {
13-
cmdLineFull = `${cmdLineFull} trim ${start} ${end}`
14-
} else if (start && !end) {
15-
cmdLineFull = `${cmdLineFull} trim ${start}`
16-
} else if (!start && end) {
17-
cmdLineFull = `${cmdLineFull} trim 0 ${end}`
9+
exec(`soxi -t ${filename}`, (err, stdout, stderr) => {
10+
if (err) return reject(err)
11+
if (stderr) return reject(stderr.trim())
12+
resolve(stdout.trim())
13+
})
14+
})
15+
}
16+
17+
const _isMP3 = (buf) => {
18+
if (!buf || buf.length < 3) {
19+
return false
20+
}
21+
return (buf[0] === 73 &&
22+
buf[1] === 68 &&
23+
buf[2] === 51) || (
24+
buf[0] === 255 &&
25+
(buf[1] === 251 || buf[1] === 250)
26+
)
27+
}
28+
29+
const runconvert = async (cmdLine, outputName, { inputBuffer, start, end }) => {
30+
const jobId = uuidv1()
31+
32+
const writeInput = !outputName || cmdLine.indexOf('{{{input}}}') >= 0 || cmdLine.indexOf('{{{inputtype}}}') >= 0
33+
34+
let input = null
35+
let inputtype = null
36+
37+
if (writeInput) {
38+
input = `${process.env.BOTIUM_SPEECH_TMP_DIR || '/tmp'}/${jobId}_input`
39+
try {
40+
fs.writeFileSync(input, inputBuffer)
41+
} catch (err) {
42+
debug(`conversion process input file ${input} not writable: ${err.message}`)
43+
throw new Error('conversion process input file not writable')
44+
}
45+
if (_isMP3(inputBuffer)) {
46+
inputtype = 'mp3'
47+
} else {
48+
try {
49+
inputtype = await _getSoxFileType(input)
50+
debug(`Identified input type: ${inputtype}`)
51+
} catch (err) {
52+
debug(`identification of input file type ${input} failed: ${err.message}`)
53+
throw new Error('identification of input file type failed')
54+
}
55+
}
56+
if (!outputName) {
57+
outputName = `output.${inputtype}`
1858
}
19-
debug(`cmdLineFull: ${cmdLineFull}`)
59+
}
60+
const output = `${process.env.BOTIUM_SPEECH_TMP_DIR || '/tmp'}/${jobId}_${outputName}`
61+
62+
let cmdLineFull = Mustache.render(cmdLine, { output, input, inputtype })
63+
if (start && end) {
64+
cmdLineFull = `${cmdLineFull} trim ${start} ${end}`
65+
} else if (start && !end) {
66+
cmdLineFull = `${cmdLineFull} trim ${start}`
67+
} else if (!start && end) {
68+
cmdLineFull = `${cmdLineFull} trim 0 ${end}`
69+
}
70+
debug(`cmdLineFull: ${cmdLineFull}`)
71+
72+
return new Promise((resolve, reject) => {
2073
const childProcess = spawn('/bin/sh', ['-c', cmdLineFull])
2174

2275
childProcess.once('exit', (code, signal) => {
@@ -25,13 +78,23 @@ const runconvert = (cmdLine, outputFile, { inputBuffer, start, end }) => {
2578
try {
2679
const outputBuffer = fs.readFileSync(output)
2780
fs.unlinkSync(output)
28-
resolve(outputBuffer)
81+
resolve({
82+
outputName,
83+
outputBuffer
84+
})
2985
} catch (err) {
3086
reject(new Error(`conversion process output file ${output} not readable: ${err.message}`))
3187
}
3288
} else {
3389
reject(new Error(`conversion process exited with code ${code}, signal ${signal}`))
3490
}
91+
if (input) {
92+
try {
93+
fs.unlinkSync(input)
94+
} catch (err) {
95+
debug(`conversion process input file ${input} not deleted: ${err.message}`)
96+
}
97+
}
3598
})
3699
childProcess.once('error', (err) => {
37100
debug(`conversion process failed: ${err.message}`)
@@ -50,7 +113,9 @@ const runconvert = (cmdLine, outputFile, { inputBuffer, start, end }) => {
50113
debug('stderr ' + data)
51114
})
52115

53-
childProcess.stdin.write(inputBuffer)
116+
if (cmdLine.indexOf('{{{input}}}') < 0) {
117+
childProcess.stdin.write(inputBuffer)
118+
}
54119
childProcess.stdin.end()
55120
})
56121
}

frontend/src/routes.js

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -372,10 +372,19 @@ router.get('/api/tts/:language', async (req, res, next) => {
372372
* schema:
373373
* type: array
374374
* items:
375-
* type: string
375+
* type: object
376+
* properties:
377+
* name:
378+
* type: string
379+
* description:
380+
* type: string
376381
*/
377382
router.get('/api/convertprofiles', async (req, res, next) => {
378-
res.json(Object.keys(process.env).filter(e => e.startsWith('BOTIUM_SPEECH_CONVERT_PROFILE_') && e.endsWith('_CMD')).map(e => e.split('_')[4]))
383+
const keys = Object.keys(process.env).filter(e => e.startsWith('BOTIUM_SPEECH_CONVERT_PROFILE_') && e.endsWith('_CMD')).map(e => e.split('_')[4])
384+
return res.json(keys.map(key => ({
385+
name: key,
386+
description: process.env[`BOTIUM_SPEECH_CONVERT_PROFILE_${key}_DESC`] || ''
387+
})))
379388
})
380389

381390
/**
@@ -423,7 +432,6 @@ router.get('/api/convertprofiles', async (req, res, next) => {
423432
* format: binary
424433
*/
425434
router.post('/api/convert/:profile', async (req, res, next) => {
426-
console.log(req.body)
427435
if (!Buffer.isBuffer(req.body)) {
428436
return next(new Error('req.body is not a buffer'))
429437
}
@@ -432,14 +440,11 @@ router.post('/api/convert/:profile', async (req, res, next) => {
432440
return next(new Error(`Environment variable ${envVarCmd} empty`))
433441
}
434442
const envVarOutput = `BOTIUM_SPEECH_CONVERT_PROFILE_${req.params.profile.toUpperCase()}_OUTPUT`
435-
if (!process.env[envVarOutput]) {
436-
return next(new Error(`Environment variable ${envVarOutput} empty`))
437-
}
438443

439444
try {
440-
const outputBuffer = await runconvert(process.env[envVarCmd], process.env[envVarOutput], { inputBuffer: req.body, start: req.query.start, end: req.query.end })
445+
const { outputName, outputBuffer } = await runconvert(process.env[envVarCmd], process.env[envVarOutput], { inputBuffer: req.body, start: req.query.start, end: req.query.end })
441446
res.writeHead(200, {
442-
'Content-disposition': `attachment; filename="${process.env[envVarOutput]}"`,
447+
'Content-disposition': `attachment; filename="${outputName}"`,
443448
'Content-Length': outputBuffer.length
444449
})
445450
res.end(outputBuffer)

frontend/src/swagger.json

Lines changed: 10 additions & 2 deletions
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.1",
5+
"version": "1.0.2",
66
"description": "Botium Speech Processing API"
77
},
88
"basePath": "/",
@@ -325,7 +325,15 @@
325325
"schema": {
326326
"type": "array",
327327
"items": {
328-
"type": "string"
328+
"type": "object",
329+
"properties": {
330+
"name": {
331+
"type": "string"
332+
},
333+
"description": {
334+
"type": "string"
335+
}
336+
}
329337
}
330338
}
331339
}

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.1",
5+
"version": "1.0.2",
66
"description": "Botium Speech Processing API"
77
},
88
"basePath": "/"

0 commit comments

Comments
 (0)