Yurii Paniv commited on
Commit
773a50a
1 Parent(s): ea0a199

Delete telegram bot and web version

Browse files
Dockerfile DELETED
@@ -1,9 +0,0 @@
1
- FROM python:3.7
2
- COPY ./webapp /app
3
- WORKDIR /app
4
- RUN apt-get update
5
- RUN apt-get install -y ffmpeg
6
- RUN wget https://github.com/robinhad/voice-recognition-ua/releases/download/v0.4/uk.tflite
7
- # RUN wget https://github.com/robinhad/voice-recognition-ua/releases/download/v0.4/kenlm.scorer
8
- RUN pip install -r requirements.txt
9
- CMD uwsgi app.ini --http 0.0.0.0:$PORT
 
 
 
 
 
 
 
 
 
 
heroku.yml DELETED
@@ -1,3 +0,0 @@
1
- build:
2
- docker:
3
- web: Dockerfile
 
 
 
 
webapp/.dockerignore DELETED
@@ -1,7 +0,0 @@
1
- __pycache__/
2
- .venv/
3
- .env
4
- .git
5
- LICENSE
6
- README.md
7
- .github/
 
 
 
 
 
 
 
 
webapp/app.ini DELETED
@@ -1,8 +0,0 @@
1
- [uwsgi]
2
- wsgi-file = main.py
3
- callable = app
4
- http = :5000
5
- processes = 1
6
- master = true
7
- vacuum = true
8
- die-on-term = true
 
 
 
 
 
 
 
 
 
webapp/client.py DELETED
@@ -1,43 +0,0 @@
1
- #!/usr/bin/env python
2
- # -*- coding: utf-8 -*-
3
- from __future__ import absolute_import, division, print_function
4
-
5
- import numpy as np
6
- import sys
7
- import wave
8
-
9
- from deepspeech import Model, version
10
- from timeit import default_timer as timer
11
-
12
-
13
- def client(audio_file, lang="uk"):
14
- model_load_start = timer()
15
- # sphinx-doc: python_ref_model_start
16
- model = "./uk.tflite"
17
-
18
- ds = Model(model)
19
- # ds.enableExternalScorer("kenlm.scorer")
20
- # sphinx-doc: python_ref_model_stop
21
- model_load_end = timer() - model_load_start
22
- print('Loaded model in {:.3}s.'.format(model_load_end), file=sys.stderr)
23
-
24
- desired_sample_rate = ds.sampleRate()
25
-
26
- fin = wave.open(audio_file, 'rb')
27
- fs_orig = fin.getframerate()
28
- audio = np.frombuffer(fin.readframes(fin.getnframes()), np.int16)
29
-
30
- audio_length = fin.getnframes() * (1/fs_orig)
31
- fin.close()
32
-
33
- print('Running inference.', file=sys.stderr)
34
- inference_start = timer()
35
- # sphinx-doc: python_ref_inference_start
36
-
37
- result = ds.stt(audio)
38
- print(result)
39
- # sphinx-doc: python_ref_inference_stop
40
- inference_end = timer() - inference_start
41
- print('Inference took %0.3fs for %0.3fs audio file.' %
42
- (inference_end, audio_length), file=sys.stderr)
43
- return result
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
webapp/main.py DELETED
@@ -1,96 +0,0 @@
1
- from flask import Flask, render_template, request
2
- from io import BytesIO
3
- from client import client
4
- import telebot
5
- import logging
6
- import os
7
- import warnings
8
- from client import client
9
- from io import BytesIO
10
- import pydub
11
-
12
- warnings.simplefilter('ignore')
13
- TOKEN = os.environ['TOKEN']
14
-
15
- if not TOKEN:
16
- print('You must set the TOKEN environment variable')
17
- exit(1)
18
-
19
- START_MSG = '''Вітання!
20
- Цей бот створений для тестування перекладу українських аудіозаписів в текст.
21
- Група для обговорення: https://t.me/speech_recognition_uk'''
22
-
23
- FIRST_STEP = '''Використовувати бота просто: надішліть аудіоповідомлення і чекайте відповіді'''
24
-
25
-
26
- bot = telebot.TeleBot(TOKEN, parse_mode=None, threaded=False)
27
- app = Flask(__name__,)
28
-
29
-
30
- @app.route('/')
31
- def index():
32
- bot.remove_webhook()
33
- bot.set_webhook(
34
- url='https://voice-recognition-ua.herokuapp.com/' + TOKEN)
35
- return render_template('hello.html')
36
-
37
-
38
- @app.route('/recognize', methods=["POST"])
39
- def recognize():
40
- file = request.files['file']
41
- lang = request.form["lang"]
42
- audio = BytesIO()
43
- file.save(audio)
44
- audio.seek(0)
45
- result = client(audio, lang)
46
- return result
47
-
48
-
49
- @app.route('/' + TOKEN, methods=['POST'])
50
- def getMessage():
51
- bot.process_new_updates(
52
- [telebot.types.Update.de_json(request.stream.read().decode("utf-8"))])
53
- return "!", 200
54
-
55
-
56
- @bot.message_handler(commands=['start', 'help'])
57
- def send_welcome(message):
58
- bot.reply_to(message, START_MSG)
59
- bot.reply_to(message, FIRST_STEP)
60
-
61
-
62
- @bot.message_handler(content_types=['voice'])
63
- def process_voice_message(message):
64
- # download the recording
65
- file_info = bot.get_file(message.voice.file_id)
66
- downloaded_file = bot.download_file(file_info.file_path)
67
- # create in-memory representation of files
68
- source_audio = BytesIO()
69
- source_audio.write(downloaded_file)
70
- source_audio.seek(0)
71
- output_audio = BytesIO()
72
- ogg_file = pydub.AudioSegment.from_ogg(
73
- source_audio)
74
-
75
- # convert ogg to wav
76
- ogg_file.set_frame_rate(16000).set_channels(
77
- 1).export(output_audio, "wav", codec="pcm_s16le")
78
- output_audio.seek(0)
79
-
80
- # do the recognition
81
- # get the recognized text
82
- try:
83
- text = client(output_audio)
84
- # no results
85
- if not text:
86
- bot.reply_to(message, 'Я не зміг розпізнати 😢')
87
- else:
88
- # send the recognized text
89
- bot.reply_to(message, text)
90
- except Exception as e:
91
- logging.log(logging.ERROR, str(e))
92
- bot.reply_to(message, 'Трапилась помилка 😢')
93
-
94
-
95
- if __name__ == '__main__':
96
- app.run(host='0.0.0.0')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
webapp/requirements.txt DELETED
@@ -1,6 +0,0 @@
1
- Flask==1.1.2
2
- deepspeech-tflite==0.9.3
3
- numpy==1.17.0
4
- uwsgi==2.0.19.1
5
- pytelegrambotapi==3.7.6
6
- pydub==0.24.1
 
 
 
 
 
 
 
webapp/static/main.js DELETED
@@ -1,78 +0,0 @@
1
- // part of script inspired by https://github.com/addpipe/simple-recorderjs-demo
2
- var gumStream; //stream from getUserMedia()
3
- var rec; //Recorder.js object
4
- var input; //MediaStreamAudioSourceNode we'll be recording
5
-
6
- // shim for AudioContext when it's not avb.
7
- var AudioContext = window.AudioContext || window.webkitAudioContext;
8
- var audioContext; //audio context to help us record
9
- const resultNode = document.getElementById('result');
10
- const actionButton = document.getElementById('action');
11
- const langSelector = document.getElementById('lang');
12
-
13
- function resultProcess(data) {
14
- resultNode.textContent = `Довжина тексту: ${data.length} \n
15
- Текст: ${data}
16
- `;
17
- actionButton.textContent = "Почати запис (3 сек)";
18
- actionButton.disabled = false;
19
- }
20
-
21
- function exportWAV(blob) {
22
- actionButton.textContent = "Обробляється..."
23
- var data = new FormData()
24
- data.append('file', blob);
25
- data.append("lang", langSelector.value);
26
- fetch(`./recognize`, { method: "POST", body: data })
27
- .then(response => response.text())
28
- .then(resultProcess);
29
- }
30
- function record() {
31
-
32
- var constraints = { audio: true, video: false }
33
- navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {
34
- actionButton.textContent = "Запис...";
35
- resultNode.textContent = "";
36
- actionButton.disabled = true;
37
- /*
38
- create an audio context after getUserMedia is called
39
- sampleRate might change after getUserMedia is called, like it does on macOS when recording through AirPods
40
- the sampleRate defaults to the one set in your OS for your playback device
41
- */
42
- audioContext = new AudioContext();
43
-
44
- /* assign to gumStream for later use */
45
- gumStream = stream;
46
-
47
- /* use the stream */
48
- input = audioContext.createMediaStreamSource(stream);
49
-
50
- /*
51
- Create the Recorder object and configure to record mono sound (1 channel)
52
- Recording 2 channels will double the file size
53
- */
54
- rec = new Recorder(input, { numChannels: 1 })
55
-
56
- //start the recording process
57
- rec.record()
58
- sleep(3000).then(stop);
59
- })
60
- }
61
-
62
-
63
- function stop() {
64
- rec.stop();
65
-
66
- //stop microphone access
67
- gumStream.getAudioTracks()[0].stop();
68
-
69
- //create the wav blob and pass it on to createDownloadLink
70
- rec.exportWAV(exportWAV);
71
- }
72
-
73
-
74
- const sleep = time => new Promise(resolve => setTimeout(resolve, time));
75
-
76
- async function handleAction() {
77
- record();
78
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
webapp/static/recorder.js DELETED
@@ -1,395 +0,0 @@
1
- //code taken from https://github.com/mattdiamond/Recorderjs/blob/master/src/recorder.js
2
- (function (f) { if (typeof exports === "object" && typeof module !== "undefined") { module.exports = f() } else if (typeof define === "function" && define.amd) { define([], f) } else { var g; if (typeof window !== "undefined") { g = window } else if (typeof global !== "undefined") { g = global } else if (typeof self !== "undefined") { g = self } else { g = this } g.Recorder = f() } })(function () {
3
- var define, module, exports; return (function e(t, n, r) { function s(o, u) { if (!n[o]) { if (!t[o]) { var a = typeof require == "function" && require; if (!u && a) return a(o, !0); if (i) return i(o, !0); var f = new Error("Cannot find module '" + o + "'"); throw f.code = "MODULE_NOT_FOUND", f } var l = n[o] = { exports: {} }; t[o][0].call(l.exports, function (e) { var n = t[o][1][e]; return s(n ? n : e) }, l, l.exports, e, t, n, r) } return n[o].exports } var i = typeof require == "function" && require; for (var o = 0; o < r.length; o++)s(r[o]); return s })({
4
- 1: [function (require, module, exports) {
5
- "use strict";
6
-
7
- module.exports = require("./recorder").Recorder;
8
-
9
- }, { "./recorder": 2 }], 2: [function (require, module, exports) {
10
- 'use strict';
11
-
12
- var _createClass = (function () {
13
- function defineProperties(target, props) {
14
- for (var i = 0; i < props.length; i++) {
15
- var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor);
16
- }
17
- } return function (Constructor, protoProps, staticProps) {
18
- if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor;
19
- };
20
- })();
21
-
22
- Object.defineProperty(exports, "__esModule", {
23
- value: true
24
- });
25
- exports.Recorder = undefined;
26
-
27
- var _inlineWorker = require('inline-worker');
28
-
29
- var _inlineWorker2 = _interopRequireDefault(_inlineWorker);
30
-
31
- function _interopRequireDefault(obj) {
32
- return obj && obj.__esModule ? obj : { default: obj };
33
- }
34
-
35
- function _classCallCheck(instance, Constructor) {
36
- if (!(instance instanceof Constructor)) {
37
- throw new TypeError("Cannot call a class as a function");
38
- }
39
- }
40
-
41
- var Recorder = exports.Recorder = (function () {
42
- function Recorder(source, cfg) {
43
- var _this = this;
44
-
45
- _classCallCheck(this, Recorder);
46
-
47
- this.config = {
48
- bufferLen: 4096,
49
- numChannels: 2,
50
- mimeType: 'audio/wav'
51
- };
52
- this.recording = false;
53
- this.callbacks = {
54
- getBuffer: [],
55
- exportWAV: []
56
- };
57
-
58
- Object.assign(this.config, cfg);
59
- this.context = source.context;
60
- this.node = (this.context.createScriptProcessor || this.context.createJavaScriptNode).call(this.context, this.config.bufferLen, this.config.numChannels, this.config.numChannels);
61
-
62
- this.node.onaudioprocess = function (e) {
63
- if (!_this.recording) return;
64
-
65
- var buffer = [];
66
- for (var channel = 0; channel < _this.config.numChannels; channel++) {
67
- buffer.push(e.inputBuffer.getChannelData(channel));
68
- }
69
- _this.worker.postMessage({
70
- command: 'record',
71
- buffer: buffer
72
- });
73
- };
74
-
75
- source.connect(this.node);
76
- this.node.connect(this.context.destination); //this should not be necessary
77
-
78
- var self = {};
79
- this.worker = new _inlineWorker2.default(function () {
80
- var recLength = 0,
81
- recBuffers = [],
82
- sampleRate = undefined,
83
- numChannels = undefined;
84
-
85
- self.onmessage = function (e) {
86
- switch (e.data.command) {
87
- case 'init':
88
- init(e.data.config);
89
- break;
90
- case 'record':
91
- record(e.data.buffer);
92
- break;
93
- case 'exportWAV':
94
- exportWAV(e.data.type);
95
- break;
96
- case 'getBuffer':
97
- getBuffer();
98
- break;
99
- case 'clear':
100
- clear();
101
- break;
102
- }
103
- };
104
-
105
- function init(config) {
106
- sampleRate = config.sampleRate;
107
- numChannels = config.numChannels;
108
- initBuffers();
109
- }
110
-
111
- function record(inputBuffer) {
112
- for (var channel = 0; channel < numChannels; channel++) {
113
- recBuffers[channel].push(inputBuffer[channel]);
114
- }
115
- recLength += inputBuffer[0].length;
116
- }
117
-
118
- function exportWAV(type) {
119
- var buffers = [];
120
- for (var channel = 0; channel < numChannels; channel++) {
121
- buffers.push(mergeBuffers(recBuffers[channel], recLength));
122
- }
123
- var interleaved = undefined;
124
- if (numChannels === 2) {
125
- interleaved = interleave(buffers[0], buffers[1]);
126
- } else {
127
- interleaved = buffers[0];
128
- }
129
- var downsampledBuffer = downsampleBuffer(interleaved, 16000);
130
- var dataview = encodeWAV(downsampledBuffer);
131
- var audioBlob = new Blob([dataview], { type: type });
132
-
133
- self.postMessage({ command: 'exportWAV', data: audioBlob });
134
- }
135
-
136
- function getBuffer() {
137
- var buffers = [];
138
- for (var channel = 0; channel < numChannels; channel++) {
139
- buffers.push(mergeBuffers(recBuffers[channel], recLength));
140
- }
141
- self.postMessage({ command: 'getBuffer', data: buffers });
142
- }
143
-
144
- function clear() {
145
- recLength = 0;
146
- recBuffers = [];
147
- initBuffers();
148
- }
149
-
150
- function initBuffers() {
151
- for (var channel = 0; channel < numChannels; channel++) {
152
- recBuffers[channel] = [];
153
- }
154
- }
155
-
156
- function mergeBuffers(recBuffers, recLength) {
157
- var result = new Float32Array(recLength);
158
- var offset = 0;
159
- for (var i = 0; i < recBuffers.length; i++) {
160
- result.set(recBuffers[i], offset);
161
- offset += recBuffers[i].length;
162
- }
163
- return result;
164
- }
165
-
166
- function downsampleBuffer(buffer, rate) {
167
- if (rate == sampleRate) {
168
- return buffer;
169
- }
170
- if (rate > sampleRate) {
171
- throw "downsampling rate show be smaller than original sample rate";
172
- }
173
- var sampleRateRatio = sampleRate / rate;
174
- var newLength = Math.round(buffer.length / sampleRateRatio);
175
- var result = new Float32Array(newLength);
176
- var offsetResult = 0;
177
- var offsetBuffer = 0;
178
- while (offsetResult < result.length) {
179
- var nextOffsetBuffer = Math.round((offsetResult + 1) * sampleRateRatio);
180
- // Use average value of skipped samples
181
- var accum = 0, count = 0;
182
- for (var i = offsetBuffer; i < nextOffsetBuffer && i < buffer.length; i++) {
183
- accum += buffer[i];
184
- count++;
185
- }
186
- result[offsetResult] = accum / count;
187
- // Or you can simply get rid of the skipped samples:
188
- // result[offsetResult] = buffer[nextOffsetBuffer];
189
- offsetResult++;
190
- offsetBuffer = nextOffsetBuffer;
191
- }
192
- return result;
193
- }
194
-
195
- function interleave(inputL, inputR) {
196
- var length = inputL.length + inputR.length;
197
- var result = new Float32Array(length);
198
-
199
- var index = 0,
200
- inputIndex = 0;
201
-
202
- while (index < length) {
203
- result[index++] = inputL[inputIndex];
204
- result[index++] = inputR[inputIndex];
205
- inputIndex++;
206
- }
207
- return result;
208
- }
209
-
210
- function floatTo16BitPCM(output, offset, input) {
211
- for (var i = 0; i < input.length; i++, offset += 2) {
212
- var s = Math.max(-1, Math.min(1, input[i]));
213
- output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
214
- }
215
- }
216
-
217
- function writeString(view, offset, string) {
218
- for (var i = 0; i < string.length; i++) {
219
- view.setUint8(offset + i, string.charCodeAt(i));
220
- }
221
- }
222
-
223
- function encodeWAV(samples) {
224
- var buffer = new ArrayBuffer(44 + samples.length * 2);
225
- var view = new DataView(buffer);
226
-
227
- /* RIFF identifier */
228
- writeString(view, 0, 'RIFF');
229
- /* RIFF chunk length */
230
- view.setUint32(4, 36 + samples.length * 2, true);
231
- /* RIFF type */
232
- writeString(view, 8, 'WAVE');
233
- /* format chunk identifier */
234
- writeString(view, 12, 'fmt ');
235
- /* format chunk length */
236
- view.setUint32(16, 16, true);
237
- /* sample format (raw) */
238
- view.setUint16(20, 1, true);
239
- /* channel count */
240
- view.setUint16(22, numChannels, true);
241
- /* sample rate */
242
- view.setUint32(24, 16000, true);
243
- /* byte rate (sample rate * block align) */
244
- view.setUint32(28, 16000 * 4, true);
245
- /* sample rate */
246
- //view.setUint32(24, sampleRate, true);
247
- /* byte rate (sample rate * block align) */
248
- //view.setUint32(28, sampleRate * 4, true);
249
- /* block align (channel count * bytes per sample) */
250
- view.setUint16(32, numChannels * 2, true);
251
- /* bits per sample */
252
- view.setUint16(34, 16, true);
253
- /* data chunk identifier */
254
- writeString(view, 36, 'data');
255
- /* data chunk length */
256
- view.setUint32(40, samples.length * 2, true);
257
-
258
- floatTo16BitPCM(view, 44, samples);
259
-
260
- return view;
261
- }
262
- }, self);
263
-
264
- this.worker.postMessage({
265
- command: 'init',
266
- config: {
267
- sampleRate: this.context.sampleRate,
268
- numChannels: this.config.numChannels
269
- }
270
- });
271
-
272
- this.worker.onmessage = function (e) {
273
- var cb = _this.callbacks[e.data.command].pop();
274
- if (typeof cb == 'function') {
275
- cb(e.data.data);
276
- }
277
- };
278
- }
279
-
280
- _createClass(Recorder, [{
281
- key: 'record',
282
- value: function record() {
283
- this.recording = true;
284
- }
285
- }, {
286
- key: 'stop',
287
- value: function stop() {
288
- this.recording = false;
289
- }
290
- }, {
291
- key: 'clear',
292
- value: function clear() {
293
- this.worker.postMessage({ command: 'clear' });
294
- }
295
- }, {
296
- key: 'getBuffer',
297
- value: function getBuffer(cb) {
298
- cb = cb || this.config.callback;
299
- if (!cb) throw new Error('Callback not set');
300
-
301
- this.callbacks.getBuffer.push(cb);
302
-
303
- this.worker.postMessage({ command: 'getBuffer' });
304
- }
305
- }, {
306
- key: 'exportWAV',
307
- value: function exportWAV(cb, mimeType) {
308
- mimeType = mimeType || this.config.mimeType;
309
- cb = cb || this.config.callback;
310
- if (!cb) throw new Error('Callback not set');
311
-
312
- this.callbacks.exportWAV.push(cb);
313
-
314
- this.worker.postMessage({
315
- command: 'exportWAV',
316
- type: mimeType
317
- });
318
- }
319
- }], [{
320
- key: 'forceDownload',
321
- value: function forceDownload(blob, filename) {
322
- var url = (window.URL || window.webkitURL).createObjectURL(blob);
323
- var link = window.document.createElement('a');
324
- link.href = url;
325
- link.download = filename || 'output.wav';
326
- var click = document.createEvent("Event");
327
- click.initEvent("click", true, true);
328
- link.dispatchEvent(click);
329
- }
330
- }]);
331
-
332
- return Recorder;
333
- })();
334
-
335
- exports.default = Recorder;
336
-
337
- }, { "inline-worker": 3 }], 3: [function (require, module, exports) {
338
- "use strict";
339
-
340
- module.exports = require("./inline-worker");
341
- }, { "./inline-worker": 4 }], 4: [function (require, module, exports) {
342
- (function (global) {
343
- "use strict";
344
-
345
- var _createClass = (function () { function defineProperties(target, props) { for (var key in props) { var prop = props[key]; prop.configurable = true; if (prop.value) prop.writable = true; } Object.defineProperties(target, props); } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
346
-
347
- var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } };
348
-
349
- var WORKER_ENABLED = !!(global === global.window && global.URL && global.Blob && global.Worker);
350
-
351
- var InlineWorker = (function () {
352
- function InlineWorker(func, self) {
353
- var _this = this;
354
-
355
- _classCallCheck(this, InlineWorker);
356
-
357
- if (WORKER_ENABLED) {
358
- var functionBody = func.toString().trim().match(/^function\s*\w*\s*\([\w\s,]*\)\s*{([\w\W]*?)}$/)[1];
359
- var url = global.URL.createObjectURL(new global.Blob([functionBody], { type: "text/javascript" }));
360
-
361
- return new global.Worker(url);
362
- }
363
-
364
- this.self = self;
365
- this.self.postMessage = function (data) {
366
- setTimeout(function () {
367
- _this.onmessage({ data: data });
368
- }, 0);
369
- };
370
-
371
- setTimeout(function () {
372
- func.call(self);
373
- }, 0);
374
- }
375
-
376
- _createClass(InlineWorker, {
377
- postMessage: {
378
- value: function postMessage(data) {
379
- var _this = this;
380
-
381
- setTimeout(function () {
382
- _this.self.onmessage({ data: data });
383
- }, 0);
384
- }
385
- }
386
- });
387
-
388
- return InlineWorker;
389
- })();
390
-
391
- module.exports = InlineWorker;
392
- }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
393
- }, {}]
394
- }, {}, [1])(1)
395
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
webapp/templates/hello.html DELETED
@@ -1,47 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
-
4
- <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>Розпізнавання української мови</title>
8
- <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
9
- integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
10
- </head>
11
-
12
- <body>
13
- <div class="container">
14
- <div class="col-12 col-md-8 col-sm-12 col-xl-6 mx-auto text-center">
15
- <h1>Демо розпізнавання української мови</h1>
16
- <p>Говоріть 3 секунди після натискання на кнопку, тоді отримаєте результат</p>
17
- <div class="row no-gutters">
18
- <div class="col-1 col-sm-3">&nbsp;</div>
19
- <div class="col-6">
20
- <button class="btn btn-primary" id="action" onclick="handleAction()">Почати запис (3 сек)</button>
21
- </div>
22
- <div class="col-5 col-sm-3">
23
- <select id="lang" class="browser-default custom-select" style="width: 100%">
24
- <option selected value="uk">Українська</option>
25
- </select>
26
- </div>
27
- </div>
28
- <div id="result"></div>
29
- <br>
30
- <a href="https://commonvoice.mozilla.org/uk" target="_blank" class="btn btn-success" id="action">Долучитись
31
- до створення відкритого
32
- набору<br> записів української мови</a>
33
- <br>
34
- <div style="margin-top: 10px" class="alert alert-warning" role="alert">
35
- Дисклеймер: через малу кількість даних для навчання нейромережі
36
- результат може бути неточний:
37
- <hr style="border-top-color:black">
38
- сів метелик на травичку -> сі вметелик на требичко <br>
39
- better late than never -> better waits and never
40
- </div>
41
- </div>
42
- </div>
43
- <script src="/static/recorder.js"></script>
44
- <script src="/static/main.js"></script>
45
- </body>
46
-
47
- </html>